下面是我边看视频变记录的重点难点,详细具体有条理的看我转载的那篇尚硅谷课件,课件有的内容我基本不重复写到
1.类数组和数组
用document.getElementsByClassName()方法或者jQuery方法获取的标签集合是类数组,不是真正的数组。使用instanceof可以知道lis instanceof Object为true; lis instanceof Array为false。假如用lis接收,那么lis可以使用lis[index]的方式获取某一个标签对象,但是不可以使用Array(数组)原型链上的属性和方法。如forEach、splice、join等。
2.类数组使用forEach遍历所有标签对象(类数组转数组)
ES6: Array.from(lis)
ES5:[].slice.call(lis) 或者 Array.prototype.slice.call(lis)
3.节点类型(nodeType)
常用的:
Document
Element
Attribute
Text
node.nodeType获取节点类型(Number)
4.定义属性Object.defineProperty(obj, prop, descriptior)
在descriptior内定义set和get方法,可以实现属性的监听和获取。
IE8不支持此语法,此方法是Vue实现数据绑定等操作的核心方法。
属性描述符:
1.数据描述符:
configurable: true/false 是否可以重新define
enumerable: true/false 是否可以枚举(for…in / keys())
value: 指定初始值
writable: true/false value 是否可以修改
2.访问描述符:
get: 回调函数, 用来得到当前属性值
set: 回调函数, 用来监视当前属性值的变化
5.判断是否是自身属性(obj.hasOwnProperty(pro))
JS学过,返回布尔值。
6.DocumentFragment: 文档碎片(高效批量更新多个节点)
内存中保存n个element的容器对象(不与界面关联),如果更新fragment中的某个element,界面不变。
多次更新界面变成一次更新界面,减少更新界面的次数。
一个节点只能有一个父亲
使用步骤:
- 创建fragment
- 取出要更新的所有节点的父节点的所有子节点保存到fragment中(使用appendChild()方法)
- 更新fragment中的所有要更新节点的更新内容
- 将fragment插入更新节点的父节点
7.数据代理
vue 数据代理: 通过vm 对象来代理data 对象中所有属性的操作
vm._data.name === vm.name
8.set和get执行的断点调试
打断点后观察可知:
1.vm对象对data中的数据实现数据代理
2.vm中触发回调函数执行,函数中调用_propxy()方法,里面是用Object.defineProperty(obj, prop, descriptior)实现。
3.修改属性值调用Object.defineProperty(obj, prop, descriptior)中的descriptior对象中的set方法,数据被存入data。
4.页面中显示数据调用get方法从data中取数据。
9.大佬仿Vue的main.js
/*
相关于Vue的构造函数
*/
function MVVM(options) {
// 将选项对象保存到vm
this.$options = options;
// 将data对象保存到vm和datq变量中
var data = this._data = this.$options.data;
//将vm保存在me变量中
var me = this;
// 遍历data中所有属性
Object.keys(data).forEach(function (key) { // 属性名: name
// 对指定属性实现代理
me._proxy(key);
});
// 对data进行监视
observe(data, this);
// 创建一个用来编译模板的compile对象
this.$compile = new Compile(options.el || document.body, this)
}
MVVM.prototype = {
$watch: function (key, cb, options) {
new Watcher(this, key, cb);
},
// 对指定属性实现代理
_proxy: function (key) {
// 保存vm
var me = this;
// 给vm添加指定属性名的属性(使用属性描述)
Object.defineProperty(me, key, {
configurable: false, // 不能再重新定义
enumerable: true, // 可以枚举
// 当通过vm.name读取属性值时自动调用
get: function proxyGetter() {
// 读取data中对应属性值返回(实现代理读操作)
return me._data[key];
},
// 当通过vm.name = 'xxx'时自动调用
set: function proxySetter(newVal) {
// 将最新的值保存到data中对应的属性上(实现代理写操作)
me._data[key] = newVal;
}
});
}
};
<