最難的 JavaScript 面試題解析

覺得自己的 JavaScript 功底還不錯(cuò)?那來試試這道復(fù)雜的面試題吧!
下面是一段代碼,請(qǐng)分析每一行的輸出,并解釋其背后的原因。
問題描述
以下是代碼,預(yù)測(cè)輸出并說明邏輯:
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 的實(shí)例,obj1.getValue() 調(diào)用的是原型上的 getValue 方法。
 - 方法中的 this 指向 obj1,返回 this.value。
 - obj1.value 初始化為 42,因此輸出:
 
輸出:42
B:obj2.getValue()
console.log(obj2.getValue()); // B解釋:
- obj2.getValue 是直接引用了 obj1.getValue,但調(diào)用時(shí)通過 obj2.getValue()。
 - 在 JavaScript 中,this 的綁定依賴調(diào)用的對(duì)象。在這里,this 指向 obj2。
 - obj2.value 為 24,因此輸出:
 
輸出:24
F:同步執(zhí)行的 obj1.getValue()
console.log(obj1.getValue()); // F解釋:
- 此處仍是 obj1.getValue() 的調(diào)用,且 obj1.value 尚未被異步代碼修改。
 - 因此輸出和 A 一樣,為:
 
輸出:42
E:Promise 中的 obj1.getValue()
Promise.resolve().then(() => {
  obj1.value = 84;
  console.log(obj1.getValue()); // E
});解釋:
- Promise 的回調(diào)是微任務(wù),在同步代碼執(zhí)行完后立即執(zhí)行。
 - 回調(diào)中將 obj1.value 修改為 84,隨后調(diào)用 obj1.getValue()。
 - 因此此處返回的是更新后的值:
 
輸出:84
C:setTimeout 中的 obj1.getValue()
setTimeout(function() {
  console.log(obj1.getValue()); // C
  obj2.value = 100;
  console.log(obj2.getValue()); // D
}, 0);解釋:
- setTimeout 的回調(diào)是宏任務(wù),在同步代碼和微任務(wù)都執(zhí)行完后才會(huì)執(zhí)行。
 - 此時(shí),obj1.value 已被微任務(wù)修改為 84,調(diào)用 obj1.getValue() 返回的是修改后的值:
 
輸出:84
D:setTimeout 中的 obj2.getValue()
console.log(obj2.getValue()); // D解釋:
- 在 setTimeout 的回調(diào)中,obj2.value 被修改為 100。
 - 調(diào)用 obj2.getValue(),this 仍指向 obj2,因此返回的是更新后的值:
 
輸出:100
完整輸出順序
- A:42
 - B:24
 - F:42
 - E:84
 - C:84
 - D:100
 
背后的知識(shí)點(diǎn)
這道題涉及了 JavaScript 中多個(gè)高級(jí)概念,是對(duì)語言機(jī)制的一次全面考察:
原型繼承:
- obj1 調(diào)用了 Foo 構(gòu)造函數(shù),通過原型鏈繼承了 getValue 方法。
 
動(dòng)態(tài)綁定的 this:
- this 的指向取決于函數(shù)的調(diào)用方式,而不是定義時(shí)的上下文。
 
事件循環(huán)與任務(wù)隊(duì)列:
- 同步代碼優(yōu)先執(zhí)行,Promise 的微任務(wù)隊(duì)列緊隨其后,而 setTimeout 的回調(diào)則在最后的宏任務(wù)隊(duì)列中執(zhí)行。
 
值的動(dòng)態(tài)修改:
- 不同任務(wù)(同步、微任務(wù)、宏任務(wù))對(duì)變量的修改會(huì)影響之后的結(jié)果。
 
總結(jié)
這道題表面看起來是簡(jiǎn)單的輸出預(yù)測(cè),但實(shí)際上需要對(duì) JavaScript 的事件循環(huán)、this 綁定規(guī)則和原型鏈有全面的理解。通過這類問題的深入分析,不僅可以提升代碼閱讀能力,也能更自信地處理實(shí)際開發(fā)中的復(fù)雜場(chǎng)景。















 
 
 











 
 
 
 