当定义了一个变量 a, var a = 10.
调用 a 的时候, 其实是调用了 a 的 getter 方法, 修改的时候, 使用了 setter方法
然后就尝试写一个

let test = {
    name: 'abc',
    get name () {
        console.log("-------")
        return this.name
    },
    set name (n) {
        this.name = n
    }
}

在控制台调用 test.name 1s 之后, 浏览器炸了....
这是因为 get 的时候, 取用了 name, 然后 取用的时候, 又去取用了 name. 无限循环
所以一般会这么写

let test = {
    _name: 'abc',
    get name () {
        console.log("-------")
        return this._name
    },
    set name (n) {
        this._name = n
    }
}

调用 getter 方法, 正常打印出 name
在这之后, 就可以做很多事情了.
vue 双向数据绑定的基础就在这里, 因为 vue 需要知道什么时候某个变量的值被改变了. 其实只需要在 setter 方法执行完毕调用一个自定义的
update `函数就可以了

![QWN2)02[9`(N$~TX75D4W.png](https://upload-images.jianshu.io/upload_images/9172646-3eeabee2a6331e40.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

 let vm = new Vey({
            el: 'app',
            data: {
                x: 1,
                y: 2,
                z: 3,
                a: {
                    b: 4,
                    c: 5
                }
            }
        })

initData 的时候, 其实是遍历了一个对象A, A里面是vue实例的data, 然后在另外一个对象B中, 写个多个gettter, setter, 然后指向的是A的数据. initData 返回的是新的对象B

function Vey(options) {
    this.el = options.el
    this.data = options.data
    // 拿到数据之后, 需要对它进行一些操作, 即重写 getter setter
    initData.call(this, this.data)
}


function initData (data) {
    let newObject = new Object()
    for (let key in data){
        let temp;
        // 如果 data[key] 是一个对象, 递归重写 setter getter
        if(typeof data[key] === 'object'){
            temp = new Object()
            initData.call(temp, data[key])
        } else {
            temp = data[key]
        }
        // 重写 getter setter
        Object.defineProperty(newObject, key, {
            configurable: true,
            enumerable: true,
            get: function() {
                console.log('get')
                return temp
            },
            set: function (n) {
                console.log('set')
                temp = n
            }
        })

        // 将 data 中的数据直接绑定在 vue 的实例上, 就不用使用 vm.$data 调用数据了.
        Object.defineProperty(this, key, {
            configurable: true,
            enumerable: true,
            get: function() {
                console.log('get')
                return temp
            },
            set: function (n) {
                console.log('set')
                temp = n
            }
        })
    }
    // 将 $data 绑定给 vue 实例
    this.$data = newObject
}

如此一来, 就实现了和 vue 一样的访问数据的方式.