代碼對比
// (1) 原型指向實例
function A() { this.display = function() { alert("A display"); } }
function B() { this.show = function() { alert("B show"); } }
A.prototype = new B(); // B 的實例作為 A 的原型
var a = new A();
a.display(); // "A display"
a.show(); // "B show" ✓ 繼承自 B 實例
// (2) 原型指向函數
function _A() { this.display = function() { alert("_A display"); } }
var _B = function() { this.show = function() { alert("_B show"); } }
_A.prototype.show = _B; // 直接賦值函數
var _a = new _A();
_a.display(); // "_A display"
_a.show(); // 不彈窗 ✗
核心差異
| 方式 | 原型鏈結構 | 結果 |
(1) A.prototype = new B() | a → A.prototype (B實例) → B.prototype → Object.prototype | show 存在於 B 實例上,可訪問 |
(2) _A.prototype.show = _B | _a → _A.prototype → Object.prototype | show 是函數 而非實例方法,調用 _a.show() 時 this 指向 _a,但 _B 內部 this.show 未被調用,故無輸出 |
本質解釋
new B() 創建一個對象,其屬性 show 是函數,成為原型鏈上的一環,a.show() 正常委託調用。
_A.prototype.show = _B 將構造函數 _B 直接作為屬性值賦給原型。調用 _a.show() 實際執行的是 _B.call(_a),但 _B 內部定義的是 this.show = ...,並未返回或調用該函數,故無副作用。
正確模仿 (1) 的寫法
_A.prototype.show = function() { alert("_B show"); }; // 直接賦值函數表達式
// 或
_A.prototype.show = (new _B()).show; // 賦值 _B 實例的 show 方法