var a = {} 和 a = {}
var a = {} 和 a = {}的返回值不同,前者返回undefined后者返回a本身
所以有以下简写
// 当slots[name]为空的时候,会被赋值为一个新数组,而slot也会被赋值为slots[name]
var slot = (slots[name] || (slots[name] = []));
nextTick一例
<span id='name' ref='name'>{{ name }}</span>
<button @click='change'>change name</button>
methods: {
change() {
this.$nextTick(() => console.log('setter前:' + this.$refs.name.innerHTML))
this.name = ' vue3 '
console.log('同步方式:' + this.$refs.name.innerHTML)
setTimeout(() => this.console("setTimeout方式:" + this.$refs.name.innerHTML))
this.$nextTick(() => console.log('setter后:' + this.$refs.name.innerHTML))
this.$nextTick().then(() => console.log('Promise方式:' + this.$refs.name.innerHTML))
}
}
// 同步方式:vue2
// setter前:vue2
// setter后: vue3
// Promise方式: vue3
// setTimeout方式: vue3
setter前为什么还打印原来的是原来内容呢,是因为 nextTick 在被调用的时候把回调挨个push进callbacks数组,之后执行的时候也是 for 循环出来挨个执行,所以是类似于队列这样一个概念,先入先出;在修改name之后,触发把render watcher填入 schedulerQueue 队列并把他的执行函数 flushSchedulerQueue 传递给 nextTick ,此时callbacks队列中已经有了 setter前函数 了,因为这个 cb 是在 setter前函数 之后被push进callbacks队列的,那么先入先出的执行callbacks中回调的时候先执行 setter前函数,这时并未执行render watcher的 watcher.run,所以打印DOM元素仍然是原来的内容。
读取es6 class上的方法原本
Class.constructor.prototype.xxx
MessageChannel
我们知道:在浏览器环境中,常见的 macro task 有 setTimeout、MessageChannel、postMessage、setImmediate。而常见的 micro task 有 MutationObsever 和 Promise.then。
Vue中对于 macro task 的实现,优先检测是否支持原生 setImmediate,这是一个高版本 IE 和 Edge 才支持的特性,不支持的话再去检测是否支持原生的MessageChannel,如果也不支持的话就会降级为 setTimeout 0;
该api可以实现对含有循环引用和undefined的对象的深拷贝
// 有undefined + 循环引用
let obj = {
a: 1,
b: {
c: 2,
d: 3,
},
f: undefined
}
obj.c = obj.b;
obj.e = obj.a
obj.b.c = obj.c
obj.b.d = obj.b
obj.b.e = obj.b.c
function deepCopy(obj) {
return new Promise((resolve) => {
const {port1, port2} = new MessageChannel();
port2.onmessage = ev => resolve(ev.data);
port1.postMessage(obj);
});
}
deepCopy(obj).then((copy) => { // 请记住`MessageChannel`是异步的这个前提!
let copyObj = copy;
console.log(copyObj, obj)
console.log(copyObj == obj)
});