繼承
構(gòu)造函數(shù) 原型對(duì)象 對(duì)象實(shí)例 三者之間的關(guān)系
- 每個(gè)構(gòu)造函數(shù)都擁有一個(gè)原型對(duì)象,
構(gòu)造函數(shù).prototype --- 原型對(duì)象 - 原型對(duì)象都有一個(gè)指向構(gòu)造函數(shù)的指針茸歧,
原型對(duì)象.constructor --- 構(gòu)造函數(shù) - 實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針
實(shí)例.proto --- 原型對(duì)象 - 每個(gè)實(shí)例是構(gòu)造函數(shù) new 出來(lái)
new 構(gòu)造函數(shù) --- 實(shí)例 // 構(gòu)造函數(shù) new 創(chuàng)建
1. 原型繼承
將父類(lèi)的實(shí)例直接賦值給子類(lèi)的原型對(duì)象 prototype
子類(lèi)的原型對(duì)象被重寫(xiě)捺疼,父級(jí)的所有屬性和方法也存在于子類(lèi)的原型對(duì)象prototype
代碼演示
// 父類(lèi)
function Person() {
this.name = 'zs';
this.age = 13;
}
// 子類(lèi)
function Student() {
this.gender = '男';
}
//父類(lèi)的實(shí)例賦值給子類(lèi)的原型對(duì)象
Student.prototype = new Person(); // 這里改constructor 指向 Person
// 改變constructor
Student.prototype.constructor = Student; // constructo指向Student
let s1 = new Student();
console.log(s1.name,s1.age,s1.gender) // zs 13 男
console.dir(Student)
原型繼承bug
- 原型繼承時(shí)將父類(lèi)的實(shí)例賦值給子類(lèi)总珠,子類(lèi)的原型會(huì)變成父類(lèi)的實(shí)例蚤假,要通過(guò)
Student.prototype.constructor = Student
來(lái)將Person的constructor改為Student的constructor - 不可以向父類(lèi)的構(gòu)造函數(shù)傳參
2. 借用構(gòu)造函數(shù)(解決傳參問(wèn)題)
使用 call() 方法改變 this 的指向趴腋,實(shí)現(xiàn)屬性繼承
在子類(lèi)中調(diào)用父類(lèi)并用call()方法將 this 指向子類(lèi)
代碼演示
// 父類(lèi)
function Person(name,age) {
this.name = name;
this.age = age;
this.sayHi = function(){
console.log('大家好吊说,我+this.name)
}
}
Person.prototype.test = function(){
console.log('今年'+this.age)
}
// 子類(lèi)
function Student(name,age,gender) {
// 通過(guò)call()方法將 this 指向由 Person 改為 Student
// Student 繼承 Person 的屬性和定義在函數(shù)內(nèi)部的方法
Person.call(this,name,age);
this.gender = gender;
}
let s1 = new Student('zs',14,'男');
console.log(s1) // Student {name: "zs", age: 14, sayHi: ?, gender: "男"}
s1.sayHi(); // 大家好,我是zs
// Person 原型對(duì)象上的方法不能被 Student 訪問(wèn)
s1.test(); // 1.html:130 Uncaught TypeError: s1.test is not a function
借用構(gòu)造函數(shù)bug
- 子類(lèi)只能繼承函數(shù)內(nèi)部的屬性和方法优炬,原型對(duì)象上的方法不能被繼承
- 為了避免方法的重復(fù)定義疏叨,將方法定義在原型上;但這樣不能繼承穿剖,要想繼承蚤蔓,就定義在構(gòu)造函數(shù)內(nèi)部
3. 復(fù)合繼承(實(shí)現(xiàn)屬性和方法的繼承)
- 復(fù)合繼承 : 原型繼承(繼承方法) + 借用構(gòu)造函數(shù)繼承(繼承屬性)
- 將父級(jí)的方法定義在原型對(duì)象上,通過(guò)原型繼承糊余,讓子類(lèi)擁有父類(lèi)的方法
- 將父級(jí)的屬性定義在構(gòu)造函數(shù)內(nèi)部秀又,通過(guò)call()方法单寂,讓子類(lèi)擁有父類(lèi)的屬性
代碼演示
// 父類(lèi)
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function () {
console.log('大家好,我是' + this.name)
}
}
Person.prototype.test = function () {
console.log('今年' + this.age)
}
// 子類(lèi)
function Student(name, age, gender) {
Person.call(this, name, age); // 繼承屬性
this.gender = gender;
}
// 父類(lèi)的實(shí)例賦值給子類(lèi)的原型對(duì)象
Student.prototype = new Person(); // 繼承方法
Student.prototype.constructor = Student;
let s1 = new Student('Tom', 18, 100)
console.log(s1) // Student {name: "Tom", age: 18, sayHi: ?, gender: 100}
s1.sayHi() // 大家好吐辙,我是Tom
s1.test() // 今年18