理解js中的getter和setter

在复习对象访问器的时候,我就犯了一个简单的错误,也让我意识到我是对getter和setter是理解不到位的。先看看我的代码和错误提示:
在这里插入图片描述
在这里插入图片描述

错误提示是:person.messageAre不是函数。我感到很困惑,因为我在person里对messageAre的写法看起来就像是一个函数。我立马再去认真学一下getter和setter,发现以下才是使用 setter 设置对象属性和getter获取属性的正确用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var person = {
        name: "QQ",
        age: 18,
        get messagesAre(){
            console.log('get messagesAre');
            return `${this.name} ${this.age}`;
        },
        set messagesAre(m){
            console.log('set messagesAre');
            [this.name,this.age] = m.split(' ');
        }
    }

    document.getElementById('getSth').innerText = person.messagesAre;
    person.messagesAre = 'QQiukulele 16'  
    document.getElementById('getSth').innerText = person.messagesAre;

在这里插入图片描述

认识getter和setter

访问器属性由“getter”和“setter”方法表示。在一个对象字面量中,它们由get和set表示,后面是与它相关得属性(messageAre)和一个函数体。函数体内定义了当属性被访问或修改时得行为。所以person.messageAre,它不是方法。
这下算是弄明白我的疑惑了,那为什么要使用getter和setter呢?

  • 它提供了更简洁的语法
  • 它允许属性和方法的语法相同
  • 它可以确保更好的数据质量
  • 有利于后台工作

从外部看,访问器属性是与常规属性类似的。这也是访问器属性的思想。
在我看来,在读取或操作对象的属性时,getter和setter的用法会比调用函数看起来更让人明了和接受。赋值就赋值,读取值就“.”来获取。??

getter /setter还可以当作**“实际”属性值的包装器**,以获得对对象属性操作的更多控制。下面是一个例子,利用setter hobby在对person.hobby赋值时判断是否"唱"出一句"You don’t know about me",hobby会存储在_hobby属性中,通过getter 和 setter访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    var person = {
        get hobby(){  //记得保持和你要操作的属性名一致
            return this._hobby;  
        },
        set hobby(h){  
            if(h !== '弹琴'){
                console.log("You don't know about me");
                return ;
        }
            this._hobby = h;
    }
}
    person.hobby = '弹琴';
    console.log(person.hobby);   //弹琴
    person.hobby = '跑步';   //You don't know about me
    console.log(person._hobby)  //弹琴  但是不推荐这样访问,因为_开头的属性默认是内部属性,不要外部访问

Object.defineProperty() 方法也可用于添加 getter 和 setter:

Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    var person = {};
        var name = '';
        Object.defineProperty(person,'name',{
            set : function(value){
                name = value;
            },
            get : function(){
                return '我的名字是'+name;
            }
    });
           
    person.name = 'QQ';  
    console.log(person.name);   //我的名字是QQ
    console.log(person);

在这里插入图片描述
以上,通过Object.defineProperty() 方法定义的访问属性器hobby包含一个getter函数和一个setter函数。假如我们把Object.defineProperty() 方法定义部分给注释掉,继续打印person对象,会发现如下结果,属性name自己本身也带有get 和 set方法的。
在这里插入图片描述
实际上,每个属性都有原生的setter和getter,但是他们不会被显示地显示出来。不论是对象字面量还是用Object.defineProperty() 方法,都是对对象原生的setter和getter的重写。

初步理解vue的双向数据绑定原理

学习setter和getter的过程,多少会看到一点vue双向数据绑定的身影。理解以及会正确运用getter和setter对于后面vue的双向数据绑定MVVM的学习理解很有帮助~Vue会对 data 中所有键值对设置 getter/setter。下面是一个简单的vue初始化数据,在控制台输出发现属性a自带get 和 set 方法,这就是vue通过Object.defineProperty()来实现的数据劫持。

1
2
3
4
5
6
7
8
9
10
11
    var vm = new Vue({
        el:'#app',
        data: {
            obj:{
                message : 'QQiukulele'
            }
        },
        created: function(){
            console.log(this.obj)
        }
    });

在这里插入图片描述
对比上面用Object.defineProperty()为一个对象显示地声明getter和setter的打印结果,看起来是和上面打印的vue数据很类似。

vue内部是怎样实现双向数据绑定的?下面是摘自别人的总结介绍o( ̄▽ ̄)ブ:

数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

这仅仅是对vue的双向数据绑定原理的初步理解,深入理解需更多学习以上也是我的学习和理解,若有描述不正确,欢迎指出!若有更深入的理解,欢迎交流~
? 参考文章链接:

?? https://www.jackfranklin.co.uk/blog/es5-getters-setters/

?? https://github.com/DMQ/mvvm