TOC
记录下我在阅读过程,觉得非常有学习的必要,非常好的东西。
操作对象属性的引用 <性能-可读性>
exp
function name(vm) {
let data = vm.$options.data
// 接下来需要读取data 全部从data中读取
这个东西几乎是全程在用,可以说出场率超级高
优点
- 增加性能 减少一次属性的读取 直接操作引用 当然更快啦
- 可读性 接下来的代码你都能少写 vm.\$options
这个习惯其实我也有,忘了从哪里开始偷学的了,实际体验确实非常好。
读取赋值初始化判断套餐 <可读性>
exp
data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
比上面的出场率略低一点,也非常常见,一行代码完成了 取值 赋值 类型判断 重新初始化
优点
- 非常简洁,可读性也很不错
放弃连续声明 <不确定>
exp
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
这个不好说到底是不是优点,从可读性上讲我觉得绝对会有一些优势,但是性能上会比连续声明弱一些。我个人是更加喜欢放弃连续声明的,不知道大家是怎么样的看法。
while 遍历对象 <可读性>
这个东西比较适合不需要明确顺序的遍历一些东西,比如说对象,如果想要从 0 到 length-1 的顺序,那么会多些不少代码,就不太划算了。
exp
let ab = { a: 1, b: 2 }
let keys = Object.keys(ab)
let i = keys.length
while (i--) {
console.log(keys[i])
}
优点
- 其实优点并不是特别的确定 不过确实是一种比较优秀的遍历手段 代码量很少(其实我个人更喜欢用 forEach 遍历对象)
检测声明赋值 V2 <可读性>
适合比上面那种方式更加简单的情况
exp
const installedPlugins = this._installedPlugins || (this._installedPlugins = [])
优点
- 非常高度可读性 减少代码量
高度可读性的变量 <可读性>
Vue 的源码中大量利用了非常高可读性的通用变量。
由于 JS 不支持命名参数,所以很多时候你必须要把参数传完整,但是有些时候又不要传递某个参数,比如在传递回调函数的时候,有些时候你并不需要使用回调。在 Vue 的源码中使用了这样的手段
exp
new Watcher(
vm,
updateComponent,
noop,
{
before() {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate')
}
}
},
true /* isRenderWatcher */
)
这里的 noop 就是传递回调函数,而这个用例并不要回调,所以传递了一个空函数的变量,并且取名为 noop,这样在 Watcher 的构造函数中,就不要写正相反查,直接运行就完事了,并且可读性也很好
除此之外 空对象 等等等 很多东西都可以用这种方式来书写,统一管理,高可读性。
变量重复利用 <性能>
exp
let ancestor = vnode
while (ancestor) {
if (isDef((i = ancestor.context)) && isDef((i = i.$options._scopeId))) {
nodeOps.setStyleScope(vnode.elm, i)
}
ancestor = ancestor.parent
}
这东西其实可以转换为一个比较普通的正相反查,只不过他用了非常巧妙的指向技巧 不断深入判断 最后还把这个 I 给用上了 牛逼啊 这个技巧其实出场率也非常高,把一些本来会废弃的变量重新进行利用,会损失一定的可读性,但是可以获得更强的性能。减少变量的声明。
合理利用公共变量
exp
const activeInstance: any = null
Vue.prototype._update = function(vnode: VNode, hydrating?: boolean) {
const prevActiveInstance = activeInstance
// 这玩意是个全局变量
activeInstance = vm
}
// 接下来其实在整个生命周期 以及子组件的渲染用 都回访问这个当前正在update的变量
这个东西我不知道怎么点评,因为实质上他带给我一些困惑 我找这个变量的起源找了一些时间
快速转 Boolean
exp
needRuntime = !!gen(el, dir, state.warn)
非常好用,几乎没有副作用
帮助函数
exp
export function isUndef(v: any): boolean %checks {
return v === undefined || v === null
}
export function isDef(v: any): boolean %checks {
return v !== undefined && v !== null
}
export function isTrue(v: any): boolean %checks {
return v === true
}
export function isFalse(v: any): boolean %checks {
return v === false
}
更好的代码阅读体验。
不写匿名函数
exp
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})
这个可以帮助 debug 进行堆栈跟踪,而不会是一个莫名其妙的没名字的匿名函数