本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
1.学习内容和学习资料:
vue(2.x)源码( 可选 ):
川哥的文章:juejin.cn/post/701092…
2.关键步骤
1.示例工程代码准备
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
<script>
const vm = new Vue({
data: {
name: "我是若川"
},
methods: {
sayName() {
console.log(this.name);
}
}
});
console.log(vm.name);
console.log(vm.sayName());
</script>
</body>
</html>
2.安装http-server
npm i -g http-server
3.启动并调试项目
G:\WorkSpace\vue2-examples>http-server .
3.关键内容记录
3.1 函数调用链条
3.2 重要函数实现
bind函数整合了原生和垫片(腻子)脚本,如果浏览器原生不支持则使用垫片:
function polyfillBind (fn, ctx) {
function boundFn (a) {
var l = arguments.length;
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
boundFn._length = fn.length;
return boundFn
}
function nativeBind (fn, ctx) {
return fn.bind(ctx)
}
var bind = Function.prototype.bind
? nativeBind
: polyfillBind;
垫片脚本使用apply和call来实现了一个bind函数。在caniuse上可以看到浏览器对bind方法的支持程度:
另外发现浏览器对call和apply的支持程度要好于bind:
getData函数内部是调用data函数获取data对象:
function getData (data, vm) {
// #7573 disable dep collection when invoking data getters
pushTarget();
try {
return data.call(vm, vm)
} catch (e) {
handleError(e, vm, "data()");
return {}
} finally {
popTarget();
}
}
proxy函数其实就是用 Object.defineProperty 定义对象,这里用处是:this.xxx 则是访问的 this._data.xxx:
var sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
};
function proxy (target, sourceKey, key) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
};
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val;
};
Object.defineProperty(target, key, sharedPropertyDefinition);
}
4.收获和总结
1.大致了解Vue构造函数流程
2.了解vue可以通过this访问methods和data的原理:
能够访问methods是因为使用bind指定了方法中的this为vue示例(vm), 然后再vue实例上增加了函数名为methods中函数名的键,指向相应的函数:
vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);
通过 this 能够访问到 data 里面的数据是因为data里的属性最终会存储到new Vue的实例(vm)上的 _data对象中,访问 this.xxx,是访问Object.defineProperty代理后的 this._data.xxx。
Object.defineProperty(vm, 'data', sharedPropertyDefinition)