vue源码解析

1、准备知识

1、[].slice.call(lis):将为数组转换成真数组

(1)、什么是伪数组?

  • 具有length属性;
  • 按索引方式存储数据;
  • 不具有数组的push、pop等方法;

例子:

<body>
    <ul>
        <li>Vue</li>
        <li>React</li>
        <li>Flutter</li>
    </ul>
</body>
<script type="text/javascript">
	// 这里的lis就是伪数组
    const lis = document.getElementsByTagName('li') 
    console.log(lis instanceof Array); // false 
    // 伪数组具有索引
    console.log(lis[1].innerHTML); // React 
    
    console.log(lis.forEach); // undefined 

    // 将伪数组转换成真数组(有两种写法)
    // const lis2 = Array.prototype.slice.call(lis) // 写法1
    const lis2 = [].slice.call(lis) // 写法2
    console.log(lis2 instanceof Array); // true 
    console.log(lis2[1].innerHTML); // React 
    console.log(lis2.forEach); // ƒ forEach() { [native code] }
</script>

2、node.nodeType: 得到节点类型

节点类型

  • document(文档)最大的节点类型
  • Element(元素)
  • Attr(属性)
  • Text(文本)

nodeType是不同类型节点的标识,不同类型节点的nodeType的值不一样,可以以此区分
例子:

<div id="text">哈哈哈</div>
<script>
    const elementNode = document.getElementById('text') // 元素节点
    const attrNode = elementNode.getAttributeNode('id') // 属性节点
    const textNode = elementNode.firstChild             // 文本节点
    console.log(elementNode.nodeType)   // 1
    console.log(attrNode.nodeType)      // 2
    console.log(textNode.nodeType)      // 3
</script>

3、Object.defineProperty()

Object.defineProperty(obj, prop, descriptor)
给对象添加/修改属性
这个属性不支持IE8,因此vue不支持IE8

vue支持的IE浏览器的最低版本是多少?
答:IE8,因为vue源码中使用了Object.defineProperty(),改方法不支持IE8及以下。

1、参数:

  • obj 要定义属性的对象。
  • prop 要定义或修改的属性的名称或 Symbol 。
  • descriptor 要定义或修改的属性描述符。

2、对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符

  • 数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的;
  • 存取描述符是由 getter 函数和 setter 函数所描述的属性;
  • 描述符只能是这两者其中之一;
  • 不能同时是两者;
    在这里插入图片描述
    3、描述符可拥有的键值
    在这里插入图片描述
    4、vue源码demo
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);
obj.firstName = 'C'
obj.lastName = 'D'
console.log(obj.fullName);

3、Object.keys(obj)

得到对象自身可枚举的属性名的数组
即属性名的enumerable的值是false

4、obj.hasOwnProperty(prop)

判断prop是否是obj自身的属性

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

  • DocumentFragment,文档片段接口,一个没有父对象的最小文档对象
  • 它被作为一个轻量版的 Document 使用,就像标准的document一样,存储由节点(nodes)组成的文档结构
  • 与document相比,最大的区别是DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。

document: 对应显示的页面,包含n个element,一旦更新ducument内部的某个元素界面更新
documentFragment: 内存中保存n个element的容器对象(不与界面关联),如果更新fragement中的某个元素,界面不变。

 <ul id="fragment">
   <li>test1</li>
   <li>test2</li>
   <li>test3</li>
</ul>
<script>
   const ul = document.getElementById('fragment')
   // 1、创建fragment
   const fragment = document.createDocumentFragment()
   
   // 2、取出ul中所有子节点,保存到fragment
   let child
   /*
    * child = ul.firstChild这个意思是先赋值再判断
    * 先将ul.firstChild的值赋给child再判断child是否存在
    */  
   /*
    * 没有导致死循环的愿意是因为:一个节点只能有一个父节点
    *  ul.firstChild赋给了fragment ul就没有了这个子节点
    * 注意:这里取出的子节点包含换行
    */
   while (child = ul.firstChild) {
       fragment.appendChild(child)
   }
   
   // 3、更新fragment中的所有li文本
   Array.prototype.slice.call(fragment.childNodes).forEach(node => {
       console.log(node);
       console.log(node.nodeType);
       if (node.nodeType === 1) {
           node.textContent = 'hahaha'
       }
   })
   
   // 4、将fragment插入ul
   ul.appendChild(fragment)
</script>

2、数据代理

  1. 通过一个对象代理对另一个对象中属性的操作(读/写);
  2. 通过vm对象来代理data对象中所有属性的操作;
  3. 好处: 更方便的操作data中的数据;
  4. 基本实现流程:
    1).通过Object.defineProperty()给vm添加与data对象的属性对应的属性描述符
    2). 所有添加的属性都包含getter/setter
    3). 在getter/setter内部去操作data中对应的属性数据
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值