前言

本文章结合VUE核心技术-尚硅谷的45-48集做的归纳总结。
  教程的文档里面提到仿照github上的朋友实现的库进行讲解 github
  抛开视频教程的讲解,其实github上的readme文档已经有了很详细的说明。
  视频教程提供了几个点

  • 数据代理
  • 模板解析
  • 数据绑定

  Hexo 博客的 Markdown 是支持嵌套 <script></script> 标签来执行js代码的。
  下面我直接使用 Markdown 来写 js 验证教程的输出结果。
  不仅将运行结果打印到控制台上,也添加了网页的显示。

根据伪数组生成对应的真数组

数组判定

  当我们使用 getElementsByTagName 获取到元素数组,会发现这个并不是js的数组。
  尽管它可以通过数组下标获取到对应的元素
  数组的一些常规方法如 foreach 也无法识别

数组slice

  在 es6 中可以使用 Array.from 来获取到真数组
  在 es5 中可以借助 Array.slice() 不传参数获取到数组的浅拷贝
  借助 slice.call 可以让非数组对象执行slice方法
  在 es5 中可以使用 Array.prototype.slice.call(lis)来获取到真数组

1
2
3
4
5
6
7
8
const lis = document.getElementsByTagName('li') 
console.log(lis instanceof Array)
console.log(lis[1].innerHTML)
console.log(lis.forEach)
const lis2 = Array.prototype.slice.call(lis);
console.log(lis2 instanceof Array);
console.log(lis2[1].innerHTML);
console.log(lis2.forEach);

切换为HTML文本

  • 1

  • 2

  • 3


  • 点击执行js代码


    node.nodeType: 得到节点类型

    nodeType

      不同类型的节点 nodeType 值是不一样的

    1
    2
    3
    4
    5
    6
    const elementNode = document.getElementById('test')
    const attrNode = elementNode.getAttributeNode('id')
    const textNode = elementNode.firstChild
    console.log(elementNode.nodeType)
    console.log(attrNode.nodeType)
    console.log(textNode.nodeType)

    切换为HTML文本

    blog.l0v0.com


    点击执行js代码


    给对象添加属性

    defineProperty

    defineProperty 的属性含义
    属性描述符:

    数据描述符:

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

    访问描述符:

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

      通过设定 enumerable true 可以实现 for .. in keys() 的效果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    const obj = {
    firstName: 'A',
    lastName: 'B'
    }

    Object.defineProperty(obj, 'fullName', {
    // 当读取对象此属性值时自动调用, 将函数返回的值作为属性值, this为obj
    get () {
    return this.firstName + "-" + this.lastName;
    },
    // 当修改了对象的当前属性值时自动调用, 监视当前属性值的变化, 修改相关的属性, this为obj
    set (value) {
    const names = value.split('-');
    this.firstName = names[0];
    this.lastName = names[1];
    }
    })

    console.log(obj.fullName); // A-B
    obj.firstName = 'C';
    obj.lastName = 'D';
    console.log(obj.fullName); // C-D
    obj.fullName = 'E-F'
    console.log(obj.firstName); // E
    console.log(obj.lastName); // F

    // 不可以使用两次 defineProperty
    /*Object.defineProperty(obj, 'fullName', {
    configurable: true,
    enumerable: true,
    value: 'G-H',
    writable: true
    })*/

    // Object.keys(obj): 得到对象自身可枚举属性组成的数组
    Object.defineProperty(obj, 'fullName2', {
    configurable: false, //是否可以重新define
    enumerable: true, // 是否可以枚举(for..in / keys())
    value: 'A-B', // 指定初始值
    writable: false // value是否可以修改
    })
    console.log(obj.fullName2) // A-B
    obj.fullName2 = 'E-F'
    console.log(obj.fullName2) // A-B

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

    // obj.hasOwnProperty(prop): 判断prop是否是obj自身的属性
    console.log(obj.hasOwnProperty('fullName')) // true
    console.log(obj.hasOwnProperty('toString')) // false

    点击执行js代码


       defineProperty 属性直到 es5 才支持,因此 IE8 及以下的浏览器都不支持 defineProperty 属性
      因此 Vue 也不支持 IE8 及以下的浏览器

    DocumentFragment: 文档碎片(高效批量更新多个节点)

      document: 对应显示的页面, 包含n个element 一旦更新document内部的某个元素界面更新
      documentFragment: 内存中保存n个element的容器对象(不与界面关联), 如果更新framgnet中的某个element, 界面不变。
      使用documentFragment只需更新一次界面,执行效率更加高效!!!

    操作步骤:

    1. 创建fragment
    2. 取出ul中所有子节点取出保存到fragment
    3. 更新fragment中所有li的文本
    4. 将fragment插入ul
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    const ul = document.getElementById('fragment_test')
    // 1. 创建fragment
    const fragment = document.createDocumentFragment()
    // 2. 取出ul中所有子节点取出保存到fragment
    let child
    // 注意:这里不是判断语句 !!! child 获取 ul 下的标签元素,然后判断child是否为真
    while(child=ul.firstChild) {
    fragment.appendChild(child) // 先将child从ul中移除, 添加为fragment子节点
    }

    // 3. 更新fragment中所有li的文本
    Array.prototype.slice.call(fragment.childNodes).forEach(node => {
    if (node.nodeType===1) { // 判断元素节点 <li>
    node.textContent = 'l0v0.com'
    }
    })

    // 4. 将fragment插入ul
    ul.appendChild(fragment)

    切换为HTML文本

    点击执行js代码