JavaScript繼承的六種方式
我覺得有些地方我可能理解的不是很到位,如果我下文有出現錯誤直接提出,謝謝~
另外可以看看這兩篇文章:
https://www.cnblogs.com/humin/p/4556820.html
https://www.cnblogs.com/Grace-zyy/p/8206002.html
繼承就是讓子類擁有父類的資源
繼承的意義
減少代碼冗餘
方便統一操作
弊端
耦合性比較強
繼承方法
// 父類
function Person() {
this.name = 'cc';
this.pets = ['aa', 'bb'];
}
Person.prototype.run = function () {
console.log('跑');
};
1. 原型鏈繼承
核心:將父類的實例作爲子類的原型
// 子類
function Student() {
this.num = '111';
}
// 讓新實例的原型等於父類的實例
Student.prototype = new Person();
var stu = new Student();
console.log(stu.num); // 111
stu.run(); // 跑
// 問題:類型問題
console.log(stu.constructor.name); //Person 對象類型改變
優化:修復constructor指針
// 子類
function Student() {
this.num = '111';
}
Student.prototype = new Person();
// 修復constructor指針即可
Student.prototype.constructor = Student;
var stu = new Student();
console.log(stu.num); // 111
stu.run(); // 跑
console.log(stu.pets); // ["aa", "bb"]
console.log(stu.constructor.name); // Student
// 問題:繼承過來的實例屬性, 如果是引用類型, 會被多個子類的實例共享
var stu1 = new Student();
stu.pets.push('dd');
console.log(stu.pets); // ["aa", "bb", "dd"]
console.log(stu1.pets); // ["aa", "bb", "dd"]
2. 借用構造函數繼承
核心:在子類型構造函數的內部調用父類構造函數,通過使用call()和apply()方法可以在新創建的對象上執行構造函數。
// 子類
function Student() {
Person.call(this);
this.num = '111';
}
var stu = new Student();
console.log(stu.name); // 111
// 問題:沒用到原型,只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法
stu.run(); // 報錯:stu.run is not a function
3. 組合繼承
核心: 將原型鏈和借用構造函數的技術組合在一塊,從而發揮兩者之長的一種繼承模式。(常用)
// 子類
function Student() {
Person.call(this);
this.num = '111';
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
var stu = new Student();
var stu1 = new Student();
stu.pets.push('小花');
console.log(stu.pets); // ["aa", "bb", "小花"]
console.log(stu1.pets); // ["aa", "bb"]
// 問題:調用了兩次父類構造函數(耗內存)
4. 原型式繼承
核心:藉助原型,然後基於已有的對象, 創建出新對象;同時不需要創建自定義類型
用一個函數包裝一個對象,然後返回這個函數的調用,這個函數就變成了一個可以隨意增添屬性的實例或對象。object.create()就是這個原理。
// 原型式繼承
function content(obj) {
function Temp() {}
Temp.prototype = obj;
return new Temp();
}
var p = new Person();
var stu1 = content(p);
console.log(stu1.name);
console.log(stu1.age);
5. 寄生式繼承
核心:在原型式基礎上增強這個對象。所謂增加, 就是指, 再次給這個對象增加一些屬性或者方法
// 子類
function Student() {
this.num = '111';
}
function Temp() {}
Temp.prototype = new Person();
Student.prototype = new Temp();
Temp.constructor = Student;
var stu = new Student();
console.log(stu);
6. 寄生式組合繼承
核心:通過借用函數來繼承屬性,通過原型鏈的混成形式來繼承方法。(常用)
// 子類
function Student(num, name, pets) {
Person.call(this, name, pets);
this.num = num;
}
function Temp() {}
Temp.prototype = new Person();
Student.prototype = new Temp();
Temp.constructor = Student;
var stu = new Student('001', '張三', ['小花']);
var stu1 = new Student('002', '李四', ['小茂']);
console.log(stu);
console.log(stu1);