继承方式主要有六种:
1、原型链继承 存在对象共享的问题
2、构造函数继承 借助call apply方法实现 :函数复用性问题 每次实例化,都重新执行了一次父类,父类中的方法重复定义
3、组合模式(原型链+构造函数)构造函数继承属性,原型链继承方法 :解决了对象共享,但是属性继承出现两次
4、原型方式 使用一个空间空函数
5、寄生方式 在原型方式上增加额外了方法
6、寄生组合方式(解决了属性继承出现2次的问题)
1、原型链方式
子类在继承父类时,是将子类的prototype指向父类的一个实例对象。 在子类实例化时,所有子类的实例都会共享父类的那个实例上(假设叫p)的属性和方法,如果p上有引用型的属性,则子类的实例可以修改该引用型的属性,导致其他实例上的该属性也被修改。
//原型链方式function A(){ this.name = 'lc'; this.stus = ['a','b','c'];}A.prototype.introduce = function (){ alert(this.name);}function B(){}B.prototype = new A();var s1 = new B();var s2 = new B();console.log(s1.stus); //['a','b','c'] s1.stus.push('d'); //改变s1上的属性,会影响s2上的该属性console.log(s2.stus); // ['a','b','c','d']
如果改成下面的,则不会影响。
//原型链方式function A(){ this.name = 'lc'; this.stus = ['a','b','c'];}A.prototype.introduce = function (){ alert(this.name);}function B(){}B.prototype = new A();var s1 = new B();var s2 = new B();s1.stus = ['d']; //在s1上增加了属性, 就近原则,不在查找原型链上的同名属性console.log(s1.stus); //['d']console.log(s2.stus); // ['a','b','c']
2、构造函数方式继承
共用构造函数,方法都是在内部定义,复函复用性问题无从谈起。
//构造函数方式继承function A(name){ this.name = name; this.type = 'parent'; this.introduce = function (){ alert(this.name);}}A.prototype.sayhi = function (){ alert(this.type);}function B(name,age){ A.call(this,name); //使用call方法 实现继承 但是父类中的方法重复定义 无复用性 this.age = age; this.introduce = function (){ alert(this.name+this.age);}}var b = new B('lc',25);b.introduce(); //lc25b.sayhi(); //parent
3、混合方式 (原型方式+构造函数方式)
使用构造函数继承属性,原型链继承方法
但是有一点不好的地方: 使用原型链继承时,实际上属性也继承了,重复了。
function A(name){ this.name = name; this.type = 'parent';}A.prototype.sayhi = function (){ alert(this.type);}function B(name,age){ A.call(this,name); this.age = age; this.introduce = function (){ alert(this.name+this.age);}}B.prototype = new A();
4、原型式继承
使用了一个中间空函数,实现继承后,返回一个对象。
function extend(parent){ function F(){} F.prototype = parent; return new F();}
5、寄生式继承 在原型式的基础上,再为对象添加属性 方法
function extend(parent){ function F(){} F.prototype = parent; return new F();}function createObj(p){ var clone = extend(p); clone.name = 'hello'; clone.say = function (){} return clone;}
6、寄生组合式继承
在继承方法的时候,不再实例化父类型的构造函数,而是使用inheritPrototype方法. 使用一个中间空函数,让这个空函数去继承父类原型,然后实例化这个空函数(继承了父类prototype中的所有方法)。将子类的原型指向这个实例化的空对象即可。
避免了实例化父类的构造函数。
/* 寄生组合式继承 */function inheritPrototype(subType, superType) { // var obj= extend(superType.prototype); function F(){} F.prototype = superType.prototype; var obj= new F(); //obj.constructor = subType; subType.prototype = obj; //不可将subType的prototype直接指向superType,否则的话,对子类prototype的修改会反应到父类上, 引用型变量 subType.prototype.constructor = subType;
}
对象冒充: 使用构造函数的方式声明类,将一个类的方法指向另一个构造函数(因为构造函数本身就是一个方法函数),实现继承
function A(){ this.name = {name1:'hello'}; this.say = function (){ console.log(this.name);}}function B(){ this.method = A; this.method(); delete this.method; } var bObj = new B();