文章目录
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、数据代理
- 通过一个对象代理对另一个对象中属性的操作(读/写);
- 通过vm对象来代理data对象中所有属性的操作;
- 好处: 更方便的操作data中的数据;
- 基本实现流程:
1).通过Object.defineProperty()给vm添加与data对象的属性对应的属性描述符
2). 所有添加的属性都包含getter/setter
3). 在getter/setter内部去操作data中对应的属性数据