js继承主要有原型链继承和对象冒充继承两种,他们各有优缺点,实际中都是结合两种方式使用
// 父类
function Father (name) {
this.name1 = name;
this.print1 = function () {
alert("print1(): " + this.name1 + " " + this.name2);
};
}
Father.prototype.name2 = "name2";
Father.prototype.print2 = function () {
alert("print2(): " + this.name1 + " " + this.name2);
};
var f1 = new Father("name1");
f1.print1(); // "print1(): name1 name2"
f1.print2(); // "print2(): name1 name2"
var f2 = new Father("new name1");
f2.name2 = "new name2";
f2.print1(); // "print1(): new name1 new name2"
f2.print2(); // "print2(): new name1 new name2"
// 1.单纯的通过原型继承
// 单纯通过原型继承要求父类构造函数应该是无参数的构造函数,否则会造成有些成员不能被初始化
// 在这个例子里,因为父类构造函数有个参数name,所以通过原型继承时,
// 这个参数name没有传递给Father的构造函数,造成this.name成员没有被初始化
// 注意:原型继承可以继承父类通过this.xxx和Father.prototype.xxx定义的所有属性和方法
function Son () {}
Son.prototype = new Father();
var s1 = new Son();
s1.print1(); // "print1(): undefined name2" // 因为this.name成员没有被初始化
s1.print2(); // "print2(): undefined name2"
// 2. 单纯的通过对象冒充继承
// 通过call方式继承
// 单纯通过call方式继承,只能继承父类通过this.xxx定义的所有属性和方法,而父类通过Father.prototype.xxx
// 定义的所有属性和方法都不能被继承
function Son2 (name) {
Father.call(this, name);
//Father.apply(this, new Array(name));
}
var s2 = new Son2("son");
s2.print1(); // "print1(): son undefined" // 父类通过prototype定义的属性不能被继承
s2.print2(); // error // 父类通过prototype定义的方法不能被继承
// 3. 混合原型继承和对象冒充继承
// 原型继承继承了父类通过prototype设置的属性和方法
// 对象冒充继承继承了父类通过this设置的属性和方法
function Son3 (name) {
Father.call(this, name); // 对象冒充。实质上是this指针转移
}
Son3.prototype = new Father(); // 原型继承
var s3 = new Son3("son3");
s3.print1(); // "print1(): son3 name2"
s3.print2(); // "print2(): son3 name2"