Vue源码分析之准备知识点和数据代理

准备知识点

1、[].slice.call()/Array.prototype.slice.call()    将伪数组转换成真数组

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul id="fragment_test">
        <li>test1</li>
        <li>test2</li>
        <li>test3</li>
    </ul>
    <script>      
        const lis = document.getElementsByTagName('li')
        console.log(lis instanceof Array, lis[1].innerHTML, lis.forEach)  //false 'test2' undefined
        const lis2 = Array.prototype.slice.call(lis)
        console.log(lis2 instanceof Array, lis2[1].innerHTML, lis2.forEach)  //true 'test2' function   
    </script>
</body>
</html>

2、node.nodeType    得到节点类型

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="test">哈哈哈</div>
    <script>
        const elementNode = document.getElementById('test')
        const attrNode = elementNode.getAttributeNode('id')
        const textNode = elementNode.firstChild
        console.log(elementNode.nodeType, attrNode.nodeType, textNode.nodeType)  //1 2 3   
    </script>
</body>
</html>

3、Object.defineProperty(obj, propertyName, {})    给对象添加属性(指定描述符)ES5语法,不支持IE8

        属性描述符:

  • 数据描述符

            configurable:是否可以重新定义
            enumerable:是否可枚举
            value:初始值
            writable:是否可以修改属性值

  • 访问描述符

            get:回调函数,根据其它相关的属性动态计算得到当前属性值
            set:回调函数,监视当前属性值的变化,更新其它相关的属性值

const obj = {
    firstName: 'A',
    lastName: 'B'
}
Object.defineProperty(obj, 'fullName', {
    configurable: false,
    enumerable: true,
    get () {
        return this.firstName + ' ' + this.lastName
    },
    set (value) {
        const names = value.split(' ')
        this.firstName = names[0]
        this.lastName = names[1]
    }
})

4、Object.keys(obj)    得到自身可枚举属性组成的数组

const names = Object.keys(obj)
console.log(names)

5、obj.hasOwnProperty(prop)    判断prop是否是自身的属性

console.log(obj.hasOwnProperty('fullname'), obj.hasOwnProperty('toString'))

6、DocumentFragment    文档碎片(高效更新多个节点)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="test">哈哈哈</div>
    <ul id="fragment_test">
        <li>test1</li>
        <li>test2</li>
        <li>test3</li>
    </ul>
    <script>
        const ul = document.getElementById('fragment_test')
        const fragment = document.createDocumentFragment()
        let child
        while(child=ul.firstChild){  // 一个节点只能有一个父亲
            fragment.appendChild(child)
        }
        Array.prototype.slice.call(fragment.childNodes).forEach(node => {
            if (node === 1) {  //  元素节点<li>
                node.textContent = 'xixixi'
            }
        })
        ul.appendChild(fragment)        
    </script>
</body>
</html>

数据代理

  • 数据代理:通过一个对象代理另一个对象中属性的操作(读/写)
  • vue数据代理:通过vm对象来代理data对象中所有属性的操作
  • 好处:更方便的操作data中的数据
  • 基本实现流程:
  1. 通过Object.defineProperty()给vm添加与data对象的属性对应的属性描述符
  2. 所有添加的属性都包含getter/setter
  3. getter/setter内部去操作data中对应的属性数据
function MVVM (options) {
    this.$options = options
    var data = this._data = this.$options.data
    var me = this

    // 实现vm.xxx -> vm._data.xxx
    Object.keys(data).forEach(function(key){
        me.proxy(key)
    })
}

MVVM.prototype = {
    _proxy: function(key) {
        var me = this
        Object.defineProperty(me, key, {
            configurable: false,
            enumerable: true,
            // 当通过vm.xxx读取属性值时可调用,从data中获取对应的属性值返回,代理读操作
            get: function proxyGetter () {
                return me._data[key]
            },
            // 当通过vm.xxx = value时,value被保存到data中对应的属性上,代理写操作
            set: function proxySetter (value) {
                me._data[key] = value
            }
        })
    }
}
发布了20 篇原创文章 · 获赞 3 · 访问量 877

猜你喜欢

转载自blog.csdn.net/qq_16049879/article/details/104659371
今日推荐