| 方法 | 用途 | 示例 |
| hasOwnProperty(prop) | 判斷自身屬性 (非繼承) | arr.hasOwnProperty('push') // false |
| constructor | 獲取構造函數 | a1.constructor === Aaa // true |
| instanceof | 檢測原型鏈關係 | [] instanceof Array // true |
| Object.prototype.toString.call() | 精確類型判斷 | Object.prototype.toString.call([]) === '[object Array]' |
iframe 跨域類型判斷:前兩種失效,唯有 Object.prototype.toString.call() 可靠
四、三大繼承模式深度對比
1. 原型鏈繼承
function Super() { this.colors = ['red','blue']; }
Super.prototype.getColors = function() { return this.colors; };
function Sub() {}
Sub.prototype = new Super(); // 關鍵:子原型指向父實例
Sub.prototype.constructor = Sub; // 修正 constructor
const s1 = new Sub(), s2 = new Sub();
s1.colors.push('green');
console.log(s2.colors); // ['red','blue','green'] - 引用類型共享問題!
缺點:引用類型屬性被所有實例共享;無法向父構造函數傳參
2. 構造函數繼承 (借用 call/apply)
function Super(name) { this.name = name; this.colors = ['red']; }
function Sub(name, age) {
Super.call(this, name); // 在子實例上執行父構造函數
this.age = age;
}
const s1 = new Sub('Tom', 20), s2 = new Sub('Jerry', 18);
console.log(s1.colors, s2.colors); // 各自獨立 ['red'] ['red']
缺點:方法定義在構造函數內,無法復用;父原型方法不可見
3. 組合繼承 (經典模式) - 推薦
function Super(name) { this.name = name; this.colors = ['red','blue']; }
Super.prototype.sayName = function() { console.log(this.name); };
function Sub(name, age) {
Super.call(this, name); // 繼承實例屬性 (解決共享問題)
this.age = age;
}
Sub.prototype = new Super(); // 繼承原型方法
Sub.prototype.constructor = Sub; // 修正 constructor
Sub.prototype.sayAge = function() { console.log(this.age); };
const s1 = new Sub('Tom', 20), s2 = new Sub('Jerry', 18);
s1.colors.push('green');
console.log(s1.colors); // ['red','blue','green']
console.log(s2.colors); // ['red','blue'] - 獨立!
s1.sayName(); s1.sayAge(); // 方法復用正常
4. 拷貝繼承 (jQuery extend 風格)
function extend(target, source) {
for (let key in source) target[key] = source[key];
}
function Person(name) { this.name = name; }
Person.prototype.sayHi = function() { console.log(this.name); };
function Star(name, job) {
Person.call(this, name);
this.job = job;
}
extend(Star.prototype, Person.prototype); // 方法拷貝
Star.prototype.showJob = function() { console.log(this.job); };
五、實戰案例:可拖拽組件與邊界限制繼承
基類:基礎拖拽邏輯
function Drag(id) {
this.obj = document.getElementById(id);
this.disX = this.disY = 0;
}
Drag.prototype.init = function() {
const self = this;
this.obj.onmousedown = function(e) {
e = e || window.event;
self.fnDown(e);
document.onmousemove = function(e) { self.fnMove(e || window.event); };
document.onmouseup = self.fnUp;
return false; // 防止選中文字
};
};
Drag.prototype.fnDown = function(e) {
this.disX = e.clientX - this.obj.offsetLeft;
this.disY = e.clientY - this.obj.offsetTop;
};
Drag.prototype.fnMove = function(e) {
this.obj.style.left = e.clientX - this.disX + 'px';
this.obj.style.top = e.clientY - this.disY + 'px';
};
Drag.prototype.fnUp = function() {
document.onmousemove = document.onmouseup = null;
};
子類:限制邊界內拖拽
function BoundDrag(id) {
Drag.call(this, id); // 繼承屬性
}
extend(BoundDrag.prototype, Drag.prototype); // 繼承方法
BoundDrag.prototype.fnMove = function(e) {
let left = e.clientX - this.disX;
let top = e.clientY - this.disY;
const maxLeft = document.documentElement.clientWidth - this.obj.offsetWidth;
const maxTop = document.documentElement.clientHeight - this.obj.offsetHeight;
left = Math.max(0, Math.min(left, maxLeft));
top = Math.max(0, Math.min(top, maxTop));
this.obj.style.left = left + 'px';
this.obj.style.top = top + 'px';
};
// 使用
window.onload = function() {
new Drag('div1').init(); // 自由拖拽
new BoundDrag('div2').init(); // 邊界限制拖拽
};
配套 HTML/CSS
<style>
#div1, #div2 { width:100px; height:100px; position:absolute; }
#div1 { background:red; }
#div2 { background:blue; left:100px; }
</style>
<div id="div1"></div>
<div id="div2"></div>
六、原型繼承最佳實踐總結
- 組合繼承:實例屬性用
call,原型方法用原型鏈,最通用
- 寄生組合繼承:
Sub.prototype = Object.create(Super.prototype) 避免兩次調用父構造函數 (最優)
- ES6 class:
extends/super 只是語法糖,底層仍是原型機制
- 避免修改內置原型:污染全局,改用組合/裝飾模式
- 慎用 \_\_proto\_\_:非標準,現代用
Object.getPrototypeOf/Object.setPrototypeOf

JavaScript 面向對象的核心在於理解原型鏈委托機制。掌握各種繼承模式的優劣、原型屬性共享陷阱、constructor 修正、類型精準判斷,能寫出靈活復用、結構清晰的組件化代碼。
- 上一篇文章: ES5 規範核心增強:Object 靜態方法全解析與安全編程實踐
- 下一篇文章: Java Web 核心知識體系總結:從 OSI 七層模型到會話管理
Copyright ©
程式碼之家 All Rights Reserved