最难的 JavaScript 面试题解析

开发 前端
这道题表面看起来是简单的输出预测,但实际上需要对 JavaScript 的事件循环、this 绑定规则和原型链有全面的理解。通过这类问题的深入分析,不仅可以提升代码阅读能力,也能更自信地处理实际开发中的复杂场景。

觉得自己的 JavaScript 功底还不错?那来试试这道复杂的面试题吧!

下面是一段代码,请分析每一行的输出,并解释其背后的原因。

问题描述

以下是代码,预测输出并说明逻辑:

function Foo() {
  this.value = 42;
}

Foo.prototype.getValue = function() {
  return this.value;
};

const obj1 = new Foo();
const obj2 = {
  value: 24,
  getValue: obj1.getValue
};

console.log(obj1.getValue());      // A
console.log(obj2.getValue());      // B

setTimeout(function() {
  console.log(obj1.getValue());    // C
  obj2.value = 100;
  console.log(obj2.getValue());    // D
}, 0);

Promise.resolve().then(() => {
  obj1.value = 84;
  console.log(obj1.getValue());    // E
});

console.log(obj1.getValue());      // F

分析与输出

A:obj1.getValue()

console.log(obj1.getValue()); // A

解释

  • obj1 是 Foo 的实例,obj1.getValue() 调用的是原型上的 getValue 方法。
  • 方法中的 this 指向 obj1,返回 this.value。
  • obj1.value 初始化为 42,因此输出:

输出:42

B:obj2.getValue()

console.log(obj2.getValue()); // B

解释

  • obj2.getValue 是直接引用了 obj1.getValue,但调用时通过 obj2.getValue()。
  • 在 JavaScript 中,this 的绑定依赖调用的对象。在这里,this 指向 obj2。
  • obj2.value 为 24,因此输出:

输出24

F:同步执行的 obj1.getValue()

console.log(obj1.getValue()); // F

解释

  • 此处仍是 obj1.getValue() 的调用,且 obj1.value 尚未被异步代码修改。
  • 因此输出和 A 一样,为:

输出42

E:Promise 中的 obj1.getValue()

Promise.resolve().then(() => {
  obj1.value = 84;
  console.log(obj1.getValue()); // E
});

解释

  • Promise 的回调是微任务,在同步代码执行完后立即执行。
  • 回调中将 obj1.value 修改为 84,随后调用 obj1.getValue()。
  • 因此此处返回的是更新后的值:

输出84

C:setTimeout 中的 obj1.getValue()

setTimeout(function() {
  console.log(obj1.getValue()); // C
  obj2.value = 100;
  console.log(obj2.getValue()); // D
}, 0);

解释

  • setTimeout 的回调是宏任务,在同步代码和微任务都执行完后才会执行。
  • 此时,obj1.value 已被微任务修改为 84,调用 obj1.getValue() 返回的是修改后的值:

输出84

D:setTimeout 中的 obj2.getValue()

console.log(obj2.getValue()); // D

解释

  • 在 setTimeout 的回调中,obj2.value 被修改为 100。
  • 调用 obj2.getValue(),this 仍指向 obj2,因此返回的是更新后的值:

输出100

完整输出顺序

  • A:42
  • B:24
  • F:42
  • E:84
  • C:84
  • D:100

背后的知识点

这道题涉及了 JavaScript 中多个高级概念,是对语言机制的一次全面考察:

原型继承

  • obj1 调用了 Foo 构造函数,通过原型链继承了 getValue 方法。

动态绑定的 this: 

  • this 的指向取决于函数的调用方式,而不是定义时的上下文。

事件循环与任务队列

  • 同步代码优先执行,Promise 的微任务队列紧随其后,而 setTimeout 的回调则在最后的宏任务队列中执行。

值的动态修改

  • 不同任务(同步、微任务、宏任务)对变量的修改会影响之后的结果。

总结

这道题表面看起来是简单的输出预测,但实际上需要对 JavaScript 的事件循环、this 绑定规则和原型链有全面的理解。通过这类问题的深入分析,不仅可以提升代码阅读能力,也能更自信地处理实际开发中的复杂场景。

责任编辑:姜华 来源: 大迁世界
相关推荐

2019-08-13 08:43:07

JavaScript前端面试题

2018-03-06 15:30:47

Java面试题

2013-01-05 14:51:34

JavaScriptjQuery面试

2024-06-04 14:52:28

2021-01-14 05:12:19

Http协议面试

2021-04-23 14:14:46

设计模式对象

2023-07-28 07:18:39

final继承结构

2022-05-08 19:58:10

JSONPJavaScript

2024-01-01 15:30:59

JavaScriptWeb 应用程序开发

2015-08-27 09:27:34

JavaScript面试题

2024-02-26 15:35:44

2010-11-26 10:31:44

2020-06-04 14:40:40

面试题Vue前端

2014-09-19 11:17:48

面试题

2023-09-04 08:28:34

JavaScripforEach 循环

2023-11-13 07:37:36

JS面试题线程

2011-03-24 13:27:37

SQL

2023-07-05 07:30:44

StringHashMapKey类型

2011-06-07 08:55:25

2021-02-02 06:12:39

JavaScript 前端面试题
点赞
收藏

51CTO技术栈公众号