最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 手把手带你实现一个min版的vue2(1) 数据响应式核心原理

    正文概述 掘金(不知凡几酱)   2021-05-28   610

    vue2数据响应式核心通过Object.defineProperty()这个API实现的,但这个API实际中开发运用不多,为了应付面试笔者,尝试过死记硬背,但过不了几天就会忘记。没有经过大脑理解的知识,终究就留不下来。这篇文章中,笔记以自己的思考,讲解这个API的用途,以及vue2利用这个API做了什么事情。

    理解对象的属性类型

    在讲述Object.defineProperty这个API之前,我们先来思考一下js 怎么知道对象中某个的属性是否可以更改?

    比如我们声明一个变量对象 a,a有name属性,那么怎么知道 这个name属性是否可以更改呢

    const a = { name: 'a' }
    

    我们可以通过Object.getOwnPropertyDescriptor()获取指定对象上一个自有属性对应的属性描述符

    const b = Object.getOwnPropertyDescriptor(a, 'name')
    console.log(b) 
    // {
    // configurable: true
    // enumerable: true
    // value: "haha"
    // writable: true
    // __proto__: Object
    //}
    
    

    这些属性是内部的,我们并不能看到,也不能直接访问这些特性,因为这些属性是JS实现引擎的规范定义,它们是用来描述属性的特征。如何区分:内部特性会用两个中括号把特性的名称括起来,比如[[Enumerable]]。

    其中 writable 就表示这个name属性是否可以修改。

    JS对象属性分两种:数据属性访问器属性。这两种属性都4个特性描述它们的行为。

    • 数据属性

      数据属性是可以直接定义的,前面声明的对象a就是数据属性。我们不管是通过字面量还是new 操作符加上Object构造函数声明的对象都是数据属性。

      • [[Configurable]]: 表示是否可以通过delete删除并重新定义,是否可以修改它的特性,以及是否可以把它改为访问器属性。默认为true

      • [[Enumerable]]:表示是否可以通过for-in循环返回。默认为true

      • [[Writable]]:表示属性的值是否可以被修改。默认为true

      • [[Value]]:包含属性实际的值。默认为undefined

    • 访问器属性

      访问器属性不可以直接定义,必须使用Object.defineProperty()

      • [[Configurable]]:与数据属性的一样
      • [[Enumerable]]:同上
      • [[Get]]:获取函数,在读取属性时调用。默认值为undefined。
      • [[Set]]:设置函数,在写入属性时调用。默认值为undefined。

    Object.defineProperty()

    通过Object.defineProperty()我们可以改变对象的内部属性。

    设置属性只读

    const c = {name: 'ccc'}
    Object.defineProperty(c, 'name',{
      configurable: true,
      enumerable: true,
      writable: false,
    })
    c.name = 'ddd'
    // test
    console.log(c.name) // ccc 不可以更改
    

    设置对象属性拦截

    const obj = { name: 'hh' }
    const vm = {}
    // 数据劫持
    Object.defineProperty(vm, 'name', {
      configurable: true,
      enumerable: true,
      get: () => {	// 读取属性
        return obj.name
      },
      set: (val) => {	// 写入属性
        	if (val === obj.name) {
            return
          }
        	obj.name = val
      }
    })
    // test 
    vm.name = 'a'
    console.log(obj) // {name: "a"}
    

    上述例子中,把对象vm数据属性设置成访问器属性,当vm的name发生更改时,obj的name也会随之更改。理解了这个后,我们就可以模拟vue中的响应式了。

    多属性数据劫持

    // 模拟vue的 data选项
    const data = {
      name: 'hello',
      count: 10
    }
    // 模拟 Vue 的实例
    const vm = {}
    // 把对象中的每个数据属性都改变成访问器属性
    function proxyData(data) {
      // 遍历 data 对象的所有属性
      Object.keys(data).forEach(key => {
        Object.defineProperty(vm, key, {
          configurable: true,
          enumerable: true,
          // 当获取值的时候执行
          get: () => {
            console.log('get: ', key, data[key])
            return data[key]
          },
          // 当设置值的时候执行
          set: newVal => {
            console.log('set: ', key, newValue)
            if (newValue === data[key]) {
              return
            }
            data[key] = newValue
          }
        })
      })
    }
    proxyData(data)
      
    // test
    vm.msg = 'Hello World'
    console.log(vm.msg) // Hello World
    

    总结: 通过Object.getOwnPropertyDescriptors()获取读取属性的特性,通过Object.defineProperty()设置属性的特性属性特性分为数据属性和访问器属性。

    ​ 数据属性包含configurable、enumerable、writable和value属性

    ​ 访问器属性包含configurable、enumerable、get和set属性

    ​ vue中响应式核心就是把对象的数据属性设置成访问器属性,这样就可以获取、设置对象属性的时候进行操作了。


    起源地下载网 » 手把手带你实现一个min版的vue2(1) 数据响应式核心原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元