面试题之手写call,apply,bind
在面试中,手写call,apply,bind是常见的题目,主要考察对JavaScript中函数上下文(this)和参数传递的理解。对于我这个小菜鸟来说,这无疑也是一道难题呢,嘤嘤嘤
1. 手写 call
call
方法允许你调用一个函数,并显式地指定函数内部的 this
值,同时可以逐个传递参数。
实现思路:
-
将目标函数绑定到指定的上下文对象(
thisArg
)。 -
调用目标函数。
-
返回目标函数的执行结果。
代码实现:
Function.prototype.myCall=function(thisArg,...args){
if(typeof this!=='function'){
//如果调用者不是一个函数,则抛出错误
throw new TypeError("myCall must be called on a function");
}thisArg = thisArg||(thisArg===null?globalThis:thisArg)
thisArg['fn']=this
thisArg['fn'](...args)// 这里相当于立即执行函数
delete thisArg['fn']}
测试:
function greet(...message){
console.log(`${message},my name is ${this.name}`)
}const person = {name:'alita'}
greet.myCall(person,'hello','hi','嘻嘻')//hello,hi,嘻嘻,my name is alita
2. 手写 apply
apply
方法与 call
类似,但参数是以数组的形式传递的。
实现思路:
-
将目标函数绑定到指定的上下文对象(
thisArg
)。 -
调用目标函数。
-
返回目标函数的执行结果。
代码实现:
Function.prototype.myApply = function (thisArg, argsArray) {
// 检查是否为函数
if (typeof this !== "function") {
throw new TypeError("myApply must be called on a function");
}// 如果 thisArg 是 null 或 undefined,按照规范,this 应该指向全局对象
thisArg = thisArg || (thisArg === null ? globalThis : Object(thisArg));// 将函数绑定到 thisArg 上
const fn = Symbol("fn");
thisArg[fn] = this;// 调用函数并获取结果
const result = thisArg[fn](...argsArray);// 删除临时属性
delete thisArg[fn];return result;
};
测试:
function greet(message) {
console.log(`${message}, my name is ${this.name}`);
}const person = { name: "Alice" };
greet.myApply(person, ["Hello"]); // 输出: Hello, my name is Alice
3. 手写 bind
bind
方法用于创建一个新的函数,并将该函数的 this
值永久绑定到指定的对象上。与 call
和 apply
不同,bind
不会立即调用函数,而是返回一个新的函数。
实现思路:
-
创建一个新的函数。
-
将目标函数的
this
值绑定到指定对象。 -
支持预绑定参数。
-
支持作为构造函数使用(可选)。
代码实现:
Function.prototype.myBind = function (thisArg, ...bindArgs) {
// 检查是否为函数
if (typeof this !== "function") {
throw new TypeError("myBind must be called on a function");
}const fn = this;
// 返回一个新的函数
const boundFunction = function (...callArgs) {
// 合并预绑定参数和调用时的参数
const finalArgs = bindArgs.concat(callArgs);// 如果作为构造函数调用,this 指向新创建的对象
if (new.target) {
return new fn(...finalArgs);
} else {
// 否则,this 指向绑定的对象
return fn.apply(thisArg, finalArgs);
}
};// 修复绑定函数的原型链
boundFunction.prototype = Object.create(fn.prototype);return boundFunction;
};
测试:
function greet(message) {
console.log(`${message}, my name is ${this.name}`);
}const person = { name: "Alice" };
const greetAlice = greet.myBind(person, "Hello");
greetAlice(); // 输出: Hello, my name is Alice// 测试作为构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}const createPerson = Person.myBind(null, "Alice");
const alice = new createPerson(25);
console.log(alice); // { name: "Alice", age: 25 }
总结
-
call
和apply
:-
都用于立即调用函数并改变上下文。
-
区别在于参数传递方式:
call
是逐个传递,apply
是数组传递。 -
实现时,主要通过临时属性绑定和调用目标函数。
-
-
bind
:-
返回一个新的函数,
this
值和参数被预绑定。 -
支持延迟调用和作为构造函数使用。
-
实现时需要处理
new
调用的情况,并修复原型链。
-
这些实现可以帮助你更好地理解 JavaScript 中的函数上下文和参数传递机制。