JS继承
- 1.原型链属性继承(创建父类对象)
子类构造函数.prototype = new 父类构造();
子类构造函数.prototype.constructor =子类构造函数;//修改继承关系的错乱
注释:因为创建对象,用不好可能会造成浪费内存 - 2.原型链直接继承(不创建对象)
子类构造函数.prototype = 父类构造函数.prototype;
子类构造函数.prototype.constructor =子类构造函数;
注释:当父类中的属性和方法都是固定值的时候,才考虑用
优点:不创建对象,节约内存
优点:因为子类和父类共享同一个原型(地址内存),所以子类改变了构造,父类也会跟着改变。 - 3.空对象作为中介继承
var Temp = function(){}
Temp.prototype = 父类构造函数.prototype;
子类构造函数.prototype = new Temp();//这边不会浪费空间,因为他是空对象
子类构造函数.prototype.constructor = 子类构造函数; - 4.构造绑定(call & apply)
父类构造.call(this,参数1,参数2…);
父类构造.apply(this,[参数1,参数2…]);
构造绑定是【伪继承】,只继承其构造函数内的所有属性和方法,不继承所有的原型属性和方法。 - 5组合继承
就是原型继承和构造绑定的同时使用,组成的一种比较好比较全面的继承方式
构造绑定负责继承属性
原型负责绑定方法【分工明确】
写一个具体的案例:
function Phone(brand,type,price){
//(都是手机共同的特征)
//手机品牌
this.brand = brand;
//手机型号
this.type = type;
//手机售价
this.price = price;
}
// 手机共同的功能(拍照、电话、信息)
Phone.prototype.takePhoto = function(){
alert(this.type+"打开拍照功能");
}
Phone.prototype.callNumber = function(){
alert(this.type+"打开拨号功能");
}
Phone.prototype.sendMessage = function(){
alert(this.type+"打开信息功能");
}
jiCheng(HuaWei,Phone);
// 在继承关系的基础之上,扩展新的功能
HuaWei.prototype.superNight = function(){
alert(this.type+"打开了超级夜景模式");
}
function HuaWei(brand,type,price,isFiveG){
// 属性 - 特征的复制
Phone.apply(this,[brand,type,price]);
// 子类里可以写自己独有的属性
this.isFiveG = isFiveG;
}
jiCheng(MI,Phone);
function MI(brand,type,price){
Phone.call(this,brand,type,price);
}
var p30 = new HuaWei("HUAWEI","P30 Pro",5299,true);
p30.superNight();
var v20 = new HuaWei("荣耀","V20",3299,false);
v20.superNight();
var mi9 = new MI("小米","小米9",2999);
mi9.takePhoto();
function jiCheng(child,parent){
child.prototype = new parent();
child.prototype.constructor = child;
}
- 6
拷贝继承
var 父类型原型 = 父类构造.prototype;
var 子类型原型 = 子类构造.prototype;
for(var index in 父类型原型){
子类型原型[index] = 父类型原型[index];
}
总结
1、善于发现所有共同存在的特征和行为,将这些特征和行为全部放在父类构造函数类,方便子类准备继承
2、不可以将不是共同的,某个子类特有的属性放进父类构造
3、继承必须符合面向对象的思想,也是符合生活中的逻辑
举例:构造一个Bird 鸟的函数
鸟的特征(属性) :color wing
鸟的行为:eat sleep fly(?!)
△请注意,不是所有鸟都会飞(企鹅、鸵鸟等),把fly放进父类中,当创建企鹅、鸵鸟等子类时就会出问题,不符合逻辑。因此fly不适合放进父类的方法中。
请在写父类构造时注意这些特殊情况。