JS知识点总结
文章目录
一、如何监听数组的改变?
利用Proxy可以来监听数组的length属性,当push或者pop的时候,会触发setter:
const proxyArr = new Proxy(unkownArr, {
set(target, prop, value, receiver) {
if (prop === 'length') {
console.log('set new value', value);
return false;
}
console.log('receiver', receiver);
return Reflect.set(...arguments);
}
});
那要监听数组某一项的变化呢?那就是prop !== 'length'的情况了:
const proxyArr = new Proxy(unkownArr, {
set(target, prop, value, receiver) {
if (prop !== 'length') {
console.log('set new value', value);
return false;
}
console.log('receiver', receiver);
return Reflect.set(...arguments);
}
});
二、用setTimeout代替setInterval
首先,为什么要用setTimeout代替setInterval呢?如果单单从事件循环的原因来看的话,这两者不都会因为JS主线程执行的原因造成一定的延迟吗?但是,思考一下setInterval的作用你会发现,setInterval的作用主要是按照一定的间隔时间把任务放进宏队列中。但是如果JS引擎线程执行时间过长,会导致JS定时器线程将setInterval多个任务在JS从宏队列中取任务前放入到宏队列中去,这就会导致JS引擎在执行的时候,这些任务就没有了原来应该有的时间间隔!
因此,我们利用setTimeout在当前任务进入队列后去手动触发下一个定时器,实现setInterval:
function myInterval(fn, time) {
// 定义一个函数,内部开启定时器,调用自己
let timer = null;
const intervalFn = () => {
fn();
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(intervalFn, time);
};
timer = setTimeout(intervalFn, time);
return timer;
}
今天面试碰到这样一个场景题:点击一个按钮,触发轮询(1s1次),每次请求一个接口,将接口返回的值作为新状态更新。若返回状态为finished则停止轮询。
这里涉及到定时器相关的问题为,要给定时器增加一个可以手动关闭的参数,不能直接传一个boolean值给myInterval,这样没有办法再外部进行控制,故传一个引用值对象进去即可:
function myInterval(fn, time, isFinished) {
// 定义一个函数,内部开启定时器,调用自己
let timer = null;
const intervalFn = () => {
fn();
if (timer) {
clearTimeout(timer);
}
// 用来控制停止计时器
if (!isFinished.done) {
timer = setTimeout(intervalFn, time);
}
};
timer = setTimeout(intervalFn, time);
}
const isFinished = {
done: false
};
const timer = myInterval(() => {
console.log('myInterval');
}, 200, isFinished);
setTimeout(() => {
isFinished.done = true;
}, 3000);
三、实现Promise.prototype.finally
finally的作用是在.then和.catch之后调用,执行必须要执行的代码,.finally中没有传入参数。如果在.then和.catch之前调用.finally,不会影响后面的.then和.catch。这说明finally内部拦截了(通过调用this.then)前面promise的value或reason,把value或reason传给下一个promise。
Promise.prototype.finally = function(callback) {
// 获得前面的promise或者拦截前面的promise
return this.then(
// finally前面是成功,就执行成功的回调,并把前面的参数向下传递
value => {
// 嵌套一层Promise.resolve保证向下传递
return Promise.resolve(callback()).then(() => value)
},
reason => {
return Promise.resolve(callback()).then(() => { throw reason })
}
)
}
四、什么是伪数组,怎么将伪数组转换为数组
1.什么是伪数组
常见的,function里面的arguments,和document.querySelectorAll()获取的元素数组是伪数组。从定义上说:
- 伪数组是一个对象
- 支持按索引获值
- 拥有
length属性 - 支持数组遍历
- 没有
Array相关的方法
function arrayLike() {
console.log('arguments', arguments); // [Arguments] { '0': 1, '1': 2, '2': 'c' }
console.log(arguments.__proto__ === Object.prototype); // true
}
arrayLike(1, 2, 'c');
2.将伪数组转换为数组的方法
1. 解构赋值
[...arguments]
2. Array.from
Array.from(arguments)
3.Array.prototype.slice
Array.prototype.slice.call(arguments)
2955

被折叠的 条评论
为什么被折叠?



