本文为加入源码共读小组后,跟着往期的学习资料(初学者也能看懂的 Vue3 源码中那些实用的基础工具函数)对vue-next 库里的packages/shared/src/index.ts的源码进行学习的过程记录和开发经验总结。
- 克隆仓库
依照若川老师的文章,分别克隆了 vue-next仓库和vue-next-analysis仓库
备注:本人node版本为 v14.15.4
之前开发一直用的npm,按照文章提示,全局安装了yarn,并使用yarn进行代码在线调试。
clone地址:
https://zhuanlan.zhihu.com/p/431976529 https://zhuanlan.zhihu.com/p/431975088 https://zhuanlan.zhihu.com/p/431974045 https://zhuanlan.zhihu.com/p/432085648 https://zhuanlan.zhihu.com/p/432815187 https://zhuanlan.zhihu.com/p/432819345 https://zhuanlan.zhihu.com/p/432820117 https://zhuanlan.zhihu.com/p/432821356 https://zhuanlan.zhihu.com/p/432822391 https://zhuanlan.zhihu.com/p/432955990
git clone https://github.com/lxchuan12/vue-next-analysis.git
cd vue-next-analysis/vue-next
git clone https://github.com/vuejs/vue-next.git
cd vue-next
复制代码
- 调试源码
在项目根目录下,执行yarn build,先把ts文件编辑成js文件,便于查看和调试。 编译完成后,在examples文件下新建 test.js文件。本人是直接通过vscode的code Runner插件进行块代码的即时调试的。如果需要在浏览器看效果,可以在/examples/index.html的文件里直接编写js脚本,然后启用服务yarn serve ,在浏览器里输入服务器地址即可。
- 源码调试
*所有的工具函数都来自packages\shared\dist\shared.cjs.js
我只抽取了部分工具函数进行验证
3.1 Object.freeze
复制代码
EMPTY_OBJ_2.props.name = '若川';
EMPTY_OBJ_2.props2 = 'props2';
console.log(EMPTY_OBJ_2.props.name); // '若川'
console.log(EMPTY_OBJ_2.props2); // undefined
console.log(EMPTY_OBJ_2); // { props: { mp: '若川视野', name: '若川' } }
const EMPTY_ARR = Object.freeze([]) ;
// EMPTY_ARR.push(1); // 报错
// EMPTY_ARR = [1,2,3]; // 报错,提示是常量
console.log(EMPTY_ARR); // []
// 利用Object的冻结方法,使对象或者数组变成不可编辑的常量,避免被误赋值
// 在vue2中也可以使用这个方法让vue编译时减少对一些常量对象自动设置响应,压缩编译后的代码
复制代码
3.2 NOOP = () => { }
复制代码
const NOOP = () => { };
const instance = {
render: NOOP
};
console.log('object :>> ', instance.render);
const dev = true;
if(dev){
instance.render = function(){
console.log('render');
}
}
// 可以用作判断
if (instance.render === NOOP){
console.log('i'); // dev = false
} else {
console.log('f'); // dev = true
}
// 项目中使用箭头函数,可以在编译时更多地压缩代码
// 利用指向同一个空函数对象,可以进行空函数的判断,但是需要先对要判断的属性默认赋值NOOP,然后就可以判断该属性是否有重新赋值新的函数
复制代码
3.3 isObject vs isPlainObject
复制代码
const isObject = (val) => val !== null && typeof val === 'object';
console.log(isObject(null)); // false
console.log(isObject({name: '1111'})); // true
console.log(isObject([])); // true
console.log(isObject(() => {})); // false
const objectToString = Object.prototype.toString;
const toTypeString = (value) => objectToString.call(value);
const isPlainObject = (val) => toTypeString(val) === '[object Object]';
console.log(isPlainObject(null)); // false
console.log(isPlainObject({name: '1111'})); // true
console.log(isPlainObject([])); // false
console.log(isPlainObject(() => {})); // false
// 通过上面的输出结果,可以看到两者都能判断对象类型,但是前者会把数组也当作Object对象,后面才能更纯粹地判断出真实业务中的Object
复制代码
3.4 hasChanged
复制代码
const hasChangedNew = (value, oldValue) => !Object.is(value, oldValue);
const hasChangedOld = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue);
let a = {};
const b = a;
const c = {};
console.log(hasChangedOld(NaN, NaN)); // false
console.log(hasChangedOld(1, 1)); // false
console.log(hasChangedOld(1, 2)); // true
console.log(hasChangedOld(+0, -0)); // false
console.log(hasChangedOld(a, b)); // false
console.log(hasChangedOld(a, c)); // true
console.log(hasChangedNew(NaN, NaN)); // false
console.log(hasChangedNew(1, 1)); // false
console.log(hasChangedNew(1, 2)); // true
console.log(hasChangedNew(+0, -0)); // true
console.log(hasChangedNew(a, b)); // false
console.log(hasChangedNew(a, c)); // true
a = { a: '' };
// a.a = '';
console.log(hasChangedOld(a, b)); // true
console.log(hasChangedNew(a, b)); // true
// 这里根据文章说到的源码前后两种封装方式,我这里也同时进行调试对比,从console的结果来看,
// 使用Object.is,能够把+0, -0两个值判断为没有改变过,但是两者对于NaN,都是判断为发生改变。
复制代码
以上几点是本次源码调试试手过程中,我自己觉得对自己启发比较大的工具函数,也让自己对未来在项目中封装通用的方法有了更好的选择。期待接下来在源码的学习过程中学到更多巧妙的开发经验。
?
|