1.原型链
基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
如果让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应的,另一个原型中也包含着一个指向另一个构造函数的指针,假如另一个原型又是另一个类型的实例,那么按照上述关系,构成了实例与原型的链条,这就是所谓的原型链。------------------基本概念
function sup(){ this.sup1=true; } sup.prototype.getValue=function(){ return this.sup1; } function sub(){ this.sub1=false } sub.prototype=new sup(); //继承了sup sub.prototype.getValue=function () { return this.sub1; } var demo=new sub(); console.log(demo.getValue());//FALSE
根据这个实例
就这样以此类推,所以是原型链,图中很多未注释明白,大致结构就是这样
console.log(demo instanceof Object); console.log(demo instanceof sup); console.log(demo instanceof sub);
结果全是true,可以说,demo是Object sup sub 任何一个类型的实例
注意一点:子类型如果需要覆盖父类的方法,一定要放在替换原型的语句之后。千万不能使用对象字面量创建原型方法,这样就会导致重写原型链,构建对象也是如此。
还是存在老问题:
function sup(){ this.colors=["red"] } function sub(){ } sub.prototype=new sup(); //继承了sup var demo=new sub(); demo.colors.push("yellow"); console.log(demo.colors); var demo2=new sub(); console.log(demo2.colors);
结果:
[ 'red', 'yellow' ]
[ 'red', 'yellow' ]
还存在第二个问题:在创建子类型的实例时,不能向父类的构造函数传递参数。
一般不单独使用。
2.借用构造函数
基本思想:子类的构造函数调用父类的构造函数
function sup(name) { this.name=name; } function sub() { sup.call(this,"222"); this.age=19; } var demo=new sub(); console.log(demo.name); console.log(demo.age);
这次可以传参数了,但是函数不可以复用,所以该方法很少使用。
3.组合继承
结合了上面两个的优点
ps:有种创建对象的感觉
function sup(name) { this.name=name; this.colors=["red"]; } sup.prototype.sayname=function () { console.log(this.name); } function sub(name,age) { sup.call(this,name); this.age=age; } sub.prototype=new sup(); sub.prototype.constructor=sub; sub.prototype.sayAge=function () { console.log(this.age); } var demo=new sub("1",1); demo.colors.push("yellow"); console.log(demo.colors); demo.sayAge(); demo.sayname(); var demo1=new sub("2",2); console.log(demo1.colors); demo1.sayAge(); demo1.sayname();
结果:
[ 'red', 'yellow' ]
1
1
[ 'red' ]
2
2
这种方式是JS最常用的继承模式