优秀博客总结参考
🙅
拉平数组,变成一维的数组,返回一个新数组。
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
flat()
的参数默认为1,表示只会拉平1层。如果要拉平多层则传入参数,表示想要拉平的层数。
var broastEvent = {
// 消息监听队列
clientList: {},
// 订阅(监听)消息
listen: function(observer, action) {
if (clientList[observer]) { // 如果已经存在订阅消息了
this.clientList[observer].push(action) // 新增监听
} else {
this.clientList[observer] = [].concat(action)
}
},
// 发布(触发)消息
trigger: function(observer, ...args) {
const actionList = this.clientList[observer] || []
if (actionList.length > 0) {
actionList.forEach(fn => {
fn(...args)
})
}
},
// 移除消息监听
remove: function(observer) {
this.clientList && delete this.clientList[observer]
}
}
// 测试
broastEvent.listen('some', function (...args) {
console.log('some: ', args, this)
}.bind(this))
broastEvent.listen('some2', (...args) => {
console.log('some2: ', args, this)
})
setTimeout(() => {
broastEvent.trigger('some', 123, 234)
broastEvent.trigger('some2', 123, 234)
broastEvent.remove('some2')
}, 2000)
setTimeout(() => {
broastEvent.trigger('some2', 123, 234)
broastEvent.trigger('some', 123, 234)
}, 5000)
// some: [ 123, 234 ] {}
// some2: [ 123, 234 ] {}
// some: [ 123, 234 ] {}
参考《你不知道的JavaScript(中卷)》第2章28页
引用就像一种特殊的指针,是来指向变量的指针(别名)。如果参数不声明为引用的话,参数值总是通过值复制的方式传递,即便对复杂的对象值也是如此。
JavaScript 中没有指针,引用的工作机制也不尽相同。在 JavaScript 中变量不可能成为指向另一个变量的引用。
JavaScript 引用指向的是值。如果一个值有 10 个引用,这些引用指向的都是同一个值, 它们相互之间没有引用 / 指向关系。
JavaScript 对值和引用的赋值 / 传递在语法上没有区别,完全根据值的类型来决定。
function timeoutify(fn, delay) {
var intv = setTimeout(function() {
intv = null;
fn(new Error("Timeout!"));
}, delay);
return function() {
// 还没有超时
if (intv) {
clearTimeout(intv);
fn.apply(this, arguments);
}
}
}
// 使用promise.race 竞速 promise状态一旦决议就无法改变
function test() {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('test')
resolve('test')
}, 3000)
})
}
function timeoutfn() {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('timeoutfn')
resolve('timeoutfn')
}, 4000)
})
}
Promise.race([
test(),
timeoutfn()
]).then(res => {
console.log('race end')
}).catch(err => {
console.log('race err')
})
防抖的原理:触发事件,但在事件触发 n 秒后才执行,如果在一个事件触发的 n 秒内又触发了这个事件,那就以新的事件时间为准,n 秒后才执行。总之,就是要等触发完事件 n 秒内不再触发事件,才执行。
应用场景:input
输入
function debounce(func, wait, immediate) {
var timeout = null, result;
return function() {
var context = this; // 修改this指向,避免指向window
var args = argumenets; // 传参
if (timeout) clearTimeout(timeout); // 等触发完事件n秒后执行
if (immediate) { // 立即执行第一次 immediate判断是否立即执行
// 如果已经执行过,不再执行
var callNow = !timeout; // !null = true !12 = false
timeout = setTimeout(function() {
func.apply(context, args)
}, wait)
if (callNow) { // 第一次执行
result = func.apply(context, args)
}
} else {
timeout = setTimeout(function() {
func.apply(context, args)
}, wait)
}
return result; // 只有立即执行模式才能返回结果
}
}
节流的原理是:固定时间间隔执行函数
应用场景:resize
、scroll
function throttle(func, wait) {
var timeout, context, args;
var previous = 0;
var later = function() {
previous = +new Date();
timeout = null;
func.apply(context, args)
};
var throttled = function() {
var now = +new Date();
//下次触发 func 剩余的时间
var remaining = wait - (now - previous);
context = this;
args = arguments;
// 如果没有剩余的时间了或者你改了系统时间
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(context, args);
} else if (!timeout) {
timeout = setTimeout(later, remaining);
}
};
return throttled;
}
function throttle2(func, wait) {
var timeout = null;
var previous = 0;
return function() {
var args = arguments;
var context = this;
var now = +new Date();
var remainning = wait - (now - previous); // 等待时间减去两次触发事件的时间差
timeout && clearTimeout(timeout)
if (remainning <= 0) { // 两次触发时间差大于等待时间,立马执行
func.apply(context, args)
previous = now // 更新时间
} else { // 小于等待时间,等待一段时间后执行
timeout = setTimeout(function () {
func.apply(context, args)
provious = +new Date()
}, remainning) // 修改设置timeout时间
}
}
}
我们可以看到:鼠标移入,事件立刻执行,晃了 3s,事件再一次执行,当数字变成 3 的时候,也就是 6s 后,我们立刻移出鼠标,停止触发事件,9s 的时候,依然会再执行一次事件。