函数 | call apply bind区别(含手写)

call apply bind都可用于修改this的指向

call

语法

1
function.call(thisArg, arg1, arg2, ...)

参数

  • thisArg:在function函数运行时使用的this值,在非严格模式下,如果指定为null或者undefinedthiswindow
  • arg1 arg2 arg3:指定的参数列表

返回值

使用thisArg和参数调用该函数的返回值,若该方法没有返回值,则返回undefined

apply

语法

1
function.apply(thisArg, argsArray)

参数

  • thisArg:在function函数运行时使用的this值,在非严格模式下,如果指定为null或者undefinedthiswindow
  • argsArray:一个数组或者是类数组对象,其中数组元素将作为单独的参数传给function函数,如果该参数的值为null或者undefined,则表示不需要传入任何参数

返回值

使用thisArg和参数调用该函数的返回值,若该方法没有返回值,则返回undefined

bind

语法

1
function.bind(thisArg, arg1, arg2, ...)

参数

  • thisArg:在function函数运行时使用的this值,在非严格模式下,如果指定为null或者undefinedthiswindow
  • arg1 arg2 arg3:指定的参数列表

返回值

返回一个绑定了指定的this值和初始函数的原函数的拷贝

三者区别

  • callapply: 传入形式不同,call第二个参数开始都是function所需要的参数,而apply则把function所需的参数以数组的形式作为第二个参数传入

  • call applybind:call 和 apply 是立即执行,而bind的方法是创建一个新的函数,这个函数是原函数的拷贝

手写实现

手写call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Function.prototype.myCall = function(context,...args) {   // ...rest: ...剩余参数数组名称
// 1. 判断传入context是否为空
context = context ? context : window;
// 2. 给context指定一个方法,指向this
context.fn = this;
// 3. 执行fn
let res = context.fn(...args);
// 4. 执行完毕后删除自定义的方法
delete context.fn;
// 5. 返回调用函数的返回值
return res;
}


// test
const person = {
name: 'Kate',
sayName: function(p1, p2, p3) {
console.log(`Hello, ${this.name}, they are my friends, ${p1}, ${p2}, ${p3}.`)
},
};
const person2 = {
name: 'Katrina',
};
person.sayName.myCall(person2, 'Jack', 'Jenny', 'John'); // Hello, Katrina, they are my friends, Jack, Jenny, John.

手写apply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Function.prototype.myApply = function(context, args=[]) {
// 1. 判断传入context是否为空
context = context ? context : window;
// 2. 给context指定一个方法,指向this
context.fn = this;
// 3. 执行fn
let res = context.fn(...args);
// 4. 执行完毕后删除自定义的方法
delete context.fn;
// 5. 返回调用函数的返回值
return res;
}

// test
const person = {
name: 'Kate',
sayName: function(p1, p2, p3) {
console.log(`Hello, ${this.name}, they are my friends, ${p1}, ${p2}, ${p3}.`)
},
};
const person2 = {
name: 'Katrina',
};
person.sayName.myApply(person2, ['Jack', 'Jenny', 'John']); // Hello, Katrina, they are my friends, Jack, Jenny, John.

手写bind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Function.prototype.myBind = function(context, ...args) {
// 1. 判断传入context是否为空
context = context ? context : window;
// 2. 保存this
const self = this;

// 3. 返回函数
return function(...newArgs) {
// 4. 柯里化函数
return self.myApply(context, [...args, ...newArgs]);
}
}


// test
const person = {
name: 'Kate',
sayName: function(p1, p2, p3) {
console.log(`Hello, ${this.name}, they are my friends, ${p1}, ${p2}, ${p3}.`)
},
};
const person2 = {
name: 'Katrina',
};

const res = person.sayName.myBind(person2)('Jack', 'Jenny', 'John'); // Hello, Katrina, they are my friends, Jack, Jenny, John.