准备知识
1、[].slice.call():将伪数组转换成真数组
- 伪数组:length ,可下标获取 eg:$(“li”)
- 验证 instanceof Array
- Array.prototype.slice.call() 效率好点,原型链少查找一层
2、node.nodeType:得到节点类型,来做不同的方法处理
- document / Element / Attr Text
3、Object.defineProperty(obj,propertyName,{}):给对象添加属性(指定描述符)
const obj = {
firstName:'A',
lastName:'B',
}
/**
* configurable 是否重新定义
* enumerable 是否可以枚举
* value 初始值
* writable 是否修改
* get 动态获取当前值 回调函数
* set 动态监听属性的变化 回调函数
*/
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
Vue浏览器支持IE8以上,一部分原因就是这个属性IE8下不支持
4、Object.keys(obj):得到对象可枚举(enumerable)属性组成的数组
5、obj.hasOwnProperty(prop):判断prop是否是obj自身的属性,如果是原型继承的就是false
6、DocumentFragment:文档碎片(高效批量更新多个节点)内存中保存N个element的容器对象。如果更新framgnet中的某个element,界面不变,一次批量更新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试</title>
</head>
<body>
<ul id="fragment_test">
<li>test1</li>
<li>test2</li>
<li>test3</li>
</ul>
<script>
const ul = document.getElementById('fragment_test')
//1.创建fragment
const fragment =document.createDocumentFragment()
//2.取出ul下面的子节点,保存到fragment
let child;
while(child=ul.firstChild){ //一个节点一个父亲
fragment.appendChild(child) //先将child从ul中移除,调价到fragment
}
//3.更新fragment中所有li的文本 伪数组 包含文本节点和元素节点
Array.prototype.slice.call(fragment.childNodes) .forEach(item => {
if(item.nodeType===1){
item.textContent = 'test4'
}
});
//4.将fragment放到ul中
ul.appendChild(fragment)
</script>
</body>
</html>
某大佬简易Vue源代码地址: https://github.com/DMQ/MVVM 以后文章代码讲解也是按照这个说的
自己新建一个html,把js文件导入,测试
<script src="js/mvvm.js"></script>
<script src="js/observer.js"></script>
<script src="js/compile.js"></script>
<script src="js/watcher.js"></script>
数据代理
1)数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
2)vue 数据代理:通过vm对象来代理data对象中所有属性的操作
const vm = new Vue({
el:'#test', //原生 可以jquery[0]
data:{
name:'feifei'
}
})
console.log(vm.name,vm) //feifei vm代理对data数据的读操作
vm.name = 'xiaoxiao' // vm代理对data数据的写操作
console.log(vm._data.name,vm.name) //xiaoxiao xiaoxiao
name(…)(invoke property getter)
3)好处:更方便的操作data中的数据
4)基本实现流程
- a.通过object.defineProperty给vm添加与data对象属性对应的属性描述符
- b.所有添加的属性都包含着getter/setter
- c.getter/setter
function MVVM(options) {
// 将配置对象保存到vm中 new()方法
this.$options = options || {};
// 将data对象保存到vm和变量data
var data = this._data = this.$options.data;
// 将vm保存到变量me
var me = this;
// 数据代理
// 实现 vm.xxx -> vm._data.xxx
Object.keys(data).forEach(function(key) { // key:data中属性名 data:属性名集合
me._proxyData(key);
});
}
MVVM.prototype = {
_proxyData: function(key, setter, getter) {
var me = this;
setter = setter ||
Object.defineProperty(me, key, { // 核心
configurable: false, // 不能重新定义
enumerable: true, //可枚举遍历
// 当通过vm.xx读取属性值时调用时,从data中获取对应的属性值返回 代理读
get: function proxyGetter() {
return me._data[key];
},
// 当通过vm.xx=value时调用时,从data中保存对应的属性值 代理写操作
set: function proxySetter(newVal) {
me._data[key] = newVal;
}
});
},
}