美文网首页vue
v-model原理

v-model原理

作者: 名字一定要够长才可爱 | 来源:发表于2019-07-11 15:09 被阅读0次

1. v-model是什么?

  • 在表单控件或者组件上实现双向绑定

2. v-model 原理:

vue的双向绑定是由数据劫持结合发布者-订阅者模式实现的,那么什么是数据劫持?vue是如何进行数据劫持的?说白了就是通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时做你想要做的事情。

2-1. Object.defineProperty()

  • Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性
Object.defineProperty(obj, prop, desc)
  1. obj 需要定义属性的当前对象
  2. prop 当前需要定义的属性名
  3. desc 属性描述符
  • 注意: 一般通过为对象的属性赋值的情况下,对象的属性可以修改也可以删除,但是通过Object.defineProperty()定义属性,通过描述符的设置可以进行更精准的控制对象属性。

属性描述符

通过Object.defineProperty()为对象定义属性,有两种形式,且不能混合使用,分别为数据描述符,存取描述符,下面分别描述下两者的区别:

1>. 数据描述符 - 特有的两个属性(value,writable)
let Person = {}
Object.defineProperty(Person, 'name', {
  value: 'jack',
  writable: true // 是否可以改变
})
2>. 存取描述符 - 是由一对 getter、setter 函数功能来描述的属性
  • get:一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined。
  • set:一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认值为undefined。
let Person = {}
let temp = null
Object.defineProperty(Person, 'name', {
  get: function () {
    return temp
  },
  set: function (val) {
    temp = val
  }
})
数据描述符和存取描述均具有以下描述符:
  • configrable 描述属性是否配置,以及可否删除
  • enumerable 描述属性是否会出现在for in 或者 Object.keys()的遍历中

2-2. 如何使用Object.defineProperty实现数据劫持

function render() {
    console.log('模拟试图渲染');
}

let obj = {
    name: 'jiajia',
    location: {
        x: 100,
        y: 100
    }
}

let methods = ['pop', 'shift', 'unshift', 'sort', 'reverse', 'splice', 'push'];
// 先获取原先原型上的方法
let arrayProto = Array.prototype;
// 创建一个自己的原型 并且重写methods这些方法
let proto = Object.create(arrayProto);
methods.forEach(method => {
    proto[method] = function () {
        render();
        arrayProto[method].call(this, ...arguments);
    }
})

// 定义响应式
function defineReactive(data, key, value) {
    observer(value);
    Object.defineProperty(data, key, {
        get() {
            return value;
        },
        set(newValue) {
            observer(newValue);
            if (newValue !== value) {
                render();
                value = newValue;
            }
        }
    })
}

function observer(obj) {
    // 重写数组方法
    if (Array.isArray(obj)) {
        obj.__proto__ = proto;
        return;
    }
    // 把所有的属性定义成set/get的方式
    if (typeof (obj) == 'object') {
        for (let key in obj) {
            defineReactive(obj, key, obj[key]);
        }
    }
}
observer(obj);

相关文章

网友评论

    本文标题:v-model原理

    本文链接:https://www.haomeiwen.com/subject/pfzrkctx.html