对object.defineproperty 的深入理解

 

 

如面试官问你vue中双向数据绑定实现原理是啥? 一句话其实vue中的v-model 底层就是用到就是 object.defineproperty 
然后继续问你object.defineproperty 是 这么使用和自己这么实现一个双向绑定?
然后你可沉默一会。。。。 开始一下的装逼之路

 

 

 
首先 我们看看这这么使用和有哪些属性
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
Object.defineProperty(obj, prop, descriptor)
obj
要定义属性的对象。
prop
要定义或修改的属性的名称或 Symbol 。
descriptor
要定义或修改的属性描述符。
descriptor 中有那属性注意看:
configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false
enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
默认为 false

数据描述符还具有以下可选键值:

value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
默认为 undefined
writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
默认为 false

存取描述符还具有以下可选键值:

get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
默认为 undefined
set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
默认为 undefined
下面是demo ,有助于更好的理解
<!DOCTYPE html>
<html lang="en">

 

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Object.defineProperty实现双向绑定</title>
</head>

 

<body>
  <h1 id='h1'></h1>
  <input type="text" id="inp" onkeyup="inputChange(event)">
  <input type="button" value="加" onclick="btnAdd()" />
</body>
<script>
  //数据源
  let vm = {
    value: 0
  }

 

  //用于管理watcher的Dep对象
  let Dep = function () {
    this.list = [];
    this.add = watcher => this.list.push(watcher),
      this.notify = newValue => {
        this.list.forEach(fn => {
          fn(newValue)
        })
      }
  };

 

  // 模拟compile,通过对Html的解析生成一系列订阅者(watcher)
  function renderInput(newValue) {
    let el = document.getElementById('inp');
    if (el) {
      el.value = newValue
    }
  }

 

  function renderTitle(newValue) {
    let el = document.getElementById('h1');
    if (el) {
      el.innerHTML = newValue
    }
  }
  //将解析出来的watcher存入Dep中待用
  let dep = new Dep();
  dep.add(renderInput);
  dep.add(renderTitle)
  console.log(dep);
  console.log(Dep);
  //核心方法
  function initMVVM(vm) {
    console.log(Object.keys(vm));
    Object.keys(vm).forEach(key => {
      observer(vm, key, vm[key])
    })
  }

 

  function observer(vm, key, value) {
    Object.defineProperty(vm, key, {
      enumerable: true,
      configurable: true,
      get: function () {
        console.log('Get');
        return value
      },
      set: function (newValue) {
        if (value !== newValue) {
          value = newValue
          console.log('Update')

 

          //将变动通知给相关的订阅者
          dep.notify(newValue)
        }
      }
    })
  }

 

  //页面引用的方法
  function inputChange(ev) {
    let value = Number.parseInt(ev.target.value);
    vm.value = (Number.isNaN(value)) ? 0 : value;
  }

 

  function btnAdd() { // 点击添加1
    vm.value = vm.value + 1;
  }

 

  //初始化数据源
  initMVVM(vm)
  //初始化页面
  dep.notify(vm.value);
</script>
</html>
 

object.defineProperty中的set和get的区别

1,get和set是方法,因为是方法,所以可以进行判断

2,get是得到,一般是要返回的;set是设置,不用返回

3,如果调用对象内部的属性,约定的命名方式是_age

 你学废了吗?

 

 


 

 

posted @ 2020-12-10 16:52  getMy  阅读(747)  评论(0)    收藏  举报