- CSS技巧與案例詳解
- vue2與vue3技巧合集
- VueUse原始碼解讀
覺得自己的 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
繫結規則和原型鏈有全面的理解。透過這類問題的深入分析,不僅可以提升程式碼閱讀能力,也能更自信地處理實際開發中的複雜場景。
首發於公眾號 大遷世界,歡迎關注。📝 每週一篇實用的前端文章 🛠️ 分享值得關注的開發工具 ❓ 有疑問?我來回答
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。