了解以下几点
[].slice.call()
:将arguments
转为数组node.nodeType
:判断节点类型- 了解
Object.defineProperty
是什么?- 理解:
Object.hasOwnProperty
DocumentFragment
文档碎片
<ul id="liBox"> <li>[].slice.call(childNodes)</li> <li>Object.defineProperty</li> <li>Object.keys</li> <li>Object.hasOwnProperty</li> <li>node.nodeType</li> <li>createDocumentFragment</li> </ul>
1、[].slice.call()
:
// 1. [].slice.call(childNodes) 伪数组转换为数组 // 伪数组 ==> 不能直接使用数组方法 但是内部有下标 长度 //伪数组__proto__ 不指向Array 指向的是 对象object let lis = document.getElementsByTagName("li"); console.log(lis); let arr = [].slice.call(lis); console.log(arr);
2、node.nodeType
<div id="app" class="app"> node.nodeType </div>
let elementNode = document.getElementById("app"); //let attrNode = elementNode.getAttribute("id");//获取属性值 let attrNode = elementNode.getAttributeNode("id"); //获取属性节点 let textNode = elementNode.firstChild; //获取文本节点 console.log(elementNode, attrNode, textNode); console.log(elementNode.nodeType, attrNode.nodeType, textNode.nodeType) //textNode.getAttribute("v-model") -->name console.dir(textNode); //所有的节点都继承自Node // Node上拥有一个nodeType
3、Object.defineProperty()
//Object上常用的API defineProperty keys hasOwnProperty assign // 2.Object.defineProperty 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 /** * 定义属性 * obj: 要增加或者修改属性的对象 * prop: 属性名 * descriptor: 属性描述 * return obj */ //Object.defineProperty(obj, prop, descriptor) //属性描述符 // 数据描述符 //configurable: 布尔 --> 是否可配置 //enumerable: 布尔 --> 是否可枚举 //value: 默认值 //writable: 布尔 --> 是否可重写 // 访问(存取)描述符 //get //回调函数 根据其他属性,动态计算当前属性的值 //set //回调函数 监听当前属性值是否发生改变 然后更新其他相关属性 let obj = { firstName: "A", lastName: "B" }; Object.defineProperty(obj, "fullName", { enumerable: true, get() { //回调函数 根据其他属性,动态计算当前属性的值 console.log("读取fullName"); return this.firstName + "-" + this.lastName }, set(newValue) { //回调函数 监听当前属性值是否发生改变 然后更新其他相关属性 console.log("set方法--->", newValue); //"C-D" let fullName = newValue.split("-"); //["C","D"] this.firstName = fullName[0]; this.lastName = fullName[1]; } }); Object.defineProperty(obj, "fullName1", { configurable: true, enumerable: false, }); Object.defineProperty(obj, "fullName1", { enumerable: true, // Cannot redefine property: fullName1 writable: false, // --> 是否可写 value: "1234" //默认值 }); console.log(obj.fullName); //A-B obj.firstName = "C"; console.log(obj.fullName); //C-B obj.fullName = "E-F"; console.log(obj.firstName, obj.lastName); //E ,F
4、Object.hasOwnProperty()
**hasOwnProperty()**
方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。Object
的对象都会继承到 hasOwnProperty
方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和 in
运算符不同,该方法会忽略掉那些从原型链上继承到的属性。console.log("hasOwnProperty-->", obj.hasOwnProperty("fullName")); //true
5、DocumentFragment
它被作为一个轻量版的 Document
使用,就像标准的document
一样,存储由节点(nodes
)组成的文档结构。
与document
相比,最大的区别是DocumentFragment
不是真实 DOM
树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。
<body> <ul id="liBox"> <li>这是一个文档碎片</li> <li>这是一个文档碎片</li> <li>这是一个文档碎片</li> <li>这是一个文档碎片</li> <li>这是一个文档碎片</li> </ul> </body> </html> <script> /* 利用类似于虚拟DOM思想 1、首先在内存中创建一个空的文档 2、获取出要更改的节点 3、查看节点状态,判断这个节点是否可更改 4、对符合条件的节点进行修改, 5、成功修改后将其一次行的更新到页面视图上 */ // 1、创建一个文档 var frag = document.createDocumentFragment() console.dir(frag); // 2、获取ul标签 var li = document.getElementById('liBox') console.log(li); while (li.firstChild) { frag.appendChild(li.firstChild) } let child = frag // console.log(child); // // 3、修改 Array.from(child).forEach(item => { /* #text==>nodeType:3 li===>nodeType:1 */ // console.log(child); if (item.nodeType === 1) { item.innerHTML = '这是修改后的文档碎片' } }) // console.log(frag); // // 4、将frag进行添加 li.appendChild(frag) </script>
什么是数据代理?
vm
对象代理vm.data
对象中所有的属性的操作data
中的所有的操作。基本流程:
Object.defineProperty
给vm
添加与data
对象的属性对应的属性描述符。getter/setter
。getter/setter
操作data
中对应的属性数据function MVVM(options) { //给实例新增一个$options属性,.并且把传递过来的配置进行暂存 this.$options = options; //在实例上新增一个_data 保存传递过来的data数据 var data = this._data = this.$options.data; //保存this 为了之后使用this的时候保证this指向的正确性 var me = this; //通过Object.keys取出data中每一项数据的属性名,然后遍历调用_proxy方法 Object.keys(data).forEach(function(key) { // 数据代理 me._proxy(key); }); //为data所有数据进行劫持 结合订阅发布模式 observe(data, this); //增加模版解析 this.$compile = new Compile(options.el || document.body, this) } MVVM.prototype = { $watch: function(key, cb, options) { new Watcher(this, key, cb); }, _proxy: function(key) {//实现数据代理 var me = this;//暂存this 保证this的指向正确 这里的this还是实例vm //通过defineProperty方法在实例(vm)上新增所有与data中属性所对应属性,并且为该属性添加get和set方法 Object.defineProperty(me, key, {//vm.name configurable: false, enumerable: true, get: function proxyGetter() { //实现了vm代理data中数据的读操作 return me._data[key]; }, set: function proxySetter(newVal) {//vm.name = "bb" //实现了vm代理data中数据的写操作 me._data[key] = newVal; } }); } };