MVVM data proxy implementation principle

https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2FDMQ%2Fmvvm

1. Data Agent

(1) Introduction: proxy data to a data object proxy is operating all the properties of the object by vm. For example, we want to access the data vue data should be vm.data.msg, method of access vue should be vm.methods.getMsg (), but in fact we use vm.msg directly or vm.getMsg () to access the data the methods or data. That data agent
attribute values for all proxy objects to be traversed key, key attribute of the same name is added to the object by Object.defineProperty vm, get and set methods provided to dynamically obtain or modify data objects: (2) implementation principle

<script>
function MVVM (option) {
    //保存传入的配置
    this.$option = option
    //保存data对象
    var data = this._data = this.$option.data
    //遍历data中的所有key
    Object.keys(data).forEach(key => {
        //为vm添加与key相同属性,且配置相应的属性描述符
        Object.defineProperty(this,key,{
            configurable: false,//可重新定义
            enumerable: true,//可枚举
            get () {
                return this._data[key]
            },
            set (newVlue) {
                this._data[key] = newVlue
            }
        })
    })
}

//实例化
var vm = new MVVM({
    data: {
        msg:'Hello World'
    }
})

//vm.msg相当于调用get方法返回this._data[key]
console.log(vm.msg) //Hello World
//给vm.msg赋值相当于调用set方法,更新this._data[key]的值
vm.msg = "msg is change"
console.log(vm.msg) //msg is change
</script>

2. Data hijacking

Data hijack popular to say that monitor changes in the properties, and then triggers the corresponding callback function. Such as data vue template has changed, the page also will respond, his principle is to realize data monitor, once the change occurs, update the dom in the callback function.

Way to add attributes to objects There are three, we have already learned two kinds:

//初始化时添加属性
var person = {name:"谢耳朵"}
//点语法添加属性
person.age = 25

console.log(person) //{name: "谢耳朵", age: 25}

The method of adding these two properties, either getting a property value or attribute value modification, are the object of the operation itself. While adding attributes using the third method may be configured to set other attributes, including get and set methods.
Syntax: Object.defineProperty (obj, key, options )

Data hijacking implementation principles:
(1) Data Agent can not operate itself, because you want to access its value when calling the get method to access itself will trigger the get method, resulting in an endless loop. The same is true when a property assignment, a method to set a new value is assigned to themselves, will trigger its own set method, can also cause an infinite loop
(2) Since I can not operate itself, it would need a separate configuration for each attribute variable. Either get or set methods are independent of the operating variables, in order to avoid an endless loop.
(3) The solution: to Object.defineProperty wrapped in a layer function, the property value as a parameter passed in val. And this is said earlier val independent variable, when accessing get method can return val. When the trigger set method, modifying the value of val

<script>
//这个例子没有深度劫持
function proxyData(obj,key,val){
    //val作为一个中间变量,负责存储这个属性的值
    Object.defineProperty(obj, key, {
        configurable:false,
        enumerable:true,
        get(){
            //get方法返回这个val
            console.log('通过get方法获取了'+key+'属性的值')
            return val
        },
        set(newVal){
            //set方法修改这个val
            if(newVal === val){
                return
            }
            console.log(key+'属性的值发生了变化')
            console.log('可以在这个回调函数中做其他事件,例如更新页面dom等')
            val = newVal
        }
    })
}

var p = {name: 'kyo', age: 20}
//调用proxyData()进行数据劫持
Object.keys(p).forEach((key) => {
    var val = p[key]
    proxyData(p,key,val)
})

//获取属性值
var name = p.name
//修改属性值
p.age = 27
</script>

Print Console:

通过get方法获取了name属性的值
age属性的值发生了变化
可以在这个回调函数中做其他事件,例如更新页面dom等

The above method for only the first layer properties of the object, if the object contains a multi-layer objects, the need for each level attribute data hijacking when you need to use a recursive call.
Ideas: the data for all properties hijacking, if his property value type is object, then the value of this property is a recursive call

<script>
//利用递归调用深度劫持
function proxyData(obj,key,val){
    //val作为一个中间变量,负责存储这个属性的值
    Object.defineProperty(obj, key, {
        configurable:false,
        enumerable:true,
        get(){
            //get方法返回这个val
            console.log('通过get方法获取了'+key+'属性的值')
            return val
        },
        set(newVal){
            //set方法修改这个val
            if(newVal === val){
                return
            }
            console.log(key+'属性的值发生了变化')
            console.log('可以在这个回调函数中做其他事件,例如更新页面dom等')
            val = newVal
        }
    })
    //判断属性值是否为object,如果是则对这个值进行递归调用
    if(val instanceof Object){
        Object.keys(val).forEach(key => {
            proxyData(val,key,val[key])
        })
    }
}

var data = {
    name: 'kyo',
    age: 20,
    skill: ['大蛇薙', '最终决战奥义“无式'],
    father: {
        name: '草薙柴舟',
        age: 50
    }
}
Object.keys(data).forEach((key) => {
    var val = data[key]
    proxyData(data,key,val)
})

//读取属性值
var fatherName = data.father.name
//修改属性值
data.father.age = 52
</script>

Print Console:

//data.father.name
通过get方法获取了father属性的值
通过get方法获取了name属性的值

//data.father.age = 52
通过get方法获取了father属性的值
age属性的值发生了变化
可以在这个回调函数中做其他事件,例如更新页面dom等

Guess you like

Origin www.cnblogs.com/OrochiZ-/p/11853585.html