Js中的继承
2016-04-28 10:16
597 查看
参考自:[]http://jingyan.baidu.com/article/cd4c2979f2f664756e6e600b.html]
例子:
通过原型链,ClassA的所有属性和方法传递给了ClassB,用prototype的确是方便很多。
注意的是调用ClassA的构造函数是,没有给它传递参数,这是在原型链中的标准做法。要确保构造函数没有任何参数。如果构造函数中有参数的话会怎样呢?那样便不能完全的继承,只能继承父类通过prototype初始的属性和方法,在构造函数中初始的属性和方法便不会继承。
与对象冒充相似,子类的所有属性和方法都必须出现在prototype属性被赋值之后,因为在它之前赋值的所有方法都会被删除。为什么呢?因为prototype属性被替换成了新的对象,原始对象的prototype属性以不复存在了
例子:
ClassB执行ClassA方法便相当于继承了ClassA,在调用完毕后要删除newMethod,因为后续添加的属性和方法如果和超类同名,就会覆盖超类的相关属性和方法。
利用这种继承方式可以实现多重继承,例如:
利用这种多重继承方法有个弊端,如果ClassA和ClassB具有相同的属性和方法,ClassB有较高的优先级。
call方法还是调用了ClassA()方法,利用this传递进去ClassB,为ClassB初始化,他仅仅是调用了ClassA()方法而已,如果你在ClassA之外为ClassA添加了方法(例如利用原型法),是不能继承到ClassB的。call()方法的第一个参数必须是this,可以有第二个,第三个,第四个….参数。
apply()方法与call()方法不同的是,将二个,第三个,第四个….参数用一个数组传递。例如:
可以将arguments作为参数传递给apply,但是ClassB的参数顺序必须和ClassA一致。
另外,Function.apply()在提升程序性能方面有着突出的作用:
我们先从Math.max()函数说起,Math.max后面可以接任意个参数,最后返回所有参数中的最大值。
在此例子中,继承机制有两行突出显示的代码实现。在第一行中,在ClassB的构造函数中,用对象冒充继承ClassA类的sColor属性。在第二行,用原型链继承ClassA类的方法。由于这种混合方式使用了原型链,所以instanceof运算符仍能正确运行。
原型链继承
利用prototype实现继承,prototype对象是个模板,要实例的对象都是以这个模板为基础,它的任何属性和方法都被传递给那个类的所有实例,原型链利用这种功能来实现继承机制。例子:
function ClassA(){} ClassA.prototype.color="red"; ClassA.prototype.sayColor=function(){ alert(this.color); } function ClassB(){} ClassB.prototype=newClassA();
通过原型链,ClassA的所有属性和方法传递给了ClassB,用prototype的确是方便很多。
注意的是调用ClassA的构造函数是,没有给它传递参数,这是在原型链中的标准做法。要确保构造函数没有任何参数。如果构造函数中有参数的话会怎样呢?那样便不能完全的继承,只能继承父类通过prototype初始的属性和方法,在构造函数中初始的属性和方法便不会继承。
与对象冒充相似,子类的所有属性和方法都必须出现在prototype属性被赋值之后,因为在它之前赋值的所有方法都会被删除。为什么呢?因为prototype属性被替换成了新的对象,原始对象的prototype属性以不复存在了
对象冒充(构造函数继承)
感觉这种方式利用了js中类和函数的模糊性,同是function关键字申明方法,既可以说他是函数,也可以说他是类,js太灵活了例子:
function ClassA(sColor){ this.color=sColor; this.sayColor=function(){ alert(this.color); } } function ClassB(sColor){ this.newMethod=ClassA;//把ClassA方法赋给newMethod. this.newMethod();//调用newMethod. delete this.newMethod; }
ClassB执行ClassA方法便相当于继承了ClassA,在调用完毕后要删除newMethod,因为后续添加的属性和方法如果和超类同名,就会覆盖超类的相关属性和方法。
利用这种继承方式可以实现多重继承,例如:
function ClassD(sColor){ this.newMethod=ClassA;//把ClassA方法赋给newMethod, this.newMethod();//调用newMethod delete this.newMethod; this.newMethod=ClassB; this.newMethod(); delete this.newMethod;}
利用这种多重继承方法有个弊端,如果ClassA和ClassB具有相同的属性和方法,ClassB有较高的优先级。
call方法和apply方法
ECMAScript在function对象加入两个新方法,call()和apply(),这两中方法很相似,只有在传参方面有所不同,call()方法的第一个参数用作this的对象,例如:function ClassB(sColor,sName){ ClassA.call(this,sColor); this.name=sName; this.sayName=function(){ alert(this.name); } }
call方法还是调用了ClassA()方法,利用this传递进去ClassB,为ClassB初始化,他仅仅是调用了ClassA()方法而已,如果你在ClassA之外为ClassA添加了方法(例如利用原型法),是不能继承到ClassB的。call()方法的第一个参数必须是this,可以有第二个,第三个,第四个….参数。
apply()方法与call()方法不同的是,将二个,第三个,第四个….参数用一个数组传递。例如:
function ClassB(sColor,sName,sSex){ var arr=new Arry(sColor,sName,sSex); ClassA.apply(this,arr);//传递数组 this.name=sName; this.sayName=function(){ alert(this.name); } }
可以将arguments作为参数传递给apply,但是ClassB的参数顺序必须和ClassA一致。
另外,Function.apply()在提升程序性能方面有着突出的作用:
我们先从Math.max()函数说起,Math.max后面可以接任意个参数,最后返回所有参数中的最大值。
alert(Math.max(5,7,9,3,1,6)); //9 //但是在很多情况下,我们需要找出数组中最大的元素。 var arr=[5,7,9,1]; //alert(Math.max(arr)); // 这样却是不行的。NaN //要这样写 function getMax(arr){ var arrLen=arr.length; for(var i=0,ret=arr[0];i<arrLen;i++){ ret=Math.max(ret,arr[i]); } return ret; } alert(getM 4000 ax(arr)); //9 //换用apply,可以这样写 function getMax2(arr){ return Math.max.apply(null,arr); } alert(getMax2(arr)); //9 //两段代码达到了同样的目的,但是getMax2却优雅,高效,简洁得多。
//再比如数组的push方法。 var arr1=[1,3,4]; var arr2=[3,4,5]; //如果我们要把 arr2展开,然后一个一个追加到arr1中去,最后让arr1=[1,3,4,3,4,5] //arr1.push(arr2)显然是不行的。 因为这样做会得到[1,3,4,[3,4,5]] //我们只能用一个循环去一个一个的push(当然也可以用arr1.concat(arr2),但是concat方法并不改变arr1本身) var arrLen=arr2.length; for(var i=0;i<arrLen;i++){ arr1.push(arr2[i]); } //自从有了Apply,事情就变得如此简单 Array.prototype.push.apply(arr1,arr2); //现在arr1就是想要的结果
混合方式
这种继承方式使用构造函数定义类,并未使用任何原型,对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参的构造函数了。开发者该如何选择呢?答案很简单,两者都使用。创建类的最好方式是用构造函数方式定义属性,用原型方式定义方法。这种方式同样适用于继承机制,用对象冒充继承函数的属性,用原型链继承prototype对象的方法,用这两种方式重写前面的例子,代码如下:function ClassA(sColor){ this.color=sColor; } ClassA.prototype.sayColor=function(){ alert(this.color); }; function ClassB(sColor,sName){ callA.call(this,sColor); this.name=sName; ClassB.prototype=new ClassA(); ClassB.prototype.sayName=function(){ alert(this.name); };
在此例子中,继承机制有两行突出显示的代码实现。在第一行中,在ClassB的构造函数中,用对象冒充继承ClassA类的sColor属性。在第二行,用原型链继承ClassA类的方法。由于这种混合方式使用了原型链,所以instanceof运算符仍能正确运行。
相关文章推荐
- PostgreSQL教程(三):表的继承和分区表详解
- Lua面向对象之类和继承浅析
- 浅析Ruby中继承和消息的相关知识
- 设计引导--一个鸭子游戏引发的设计理念(多态,继承,抽象,接口,策略者模式)
- C++实现不能被继承的类实例分析
- C# 面向对象三大特性:封装、继承、多态
- PHP类的封装与继承详解
- js继承 Base类的源码解析
- Javascript 面向对象 继承
- JavaScript 继承使用分析
- Javascript面向对象编程(二) 构造函数的继承
- Javascript中的几种继承方式对比分析
- javascript面向对象之Javascript 继承
- JavaScript 对象、函数和继承
- 详述JavaScript实现继承的几种方式(推荐)
- javascript 继承学习心得总结
- 学习javascript面向对象 javascript实现继承的方式
- 关于JavaScript的面向对象和继承有利新手学习
- JavaScript 继承详解(一)
- JavaScript 继承详解(二)