【js基础】javascript中几种常见的继承方式。
2017-07-28 21:08
676 查看
如果只采用原型链来继承,会有诸多问题?
如下:
首先分析原型链组成:
instance1. _ proto _ ——-》subType.prototype (subType的原型对象);
subType.prototype. _ proto _ ——-》 supType.prototype(supType的原型对象);
supType.prototype. _ proto _ ——–》Object.prototype(Object的原型对象);
对象实例instance2和instance1的原型链一致。
所以再执行instance1.colors.push(“black”);是通过原型链找到subType的原型对象,subtype.prototype对象在创建时,包含了一个colors属性,所以再在subtype.prototype对象的colors属性里加入元素”black”。这就修改了subType原型对象中color属性的内容。
当执行alert(instance2.color),沿着原型链找到subType.prototype 对象,发现colors属性,输出和alert(instance1.colors);一样。
所以通过某一个对象实例对原型链中的属性的修改,会影响全部的队象实例。注意:
对象实例的属性重写不会影响原型链上的原型对象属性的值。
比如:
对象实例属性定义和原型链上的某对象属性一致时,会屏蔽,但不会沿着原型链找到该属性,重写该属性值。
由上面分析可知,单一用原型链继承,容易通过对原型链上的某个属性修改,从而影响全部对象实例的初始化。
这种继承消除了上面原型链那种弊端。
分析过程不难发现,其实这种模式,主要是利用call 和 this 的组合应用的技巧。*当执行var instance1=new subType();语句时,可以理解为:先分配一块内存,变量instance1指向这一块内存,然后再调用subType构造函数,在调用过程中,subType构造函数中this的指向和新创建的对象实例instance1的指向一样,在执行构造函数subType里面的superType.call(this);语句时,由上分析,这里面的this值就是instance1保存的值,然后利用call的特性,让其调用函数中this的值和call方法里面的参数的值一样。所以,又让构造函数supType里面this的指向和call(this)中的this指向一样。简而言之,var instance1=new subType();superType.call(this);this.colors=[“red”,”blue”,”green”];中的instance1,两个this,他们三个指向同一块内存,三个值相等。
所以在执行instance1.color.push(“black”);条语句时,colors属性时直接在instance1对象实例中找到的,不是在原型链某处找到的。所以在push一个”black”时,是直接加到instance1对象实例中的。对原型链中任何一个属性没用影响。
过程分析:对象实例mei1,mei2指向不同,假设mei1的执向foo1,mei2指向foo2,但foo1.prototype==foo2.prototype,即alert(mei1.prototype===mei2.prototype);//true
其实,原型式模式和创建对象时构造函数模式+原型模式的组合基本一致呀。相比组合继承,原型式继承更简单一点。
原型继承的优点就是根据现有的一个对象,可以快速迭代出别的相似对象。不必要再创建设计别的构造函数来创建新对象。
es5中提供的原型函数的API Object.create()来规范原型式继承。
哎!es5还没学到,es6早已经出来了。呜呜呜……
路漫漫其修远兮 吾将上下而求索。
如下:
方式一:原型链继承
function supType(){ this.colors=["red","blue","green"]; } function subType(){} subType.prototype=new supType(); var instance1=new subType(); instance1.colors.push("black"); alert(instance1.colors); var instance2=new subType(); alert(instance2.colors);
首先分析原型链组成:
instance1. _ proto _ ——-》subType.prototype (subType的原型对象);
subType.prototype. _ proto _ ——-》 supType.prototype(supType的原型对象);
supType.prototype. _ proto _ ——–》Object.prototype(Object的原型对象);
对象实例instance2和instance1的原型链一致。
所以再执行instance1.colors.push(“black”);是通过原型链找到subType的原型对象,subtype.prototype对象在创建时,包含了一个colors属性,所以再在subtype.prototype对象的colors属性里加入元素”black”。这就修改了subType原型对象中color属性的内容。
当执行alert(instance2.color),沿着原型链找到subType.prototype 对象,发现colors属性,输出和alert(instance1.colors);一样。
所以通过某一个对象实例对原型链中的属性的修改,会影响全部的队象实例。注意:
对象实例的属性重写不会影响原型链上的原型对象属性的值。
比如:
function supType(){ this.say=function(){ alert("可乐味溜溜梅最好吃"); }; } supType.prototype.name="溜溜梅"; function subType(){} subType.prototype=new supType(); var mei1=new subType(); mei1.name="情人梅"; alert(mei1.name);//情人梅 mei1.say();//可乐味溜溜梅最好吃 var mei2=new subType(); alert(mei2.name);//溜溜梅 delete mei1.name; alert(mei1.name);//溜溜梅
对象实例属性定义和原型链上的某对象属性一致时,会屏蔽,但不会沿着原型链找到该属性,重写该属性值。
由上面分析可知,单一用原型链继承,容易通过对原型链上的某个属性修改,从而影响全部对象实例的初始化。
方式二:借用构造函数
function superType(){ this.colors=["red","blue","green"]; } function subType(){ superType.call(this); } var instance1=new subType(); instance1.colors.push("black"); alert(instance1.colors);//red,blue,green,black var instance2=new subType(); alert(instance2.colors);//red,blue,green
这种继承消除了上面原型链那种弊端。
分析过程不难发现,其实这种模式,主要是利用call 和 this 的组合应用的技巧。*当执行var instance1=new subType();语句时,可以理解为:先分配一块内存,变量instance1指向这一块内存,然后再调用subType构造函数,在调用过程中,subType构造函数中this的指向和新创建的对象实例instance1的指向一样,在执行构造函数subType里面的superType.call(this);语句时,由上分析,这里面的this值就是instance1保存的值,然后利用call的特性,让其调用函数中this的值和call方法里面的参数的值一样。所以,又让构造函数supType里面this的指向和call(this)中的this指向一样。简而言之,var instance1=new subType();superType.call(this);this.colors=[“red”,”blue”,”green”];中的instance1,两个this,他们三个指向同一块内存,三个值相等。
所以在执行instance1.color.push(“black”);条语句时,colors属性时直接在instance1对象实例中找到的,不是在原型链某处找到的。所以在push一个”black”时,是直接加到instance1对象实例中的。对原型链中任何一个属性没用影响。
方式三:原型链+借用构造函数(组合继承)
这种继承方式使用的最多的。既吸收了原型链的公共属性继承优势,减少了代码的重复性,又吸收了借用构造函数的修改属性值互不影响的长处,提高了代码的灵活性。function supType(){ this.kinds=["溜溜梅","蓝莓","情人梅","杨梅"]; } function subType(){ supType.call(this);//借用构造函数实现继承 } subType.prototype=new supType();//原型链实现继承 subType.prototype.say=function(){ alert("蓝莓很好吃"); }; var mei1=new subType(); mei1.kinds.pop(); alert(mei1.kinds);//溜溜梅,蓝莓,情人梅 mei1.say();//蓝莓很好吃 var mei2=new subType(); alert(mei2.kinds);//溜溜梅,蓝莓,情人梅,杨梅 mei2.say();//蓝莓很好吃 aler(mei1.say===mei2.say);//true
方式四:原型式继承
直接看代码,都是原型链分析function object(o){ function F(){}; F.prototype=o; return new F(); } var Plum={ names:["溜溜梅","蓝莓","情人梅","杨梅"], kinds:4 }; var mei1=object(Plum); mei1.price=35; mei1.names.push("话梅"); mei1.kinds+=1; alert(mei1.names);//溜溜梅,蓝莓,情人梅,杨梅,话梅 alert(mei1.kinds);//5 var mei2=object(Plum); alert(mei2.price);//undefined alert(mei2.names);//溜溜梅,蓝莓,情人梅,杨梅,话梅 alert(mei2.kinds);//4 alert(mei1.prototype===mei2.prototype);//true
过程分析:对象实例mei1,mei2指向不同,假设mei1的执向foo1,mei2指向foo2,但foo1.prototype==foo2.prototype,即alert(mei1.prototype===mei2.prototype);//true
其实,原型式模式和创建对象时构造函数模式+原型模式的组合基本一致呀。相比组合继承,原型式继承更简单一点。
原型继承的优点就是根据现有的一个对象,可以快速迭代出别的相似对象。不必要再创建设计别的构造函数来创建新对象。
es5中提供的原型函数的API Object.create()来规范原型式继承。
var Plum={ names:["溜溜梅","蓝莓","情人梅","杨梅"], kinds:4 }; var mei1=Object.create(Plum); mei1.names.push("话梅"); mei1.kinds+=1; alert(mei1.names);//溜溜梅,蓝莓,情人梅,杨梅,话梅 alert(mei1.kinds);//5 var mei2=Object.create(Plum); alert(mei2.names);//溜溜梅,蓝莓,情人梅,杨梅,话梅 alert(mei2.kinds);//4
哎!es5还没学到,es6早已经出来了。呜呜呜……
路漫漫其修远兮 吾将上下而求索。
相关文章推荐
- js-JavaScript常见的创建对象的几种方式
- javascript(js)创建对象的模式与继承的几种方式
- js实现继承的几种方式
- js 中继承的几种方式
- JavaScript中实现继承的几种方式的使用和分析
- 演示OOP中的封装、继承在JavaScript中的书写方式(另附JS反射的例子)
- js中的几种继承方式
- JavaScript学习12 JS中定义对象的几种方式
- javascript中的几种继承方式
- JS实现继承的几种方式
- js继承的几种方式
- Javascript中的几种继承方式比较
- js的几种继承方式
- js继承的几种方式
- javascript实现继承的几种方式
- 矩阵理论基础知识(2)--常见的几种矩阵分解方式
- JavaScript学习12 JS中定义对象的几种方式
- 【 js 基础 】Javascript “继承”
- JS实现继承的几种方式
- js对象继承的实现的几种方式