function supertype() { this.colors = [red, blue, green]; } function subtype() { //调用supertype 并且通过call()方法修正this指向 supertype.call(this); } var instance1 = new subtype(); instance1.colors.push(black); //red,blue,green,black alert(instance1.colors); //red,blue,green var instance2 = new subtype(); alert(instance2.colors);
以上例子中在subtype()调用了supertype()构造函数。通过使用call()方法(或apply()方法也可以),我们实际上是在(未来将要)新创建的subtype实例的环境下调用了supertype构造函数。这样一来,就会在新subtype对象上执行supertype()函数中定义的所有对象初始化代码。结果,subtype的每个实例就都会具有自己的colors属性的副本了(互不影响)。
使用这种方式继承的好处:可以在子类型构造函数中向超类型构造函数传递参数。如下
function supertype(name) { this.name = name; } function subtype() { //继承了supertype,同时还传递了参数 supertype.call(this, nicholas); //实例属性 this.age = 29; } var instance = new subtype(); //nicholas; alert(instance.name); //29 alert(instance.age);
supertype只接受一个参数name,该参数会直接赋给一个属性。在subtype构造函数内部调用supertype构造函数时,实际上是为subtype的实例设置了name属性。为了确保supertype构造函数不会重写子类型的属性,可以在调用超类型构造函数后,再添加应该在子类型中定义的属性。
使用这种方式继承的坏处:1.方法都在构造函数中定义
2.在超类型的原型中定义的方法,对子类型而言也是不可见的 如下
function supertype(name) { this.name = name; } supertype.prototype.a=function(){ alert(aaaa); } function subtype() { //继承了supertype,同时还传递了参数 supertype.call(this, nicholas); //实例属性 this.age = 29; } var instance = new subtype(); console.log(instance);
我们在控制台可以看到子类型原型中无法获取超类型的a方法
二 组合继承将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式,主要的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。下面来看一个例子
function supertype(name) { this.name = name; this.colors = [red, blue, green]; } supertype.prototype.sayname = function() { alert(this.name); }; function subtype(name, age) { //继承name属性 supertype.call(this, name); this.age = age; } //继承方法 (拼接原型链) subtype.prototype = new supertype(); subtype.prototype.sayage = function() { alert(this.age); }; var instance1 = new subtype(nicholas, 29); instance1.colors.push(black); //red,blue,green,black alert(instance1.colors); //nicholas; instance1.sayname(); //29 instance1.sayage(); var instance2 = new subtype(greg, 27); //red,blue,green alert(instance2.colors); //27; instance2.sayage(); //greg; instance2.sayname();
我们看到现在实例可以访问的超类型的原型上的方法了
supertype构造函数定义了两个属性:name和colors。supertype的原型定义了一个方法sayname()。sub-type构造函数在调用supertype构造函数时传入了name参数,紧接着又定义了它自己的属性age。然后,将supertype的实例赋值给subtype的原型,然后又在该新原型上定义了方法sayage()。这样一来,就可以让两个不同的subtype实例既分别拥有自己属性——包括colors属性,又可以使用相同的方法了这种方式是目前js实现继承使用的最常见的方式
使用这种继承方式的不足subtype.prototype = new supertype()的确会创建一个关联到subtype.prototype 的新对象。但是它使用了subtype(..)的“构造函数调用”,如果函数subtype有一些副作用(比如写日志、修改状态、注册到其他对象、给this添加数据属性,等等)的话,就会影响到subtype()的“后代”。
改进方法function supertype(name) { this.name = name; this.colors = [red, blue, green]; } supertype.prototype.sayname = function() { alert(this.name); }; function subtype(name, age) { //继承name属性 supertype.call(this, name); this.age = age; } //使用object.create 生成对象来代替new supertype()生成的对象 subtype.prototype = object.create(supertype.prototype); subtype.prototype.sayage = function() { alert(this.age); }; var instance1 = new subtype(nicholas, 29); console.log(instance1 );
这样可以避免对subtype后代的影响
注
// es6之前需要抛弃默认的subtype.prototype subtype.ptototype = object.create( supertype.prototype ); // es6开始可以直接修改现有的 subtype.prototypeobject.setprototypeof( subtype.prototype, supertype.prototype );
相关推荐:
js继承 base类的源码解析_js面向对象
javascript高级程序设计 阅读笔记(十四) js继承机制的实现_javascript技巧
js继承--原型链继承和类式继承_基础知识
以上就是细说js继承的详细内容。
