JS知识点总结
文章目录
- JS知识点总结
- 一、如何监听数组的改变?
- 二、用setTimeout代替setInterval
- 三、实现Promise.prototype.finally
- 四、什么是伪数组,怎么将伪数组转换为数组
- 1.什么是伪数组
- 2.将伪数组转换为数组的方法
- 1. 解构赋值
- 2. Array.from
- 3.Array.prototype.slice
一、如何监听数组的改变?
利用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)