Appearance
前端面试题
this 指向问题
- 如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window(非严格模式)。
- 如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
- 如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,**this指向的也只是它上一级的对象。
call 实现
Call 执行过程
- 将函数设为对象的属性
- 执行&删除这个函数
- 指定this到函数并传入给定参数执行函数
- 如果不传入参数,默认指向为 window
// 模拟 call bar.mycall(null);
// 实现一个call方法:
// 原理:利用 context.xxx = self obj.xx = func-->obj.xx()
Function.prototype.myCall = function(context = window, ...args) {
// this-->func context--> obj args--> 传递过来的参数
// 在context上加一个唯一值不影响context上的属性
let key = Symbol('key')
context[key] = this; // context为调用的上下文,this此处为函数,将这个函数作为context的方法
// let args = [...arguments].slice(1) //第一个参数为obj所以删除,伪数组转为数组
let result = context[key](...args);
delete context[key]; // 不删除会导致context属性越来越多
return result;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apply 实现
利用this的上下文特性。
Function.prototype.myApply = function(context = window, ...args) {
// this-->func context--> obj args--> 传递过来的参数
// 在context上加一个唯一值不影响context上的属性
let key = Symbol('key')
context[key] = this; // context为调用的上下文,this此处为函数,将这个函数作为context的方法
// let args = [...arguments].slice(1) //第一个参数为obj所以删除,伪数组转为数组
let result = context[key](args); // 这里和call传参不一样
delete context[key]; // 不删除会导致context属性越来越多
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
// 使用
function f(a,b){
console.log(a,b)
console.log(this.name)
}
let obj={
name:'Obj'
}
f.myApply(obj,[1,2]) //arguments[1]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
bind 实现
防抖
限制一个函数在事件触发的N秒以后再执行,若期间事件再次被触发,则重新计算延迟
// func是用户传入需要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
// 缓存一个定时器id
let timer = 0
// 这里返回的函数是每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个新的定时器,延迟执行用户传入的方法
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
节流
规定在单位时间内只能有一次事件可以真正触发函数的执行,其他触发被丢弃
// func是用户传入需要防抖的函数
// wait是等待时间
const throttle = (func, wait = 50) => {
// 上一次执行该函数的时间
let lastTime = 0
return function(...args) {
// 当前时间
let now = +new Date()
// 将当前时间和上一次执行函数时间对比
// 如果差值大于设置的等待时间就执行函数
if (now - lastTime > wait) {
lastTime = now
func.apply(this, args)
}
}
}
setInterval(
throttle(() => {
console.log(1)
}, 500),
1
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23