原型链实现继承的几种模式
来源:互联网 发布:邓肯大学数据 编辑:程序博客网 时间:2024/05/16 17:29
原型链很强大,可以用来实现继承,但也存在一些问题。其中最主要的问题是来自包含引用类型值的原型。看如下例子:
function Super() { this.colors = ['red', 'blue', 'green'];}function Sub() {}Sub.prototype = new Super();var instance1 = new Sub();instance1.colors.push('black');alert(instance1.colors); //red,blue,green,blackvar instance2 = new Sub();alert(instance2.colors); //red,blue,green,black
我们看到Sub()的两个实例,由于Sub.prototype继承了Super(),因此这两个实例实际上是共享了Super的属性和方法,因此colors是Sub所有实例共享的属性,而这并不是我们的意图。
第二个问题是:在创建子类型的实例时,不能向超类型的构造函数中传递函数。
1.来看看第一个方法借用构造函数:
function Super(name) { this.name = name;}function Sub() { Super.call(this, 'Shen'); this.age = 30;}var instance = new Sub();alert(instance.name); //Shenalert(instance.age); //30
在子类中我们用call方法在当前环境下(即Sub下)调用了超类的构造函数,并在子类中添加自己的属性,虽然解决了原型链的问题,但是又有新问题就是:函数不能复用。
2.接下来我们看看最常用的组合继承方法:
思路是:使用原型链实现对原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承,这样既通过了在原型上定义的方法实现了继承,又可以保证每个实例有自己的属性。
function Super(name) { this.name = name; this.colors = ['red', 'blue', 'green'];}Super.prototype.sayName = function() { alert(this.name);};function Sub(name, age) { Super.call(this, name); this.age = age;}//继承方法Sub.prototype = new Super();Sub.prototype.constructor = Sub;Sub.prototype.sayAge = function() { alert(this.age);}var instance1 = new Sub('Shen', 30);instance1.colors.push('black');alert(); //red,blue,green,blackinstance1.sayName(); //sheninstance1.sayAge(); //30var instance2 = new Sub('Han', 22);alert(instance2.colors); //red,blue,greeninstance2.sayName(); //Haninstance2.sayAge(); //22
组合继承了避免了原型链和构造函数的缺陷,是最常用的继承模式。
3.原型式继承
function object(o) { function F() {} F.prototype = o; return new F();}
在object函数内创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时对象的实例。看个例子:
var person = { name: 'Shen', friends: ['Wang', 'Han', 'Li']};var anotherPerson = object(person);anotherPerson.name = 'Han';anotherPerson.friends.push('Row');var otherPerson = object(person);otherPerson.name = 'Col';otherPerson.friends.push('zzz');alert(person.friends); //Wang,Han,Li,Row,zzz
所有object创建的对象都会共享object()方法传入对象的方法和属性,采用这种方法可以不必创建构造函数,而只想让一个对象与另一个对象保持类似的情况下使用,不过引用类型值得属性始终都会共享相应的值,和原型模式一样。
ES5通过新增了Object.create()方法规范了原型式继承。
4.前面说过组合继承是最常用的继承模式,不过它也有自己的不足:无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类原型的时候,一次是在子类构造函数内部。
例如:var instance = new Sub('Jack', 30);
第一次调用Super是Sub.prototype = new Super();
第二是Super.call(this, name);
第二次调用创建的两个实例属性会屏蔽掉第一次调用生成的实例属性。
还好有解决办法,几声组合式继承:不必为子类型的原型而调用超类型的构造函数,我们只是需要超类型的一个副本,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。:
function inheritPrototype(sub, super) { var prototype = object(super.prototype); prototype.constructor = sub; sub.prototype = prototype;}
第一行代码是创建超类型原型的一个副本,第二行代码是为创建的副本添加constructor属性,弥补因重写原型而失去默认的constructor属性。最后一行代码是将副本赋值给子类型的原型。
例如:
function Super(name) { this.name = name; this.colors = ['red', 'blue', 'green'];}Super.prototype.sayName = function() { alert(this.name);};function Sub(name, age) { Super.call(this, name); this.age = age;}inheritPrototype(Sub, Super);Sub.prototype.sayAge = function() { alert(this.age);};
寄生组合式继承只调用一次Super构造函数,并且避免了Sub.prototype上面创建不必要的、多余的属性。普遍认为是引用类型最理想的继承方式。
- 原型链实现继承的几种模式
- 基于原型继承的链模式
- 基于原型链继承的实现
- 【前端Js】原型继承的几种方式
- 原型链的继承
- 几种继承模式的比较
- JavaScript的几种继承模式
- Javascript继承机制的设计思想(原型链模式)
- javascript原型继承(第五篇)---几种继承方式的优缺点
- JS面向对象的几种创建方式:工厂模式、构造函数模式、原型模式、混合模式、动态原型模式
- 重温面向对象的几种模式与原型
- javascript 原型继承(第四篇)---几种继承方式
- 原型模式和基于原型继承的JavaScript对象系统
- javascript原型链简单示例(实现简单的继承)
- JS-实现继承及避免原型链的对象共享
- js原型链的形式实现类继承
- js继承的几种实现方法
- JavaScript继承实现的几种方法
- 2017年7月2日 学习1基本知识理解
- Linux下安装nginx
- Docker镜像保存为文件及从文件导入镜像
- 制作pe
- [51nod]1040 最大公约数之和
- 原型链实现继承的几种模式
- mybatis学习
- grails在gsp页面显示资源图片
- 应聘时最漂亮的回答】网友总结了26个面试问题解答
- Spring Mvc那点事---(19)Spring Mvc过滤器Filter实现登陆验证
- Servlet的实现类
- 亲爱的,人只能活一百年。有些人没活到,那是他们把它折算成福利捐献给了别人。
- 高像素摄像头的最好搭档:1.5A Flash Led Driver SGM3780
- 2016年7月2日学习2 栅格系统