1、apply();
function Student(name, age, grade) {
Person.apply(this, arguments); // 用apply調用Person,this(Student)代替Person的this,達到繼承Person的對象和方法的目的
this.grade = grade;
}
function Person(name, age) {
this.name = name;
this.age = age;
this.type = 'person';
}
var student = new Student("zhangsan", 21, "一年級");
console.log('student:', student.type) // student: person
缺點:
1、拿不到父類中prototype中的對方和方法,無論是在調用apply()之前還是之後
2、父類中公有的對象/方法都通過this傳遞,每new一個實例都需要儲存this的內容,耗費內存
測試如下:
function Student(name, age, grade) {
Person.prototype.sex = 'male';
Person.apply(this, arguments); // 用apply調用Person,this(Student)代替Person的this,達到繼承Person的所有對象和方法的目的
this.grade = grade;
}
function Person(name, age) {
this.name = name;
this.age = age;
this.type = 'person';
}
Person.prototype.race= 'han';
var student = new Student("zhangsan", 21, "一年級");
console.log('student:', student.type) // student: person
console.log('student sex:', student.sex) // student sex: undefined
console.log('student race:', student.race) // student race: undefined
2、 利用空對象作爲中介
function Student(name, age, grade) {
this.grade = grade;
}
function Person(name, age) {
this.name = name;
this.age = age;
}
function extend(Child, Parent) {
var F = function() {}; // 空對象,幾乎不佔內存。
F.prototype = Parent.prototype; // 空對象的prototype對象指向Parent的prototype,相當於獲取了Parent的prototype
Child.prototype = new F(); // Child的prototype對象指向空對象的prototype,間接獲取Parent的prototype
Child.prototype.constructor = Child; // 沒有這句會造成繼承鏈的紊亂,手動把構造器指回給Child
Child.uber = Parent.prototype; // 爲子對象設一個uber屬性,這個屬性直接指向父對象的prototype屬性。這等於在子對象上打開一條通道,可以直接調用父對象的方法。這一行放在這裏,只是爲了實現繼承的完備性,純屬備用性質。
}
Person.prototype.type = 'person';
extend(Student, Person);
var student = new Student("zhangsan", 21, "一年級");
console.log('student type:', student.type); // student type: person
公有的內容只能通過prototype傳遞,優勢就是會少new很多this的構造函數,比較節省內存。最大的優勢是,子類的prototype發生變化時,不影響父類的prototype。
測試如下:
function Student(name, age, grade) {
this.grade = grade;
}
function Person(name, age) {
this.name = name;
this.age = age;
}
function extend(Child, Parent) {
var F = function() {}; // 空對象,幾乎不佔內存。
F.prototype = Parent.prototype; // 空對象的prototype對象指向Parent的prototype,相當於獲取了Parent的prototype
Child.prototype = new F(); // Child的prototype對象指向空對象的prototype,間接獲取Parent的prototype
Child.prototype.constructor = Child; // 沒有這句會造成繼承鏈的紊亂,手動把構造器指回給Child
Child.uber = Parent.prototype; // 爲子對象設一個uber屬性,這個屬性直接指向父對象的prototype屬性。這等於在子對象上打開一條通道,可以直接調用父對象的方法。這一行放在這裏,只是爲了實現繼承的完備性,純屬備用性質。
}
Person.prototype.type = 'person';
extend(Student, Person);
Student.prototype.subType = 'student';
var student = new Student("zhangsan", 21, "一年級");
console.log('student type:', student.type); // student type: person
console.log('student subType:', student.subType); // student subType: student
console.log('Person.prototype:', Person.prototype); // Person.prototype: {type: "person", constructor: ƒ}
3、 拷貝繼承
function Student(name, age, grade) {
this.grade = grade;
}
function Person(name, age) {
this.name = name;
this.age = age;
}
function extend2(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) { // 遍歷拷貝賦值
c[i] = p[i];
}
c.uber = p;
}
Person.prototype.type = 'person';
extend2(Student, Person);
Student.prototype.subType = 'student';
var student = new Student("zhangsan", 21, "一年級");
console.log('student type:', student.type); // student type: person
console.log('student subType:', student.subType); // student subType: student
console.log('Person.prototype:', Person.prototype); // Person.prototype: {type: "person", constructor: ƒ}
參考:添加鏈接描述