interview
advanced-javascript-frontend
如何实现 callapply 及 bind 函数

前端 JavaScript 进阶面试题, 如何实现 call,apply 及 bind 函数?

前端 JavaScript 进阶面试题, 如何实现 call,apply 及 bind 函数?

QA

Step 1

Q:: 如何实现 call 函数?

A:: 要实现自定义的 call 函数,可以在 Function.prototype 上定义一个方法。实现的关键是将函数的 this 指向第一个参数,并通过 apply 调用函数,代码如下:

 
Function.prototype.myCall = function (context, ...args) {
  context = context || window;
  const fn = Symbol();
  context[fn] = this;
  const result = context[fn](...args);
  delete context[fn];
  return result;
};
 

Step 2

Q:: 如何实现 apply 函数?

A:: 实现 apply 函数与 call 类似,唯一的区别是参数形式从展开参数变为数组。代码如下:

 
Function.prototype.myApply = function (context, args) {
  context = context || window;
  const fn = Symbol();
  context[fn] = this;
  const result = context[fn](...args);
  delete context[fn];
  return result;
};
 

Step 3

Q:: 如何实现 bind 函数?

A:: 实现 bind 函数稍微复杂一些,因为它需要返回一个新的函数,同时保留原函数的上下文和参数。代码如下:

 
Function.prototype.myBind = function (context, ...args) {
  const fn = this;
  return function (...newArgs) {
    return fn.apply(context, [...args, ...newArgs]);
  };
};
 

用途

实现 call、apply 和 bind 函数的能力对于理解 JavaScript 中的 this 关键字和函数上下文非常重要。在实际生产环境中,开发者需要处理复杂的回调和事件处理,这时需要准确控制函数的上下文。尤其在面向对象编程和函数式编程中,这些函数的应用频率较高。通过面试考察这些内容,可以评估候选人对 JavaScript 核心机制的理解程度,以及他们解决实际问题的能力。\n

相关问题

🦆
什么是 JavaScript 中的闭包?

闭包是指在一个函数内部定义的函数可以访问其外部函数的变量。闭包使得外部函数的变量在其生命周期结束后依然能够被访问。代码示例如下:

 
function outerFunction() {
  let outerVariable = 'I am outside!';
  function innerFunction() {
    console.log(outerVariable);
  }
  return innerFunction;
}
const myFunction = outerFunction();
myFunction(); // I am outside!
 
🦆
JavaScript 中的原型链是什么?

JavaScript 中的原型链是实现继承的一种机制。每个对象都有一个内部链接指向另一个对象,这个对象称为原型。原型对象也有自己的原型,形成一个链条,直到一个对象的原型为 null 结束。这种机制允许一个对象从另一个对象继承属性和方法。代码示例如下:

 
function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  console.log('Hello, my name is ' + this.name);
};
const alice = new Person('Alice');
alice.sayHello(); // Hello, my name is Alice
 
🦆
解释 JavaScript 中的事件循环机制?

事件循环是 JavaScript 处理异步编程的一种机制。JavaScript 是单线程的,事件循环允许它在一个线程上处理多个任务。任务分为同步任务和异步任务,异步任务通过事件队列处理。事件循环不断地检查调用栈是否为空,如果为空,就从事件队列中取出一个事件并将其放入调用栈执行。代码示例如下:

 
console.log('Start');
setTimeout(() => {
  console.log('Timeout');
}, 0);
console.log('End');
// 输出顺序:Start, End, Timeout