一、为什么会有get和set的出现
在程序语言中,对象(Object)有以下几个特点:
1. 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。(eg:console.log({a: 1} == {a: 1}); >>>false)
2. 对象具有状态: 同一对象有不同的状态(c++中的成员变量,Java中的属性)
3. 对象具有行为: 对象的状态可能会有变化(c++中的成员函数,Java中的方法)
在JavaScript中,状态和行为被统一抽象为“属性”,这是因为在js中方法(function)也是以object的形式存在的,可以以属性的方式来进行抽象。
var a = {
b: 1,
c: function(){
return 3
}
}
js允许在运行时向对象添加状态,并且可以添加行为。为了提高抽象能力,js的属性被设计成了更加复杂的形式,它提提供了两类属性getter/setter,作为其数据属性和访问器属性。也可以简单的理解为,getter 是一种获得属性值的方法,setter是一种设置属性值的方法。
- getter负责查询值,它不带任何参数,setter则负责设置键值,值是以参数的形式传递,在他的函数体中,一切的return都是无效的
- get/set访问器不是对象的属性,而是属性的特性,特性只有内部才用,因此在javaScript中不能直接访问他们,为了表示特性是内部值用两队中括号括起来表示如[[Value]]
class Person {
constructor(name,age) {
this.name = name;
this.age = age;
}
set name(name) {
console.log("setter");
this.name = name;
}
get name() {
console.log("getter");
return this.name;
}
}
上面的例子中,get方法用来获取name的值,get方法用来改变name的值。
有人到这里会疑惑,获取值、改变值,只要直接person.name和person.name = "其他人"不就行了么?引入get和set方法不是多此一举?
可是在上面案例中,通过函数来获取对象属性、改变对象属性,是可以console.log到属性的行为的,也就是,通过函数是可以监听到属性的变化的,而直接通过“.”来获取改变属性,仅仅是实施了行为却无法进行行为的监听。
通过set和get监听属性的变化,这恰恰就是Vue中双向绑定的思路基础。
二、VUE中的get、set与双向绑定
在Vue项目中,我们console.log()一个对象的属性,可以在控制台看到以下结果:
发现每个对象属性里都有以下定义在其原型链上的以下方法(__proto__):
可以看到,原型链上定义的方法有ES5中的__defineGetter__和__defineSetter__,以及ES6中引入的get和set关键字。在使用对象初始化过程来定义Getter和Setter方法时唯一要做的事情就是在getter方法前面加上“get”,在setter方法前面加上“set”。 还有一点要注意的就是getter方法没有参数,setter方法必须有一个参数,也就是要设置的属性的新值。
var person = {
val: '名字',
get name() {return this.val;},
set name(name) {this.val = name;}
}
而ES5的对象原型的属性__defineGetter__和__defineSetter__,用来给对象已经定义之后,给对象绑定新的get和set方法:
var person = {
val: '名字'
}
person.__defineGetter__('name',function(){return this.val;});
person.__defineSetter__('name',function(name){this.val = name;})
console.log(person.name); >>> 名字 person.name = '新名字'; console.log(person.name); >>> 新名字