一、 vue 计算属性当中的 get 与 set 勾子
1 | calculateAttr() { |
如上代码,当我试图更改 calculateAttr
值时,在控制台将会报错 Computed property "calculateAttr" was assigned to but it has no setter.
。 简介讲,我们只是 给 calculateAttr
设置了get属性,而未设置其set勾子。
事实上,计算属性简单做字面理解既是:这个值是被计算出来的,来做展示的,而不是设置的。所以当我们想要设置计算属性的值的时候,应该单独的设置其set勾子。亦如vue文档中所说的
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter
1
2
3
4
5
6
7
8
9
10
11
12
13
14 computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
对其值的设置也是借助与 firstName lastName
而进行的
二、 Object.defineProperty(obj, prop, descriptor)
Object.defineProperty()1
2
3
4
5
6
7
8
9
10
11
12
13
14var Book = {}
var tempName = '';
Object.defineProperty(Book, 'name', {
set: function (value) {
tempName = value;
console.log('你取了一个书名叫做' + value);
},
get: function () {
return '《' + tempName + '》'
}
})
Book.name = 'vue权威指南'; // 你取了一个书名叫做vue权威指南
console.log(Book.name); // 《vue权威指南》
与 vue 的计算属性差不多,只不过vue上面的计算属性 都是 this
对象的
三、 对象初始化器在创建对象的时候指明
1 | let obj = { |
四、 Proxy 代理
拿Proxy可以做哪些有意思的事儿
与对象本身自有的get勾子不同地方在于。对象自有的get主要是针对当前对象并不存在的key,get 可以生成这个key(如果get的是已存在的key,则读取的时候是读get的值)
而代理 如其名一般,只要你对对象设置了代理,那么,当读取该对象属性的时候自然会访问代理
访问代理的前提是,你为该对象设置了代理
而 Object.defineProperty
说白了就是 给 对象定义一些属性而已
而代理 是说,我们 想要 访问 某个对象的时候,我们不直接访问这个对象,而是 访问这个对象的代理,这这个代理中,我们设置下,当我们访问某些属性的时候 需要发生的事情1
2
3
4
5
6
7
8
9
10
11
12
13
14let target = { age: 18, name: 'Niko Bellic' }
let handlers = {
get (target, property) {
return `${property}: ${target[property]}`
},
set (target, property, value) {
target[property] = value
}
}
let proxy = new Proxy(target, handlers)
proxy.age = 19
console.log(target.age, proxy.age) // 19, age : 19
console.log(target.name, proxy.name) // Niko Bellic, name: Niko Bellic
解决对象属性为undefined的问题1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19let target = {}
let handlers = {
get: (target, property) => {
target[property] = property in target ? target[property] : {}
if (typeof target[property] === 'object') {
return new Proxy(target[property], handlers)
// 如果读取的某一key值也是一个对象(A对象),那么为 A对象 设置代理
// 从而当读取A对象的某一属性的时候,也会走代理,执行此get勾子
}
return target[property]
}
}
let proxy = new Proxy(target, handlers)
// console.log('z' in proxy.x.y) // false (其实这一步已经针对`target`创建了一个x.y的属性)
// proxy.x 默认调用了 get 方法(生成了针对该key的value值(即一个空对象))
// 而 在 .y 的话,如果不在继续代理,就没有调用get,返回的自然是一个 undefied
// proxy.x.y.z = 'hello'
// console.log('z' in proxy.x.y) // true
// console.log(target.x.y.z) // hello
五、 作用于类属性的装饰器
Javascript 中的装饰器
装饰器在作用于属性的时候,实际上是通过 Object.defineProperty 来进行扩展和封装的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function readonly(target, name, descriptor) {
discriptor.writable = false;
return discriptor;
}
class Cat {
@readonly
say() {
console.log("meow ~");
}
}
var kitty = new Cat();
kitty.say = function() {
console.log("woof !");
}
kitty.say() // meow ~
上面的这段代码中,装饰器实际的作用形式是这样的:1
2
3
4
5
6
7
8
9
10let descriptor = {
value: function() {
console.log("meow ~");
},
enumerable: false,
configurable: true,
writable: true
};
descriptor = readonly(Cat.prototype, "say", descriptor) || descriptor;
Object.defineProperty(Cat.prototype, "say", descriptor);