为了解决包含引用类型值的原型属性会被所有实例共享的问题,大神们发明了在子类型构造函数的内部调用超类型构造函数然后通过apply()和call()方法在(将来)新创建的对象上执行构造函数的方式来实现继承,如下
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);//29alert(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);
登录后复制
二 组合继承
将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式,主要的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。下面来看一个例子
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();//29instance1.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 );
登录后复制
// ES6之前需要抛弃默认的SubType.prototypeSubType.ptototype = Object.create( SuperType.prototype );// ES6开始可以直接修改现有的SubType.prototypeObject.setPrototypeOf( SubType.prototype, SuperType.prototype );
登录后复制
相关推荐:
js继承 Base类的源码解析_js面向对象
JavaScript高级程序设计 阅读笔记(十四) js继承机制的实现_javascript技巧
JS继承–原型链继承和类式继承_基础知识
以上就是细说js继承的详细内容,更多请关注【创想鸟】其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。
发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2789113.html