Vue引发的getter和setter

看着文档研究了一下vue的双向数据绑定,打印出Vue实例下的data对象里的属性时,发现了一个有趣的事情:

它的每个属性都有两个相对应的get和set方法,我觉的这是多此一举的,于是去网上查了查Vue双向绑定的实现原理,才发现它和Angular.js双向绑定的实现原理完全不同,Angular是用的数据脏检测,当Model发生变化,会检测所有视图是否绑定了相关数据,再更改视图。而Vue使用的发布订阅模式,是点对点的绑定数据。

Vue的数据绑定只有两个步骤,compile=>link。

我一直在想,vue是通过什么去监听用户对Model的修改,直到我发现Vue的data里,每个属性都有set和get属性,我才明白过来。

在平时,我们创建一个对象,并修改它的属性,是这样的:

    var obj = {
        val:99
    }
    obj.val = 100;
    console.log(obj.val)//100

没有任何问题,但是如果要你去监测,当我修改了这个对象的属性时,要去做一些事,你会怎么做?

这就要用到getter和setter了。

假设我现在要给一个码农对象添加一个name属性,而且每次更新name属性时,我要去完成一些事,我们可以这样做:

    var Coder = function() {
        var that = this;
        return {
            get name(){
                if(that.name){
                    return that.name
                }
                return '你还没有取名'
            },
            set name(val){
                console.log('你把名字修成了'+val)
                that.name = val
            }
        }
    }
    var isMe = new Coder()
    console.log(isMe.name)
    isMe.name = '周神'
    console.log(isMe.name)
    console.log(isMe)

输出:

你会发现这个对象和最上面的Vue中的data对象,打印出来的效果是一样的,都拥有get和set属性。

我们来一步步分析下上面的代码,很有趣。

我们先创建一个对象字面量:

var Coder = function() {...}

再把this缓存一下:

var that = this;

接下来是最重要的,我们return了一个对象回去:

{
  get name(){...},
  set name(val){...}
}

顾名思义,get为取值,set为赋值,正常情况下,我们取值和赋值是用obj.prop的方式,但是这样做有一个问题,我如何知道对象的值改变了?所以就轮到set登场了。

你可以把get和set理解为function,当然,只是可以这么理解,这是完全不一样的两个东西。

接下来创建一个码农的实例,isMe;此时,isMe是没有name属性的,当我们调用isMe.name时,我们会进入到get name(){...}中,先判断isMe是否有name属性,答案是否定的,那麽就添加一个name属性,并给它赋值:"你还没有取名";如果有name属性,那就返回name属性。

看到这里你一定知道get怎么使用了,对,你可以把get看成一个取值的函数,函数的返回值就是它拿到的值。

我感觉比较重要的是set属性,当我给实例赋值:

isMe.name="周神"

此时,会进入set name(val){...};形参val就是我赋给name属性的值,在这个函数里,我就可以做很多事了,比如双向绑定!因为这个值的每次改变都必须经过set,其他方式是改变不了它的,相当于一个万能的监听器。

还有另一种方法可以实现这个功能。

ES5的对象原型有两个新的属性__defineGetter__和__defineSetter__,专门用来给对象绑定get和set。可以这样书写:

  var Coder = function() {
    }
    Coder.prototype.__defineGetter__('name', function() {
        if (this.name) {
            return this.name
        }else{
            return '你还没有取名'
        }
    })
    Coder.prototype.__defineSetter__('name', function(val) {
        this.name = val
    })
    var isMe = new Coder()
    console.log(isMe.name)
    isMe.name = '周神'
    console.log(isMe.name)
    console.log(isMe)

效果是一样的,建议使用下面这种方式,因为是在原型上书写,所以可以继承和重用,最近想写点小框架,才发现知识不够用,大家一起加油吧!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏青玉伏案

ReactiveSwift源码解析(十二) MutableProperty基本代码实现

前两篇博客我们分别聊了ReactiveSwift框架中的负责标记对象的生命周期的类Lifetime以及负责原子性操作的Atomic类的具体代码实现。前两篇博客之...

1645
来自专栏java技术学习之道

最通俗易懂的java注解讲解

1143
来自专栏技术分享

.NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(三)

阅读目录: 7.HtmlHelper、HtmlHelper<T>中的ViewModel的类型推断 8.控制ViewModel中的某个属性的呈现(使用Partia...

2038
来自专栏FD的专栏

写出形似QML的C++代码

我的第一个想法(居然?)是做个Embedded-DSL。不过C++又不是Ruby……随便搜了一下,发现了一篇文章,也只是利用了重载运算符和运算符优先级,看上去限...

492
来自专栏JetpropelledSnake

Django学习笔记之CBV和FBV

Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-...

611
来自专栏我杨某人的青春满是悔恨

RxCocoa 源码解析——代理转发

平常我们使用 RxSwift 的时候,一般不会去直接使用 delegate,譬如要处理 tableView 的点击事件,我们会这样:tableView.rx.i...

572
来自专栏IT笔记

Quartz学习笔记(三)配置文件实现任务调度

在JavaEE系统中,我们会经常用到定时任务,比如每天凌晨生成前天报表,每一小时生成汇总数据等等。 我们可以使用java.util.Timer结合java.ut...

2636
来自专栏Crossin的编程教室

【Python 第47课】 面向对象(1)

我们之前已经写了不少小程序,都是按照功能需求的顺序来设计程序。这种被称为“面向过程”的编程。 还有一种程序设计的方法,把数据和对数据的操作用一种叫做“对象”的...

2779
来自专栏分布式系统和大数据处理

Observer模式入门

在 C#中的委托和事件 - Part.1 一文的后半部分,我向大家讲述了Observer(观察者)模式,并使用委托和事件实现了这个模式。实际上,不使用委托和事件...

572
来自专栏程序猿DD

程序员你为什么这么累[续]:编码习惯之接口定义

前传传送门:程序员你为什么这么累? 工作中,少不了要定义各种接口,系统集成要定义接口,前后台掉调用也要定义接口。接口定义一定程度上能反应程序员的编程功底。列举一...

35110

扫码关注云+社区