(尚046)Vue_源码分析_准备1+(尚047)Vue_源码分析_准备2+(尚048)Vue_源码分析_准备3

查找各种方法上MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/
 
准备知识:
1) [].slice.call(lis): 将伪数组转换为真数组
伪数组不是数组,是个对象;只是对象特性有length属性;还有下标属性(说白了,可以通过下标取对应的属性值);
const lis = document.getElementsByTagName('li') // lis是伪数组(是一个特别的对象, length和数值下标属性)
console.log(lis instanceof Array,lis[1].innerHTML,lis.forEach) //false instanceof Array用来验证是否是数组 //lis[1].innerHTML 取第二个li文本内容
//lis.forEach为undifined
//关键是我就想通过li,遍历整个数组
//call让一个函数Array.prototype.slice成为指定方法的调用
const lis2=Array.prototype.slice.call(lis)
console.log(lis2 instanceof Array,lis2[1].innerHTML,lis2.forEach)//true 'test2' function

 

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

//节点是一个抽象的说法
//节点有很多类型:(节点从大到小排)
//1).最大的节点是?document(文档节点)(指整个html页面)
//2).Element(元素节点)
//3.1).Attribute(属性节点)
//3.2).Text(文本节点)
const elementNode=document.getElementById('test')//文档节点
const attrNode=elementNode.getAttributeNode('id')//元素节点
const textNode=elementNode.firstChild //.firstChild返回文档的首个子节点
console.log(elementNode,attrNode,textNode)
console.log(elementNode.nodeType,attrNode.nodeType,textNode.nodeType)

nodeType 属性返回以数字值返回指定节点的节点类型。

如果节点是元素节点,则 nodeType 属性将返回 1。

如果节点是属性节点,则 nodeType 属性将返回 2。

如果节点是文本节点,则nodeType属性返回的值是3.

 
3) Object.defineProperty(obj, propName, {}): 给对象添加/修改属性(指定描述符)
configurable: true/false 是否可以重新 define
enumerable: true/false 是否可以枚举(for..in / keys())
value: 指定初始值
writable: true/false value 是否可以修改
get: 回调函数, 用来得到当前属性值
set: 回调函数, 用来监视当前属性值的变化
const obj={
firstName:'A',
lastName:'B'
}
//给obj添加fullName属性
//平时使用方式obj.fullName='A-B' 但是当firstName变化时,fullName不会自动变化,故采用以下方式:
/**
* (整体都叫)属性描述符:
* 1)数据描述符
* configurable:是否可以重新定义false为不可重新定义
* enumerable:是否可以枚举(遍历查找出所有的值)
* value:指定初始值
* writable:是否可以修改属性值
* 2)访问描述符
* get:根据其他相关的属性动态计算得到当前属性值,类型:回调函数
* set:监视当前属性值的变化,更新其他相关的属性值,类型:回调函数
*/
//'fullName'的相关属性是firstName和lastName
//注意:IE8不支持Object.defineProperty,说明vue不支持IE8
   Object.defineProperty(obj,'fullName',{
get(){
return this.firstName+'-'+this.lastName
},
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,obj.lastName) //E F

Object.defineProperty(obj,'fullName2',{
configurable:false,
enumerable:true,
value:'G-H',
writable:false
})
console.log(obj.fullName2)
obj.fullName2='J-K'
console.log(obj.fullName2)
/* Object.defineProperty(obj,'fullName2',{ //不能重新定义
configurable:false,
enumerable:false,
value:'G-H',
writable:true
})*/
4) Object.keys(obj): 得到对象自身可枚举的属性名的数组
const names=Object.keys(obj)
console.log(names) //为什么没有fullName??enumerable默认为false
5) DocumentFragment: 文档碎片(高效批量更新多个节点)
 

 

const ul=document.getElementById('fragment_test')
//1.创建fragment
const fragment=document.createDocumentFragment()
//2.取出url中所有子节点取出保存到fragment
let child
while(child=ul.firstChild){//先取出ul的第一个孩子,文本的换行节点 <ul id="fragment_test"> 换行节点 <li>test1</li> 赋值给child
//换行也是一个文本数据
//接着判断child为不为真?为真;不加fragmentd.appendChild(child)为一个死循环
//注意:一个节点只能有一个父亲;换行节点的父亲为ul,现在将其放入了fragment,也就是说现在换行节点的父亲成了fragment
//也就是说将换行节点的父亲从ul中拿出来,即:移除
//.appendChild()先将child从ul中移除,添加为fragment子节点
fragment.appendChild(child)
}

//3.更新fragment中所有li的文本
Array.prototype.slice.call(fragment.childNodes).forEach(node=>{
if(node.nodeType===1){//元素节点<li>
node.textContent='atguigu' //内存中独立,界面不更新
}
})

//4.将fragment插入ul //但是fragment本身是不会进入页面的,因为他不对应任何标签,但我内部保存了很多标签,相当于把我内部标签塞到了ul里
ul.appendChild(fragment)
6) obj.hasOwnProperty(prop): 判断 prop 是否是 obj 自身的属性
//document:对应显示的界面,包含n个element  一旦更新document内部的某个元素界面更新
// DocumentFragment: 内部中保存n个element的容器对象(不与界面关联),如果更新feamgnent中的某个element,界面不变
console.log(obj.hasOwnProperty('fullName'),obj.hasOwnProperty('toString'))   //true  false

 

 

 

 

 将多次更新更改为一次批量更新;

最终减少更新界面的次数

 

posted @ 2020-02-10 15:52  Curedfisher  阅读(108)  评论(0编辑  收藏  举报