js继承除了原型链继承还有哪些方法

JS继承——原型的应用-JavaScript_网络编程-脚本宝典
页面导航: >
> JS继承——原型的应用
JS继承——原型的应用
前面我们知道JS是基于对象编程的一种脚本语言,在JS本着一切皆对象的原则,对象之间也涉及到了继承,不过这里的继承与我们以往学习过的继承有所不同,它运用的是对象的原型,来
前面我们知道JS是基于对象的一种语言,在JS本着一切皆对象的原则,对象之间也涉及到了继承,不过这里的继承与我们以往学习过的继承有所不同,它运用的是对象的原型,来构造一个原型链来实现对超类对象的继承。
1、如何实现对象继承 function Box() { //Box 构造,超类对象
this.name = 'Lee';
Desk.prototype = new Box(); //子类继承Desk,继承了 Box,通过原型,形成链条
继承原理小结:
1、通过原型链继承:超类型实例化后的对象实例赋给子类对象的原型属性。
2、new Box()会将超类对象构造函数和原型中的信息都交给子类对象,即继承全部信息 。
3、利用instanceof来判断子类是否从属于某个超类。
4、子类继承时,优先选择实例中的属性值(如果出现原型与构造实例冲突时)。
2、继承中的问题
上篇博客中还有一个遗留问题,原型函数共享带来无法重写的问题,那么在继承中,同样因为共享而无法进行重写,同时,子类无法给超类进行传参。对于这个问题,JS中可采用对象冒充来解决。
function Box(age) {
this.name = ['Lee', 'Jack', 'Hello']
this.age =
function Desk(age) {
Box.call(this, age); //对象冒充,给超类型传参
var desk = new Desk(200);
alert(desk.age);对象冒充SWOT分析:
1、实现了子类为超类对象进行传参问题
2、只能冒充构造函数中信息,不能冒充原型中的信息
当然,我们可以将所有信息写进构造函数中,但这样消耗内存空间太大,所以,这里可以采用原型链+构造函数的方式来实现,即组合模式:
function Box(age) {
this.name = ['Lee', 'Jack', 'Hello']
this.age =
Box.prototype.run = function () { //将方法写进原型中
return this.name + this.
function Desk(age) {
Box.call(this, age); //对象冒充,实现传参,第二次调用
Desk.prototype = new Box(); //原型链继承,继承全部信息,第一次调用超类型
var desk = new Desk(100);
alert(desk.run());
同时,还可以利用原型式继承等方法来实现对象传参问题,只需一个中转函数来协助返回一个实例化后的对象即可。
function obj(o) { //传递一个字面量函数
function F() {} //创建一个构造函数
F.prototype = //把字面量函数赋值给构造函数的原型
return new F(); //最终返回出实例化的构造函数
var box = { //字面量对象
name : 'Lee',
arr : ['哥哥','妹妹','姐姐']
box1.name = 'Jack';
alert(box1.name);但是原型式继承中由于中转函数中构造函数采用原型链继承,因此会出现引用类型共享问题,所以,通常不采用此种方法。
综上:JS继承中通常可采用组合式继承来实现为超类传参和重写问题,有时,由于为了更好的封装,解决组合中二次调用超类型问题,也会采用寄生组合继承来实现,这里还需要一个中转和寄生函数来实现。这个还有待深入学习。。。
本文链接:
最 近 更 新
热 点 排 行
Js与CSS工具
代码转换工具JS中继承机制的三种方法实现
JS中继承机制的三种方法实现
阅读心得:1,构造继承适合单个class简单,优点继承关系明确2,&原型链适合无参数继承3,混合根据情况而定JS中继承机制的实现JS中实现实现继承的机制不止一种,这是因为JS中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,我们有权决定最适用的继承方式。1.构造继承法。构造继承法是使用了FUNCTION对象的call和apply方法。call的第一个参数用作this的对象,其余的参数是传给函数的参数。示例代码如下function classA(sColor){&& this.color=sC&& this.sayColor=function()&& {&&&&& alert(this.color);&& }}function classB(sColor,sName){&& classA.call(this,sColor);&& this.name=sN&& this.sayName=function()&& {&&&&& alert(this.name);&& }}这样,classB内部先调用了classA的构造函数,将该构造函数的的啊用对象设置成classB的对象,从而实现了对classA的继承.而 apply的用法基本上和call相同,唯一的不同点是apply方法只有两个参数,第一个参数是用作this的对象,第二个参数是要传给构造函数的参数 数组。要注意,用prototype对象定义的属性和方法是不能用这种方法继承的。2.原型链我们知道,prototype对象是个模版,要实例化的对象都会以这模板作为基础。总而言之,prototype对象的任何属性和方法都被传递给那个类的所有实例。原型链正是利用这种功能来实现继承机制。function classA(){}classA.prototype.color="red";classA.prototype.sayColor=function(){&& alert(this.color);}function ClassB(){}ClassB.prototype=new ClassA();ClassB.prototype.name="";ClassB.prototype.sayName=function(){&& alert(this.name);}因为任何一个类只能有一个原型对象,所以原型链的弊端是不支持多重继承。而且,原型链会用另一类型的对象重写类的prototype属性。3.混合方式这种方式的思想是使用构造继承法继承属性,而用原型链继承法继承方法function ClassA(sColor){&& this.color=sC}ClassA.prototype.sayColor=function(){&& alert(this.color);}function ClassB(sColor,sName){&& ClassA.call(this,sColor);&& this.name=sN}ClassB.prototype=new ClassA();ClassB.prototype.sayName=function(){&& alert(this.name);}最后要注意的是用动态原型方法实现继承是不行的。。因为它会先创造对象实例,然后修改原型。这样会使第一个被创造的对象实例无法看到这种改变。但是未来的对象实例可以反映出这种改变。
发表评论:
TA的最新馆藏[转]&译者按:这篇文章原是出自著名的前端博主一篇关于JS原型继承的文章:中的引用。这篇文章对于原型继承讲解详细,令人读之有拨云见日之感,作者在文章里说:
我一直很难理解Javascript语言的继承机制。
它没有“子类”和“父类”的概念,也没有“类”(class)和“实例”(instance)的区分,全靠一种很奇特的“原型链”(prototype chain)模式,来实现继承。
我花了很多时间,学习这个部分,还做了很多笔记。但是都属于强行记忆,无法从根本上理解。
直到昨天,我读到法国程序员Vjeux的解释,才恍然大悟,完全明白了Javascript为什么这样设计。
不过说来惭愧,本人面向对象学的不是很好,对于传统的继承思想其实理解的并不深刻,所以JS的在程序语言里特立独行的原型继承对我来说就是第一个深入理解的继承思想。我也特别想知道这篇令作者恍然大悟的文章究竟讲的如何,于是特意翻译一下,以飨读者。
原文链接:
JavaScript采用原型继承这事儿是众所皆知的,但由于它默认只提供了一个实现的实例,也就是 new 运算符,因此对于它的解释总是令人困惑。这篇文章旨在阐明什么是原型继承以及在JavaScript中究竟如何使用原型继承。
原型继承的定义
当你阅读关于JS原型继承的解释时,你时常会看到以下这段文字:
当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止。——出自
大多数JavaScript的实现用 __proto__ 属性来表示一个对象的原型链。在这篇文章里我们将看到 __proto__与 prototype 的区别何在。
注:__proto__ 是一个不应在你代码中出现的非正规的用法,这里仅仅用它来解释JavaScript原型继承的工作原理。
以下代码展示了JS引擎如何查找属性:
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop))
return obj[prop]
else if (obj.__proto__ !== null)
return getProperty(obj.__proto__, prop)
return undefined
让我们举一个常见的例子:二维点,拥有二维坐标 x y ,同似拥有一个 print 方法。
用之前我们说过的原型继承的定义,我们创建一个对象 Point ,拥有三个属性:x,y 和 print 。为了能创建一个新的二维点,我们需要创建一个新的对象,让他其中的 __proto__ 属性指向 Point :
var Point = {
print: function () { console.log(this.x, this.y); }
var p = {x: 10, y: 20, __proto__: Point};
p.print(); // 10 20
JavaScript怪异的原型继承
令人困惑的是,每个教授原型继承的人都不会给出上面那样的代码,反而会给出下面这样的代码:
function Point(x, y) {
Point.prototype = {
print: function () { console.log(this.x, this.y); }
var p = new Point(10, 20);
p.print(); // 10 20
这和说好的不一样啊,这里 Point 变成了函数,然后还有个什么 prototype 的属性,而且有了 new 运算符。这他喵的是什么情况?
new 运算符是如何工作的
想让JS和传统的面向对象的编程语言差不太多,如Java和C++。在这些语言里,我们采用 new 运算符来给类实例化一个新的对象。所以他在JS里写了一个 new 运算符。
C++里有用来初始化实例属性的构造函数概念,因此 new 运算符必须针对函数。
我们需要将对象的方法放到一个地方去,既然我们在用原型语言,我们就把它放到函数的原型属性中去。
new 运算符接受一个函数 F 及其参数:new F(arguments...)。这一过程分为三步:
创建类的实例。这步是把一个空的对象的 __proto__ 属性设置为 F.prototype 。
初始化实例。函数 F 被传入参数并调用,关键字 this 被设定为该实例。
返回实例。
现在我们知道了 new 是怎么工作的,我们可以用JS代码实现一下:
function New (f) {
var n = { '__proto__': f.prototype }; /*第一步*/
return function () {
f.apply(n, arguments);
/*第二步*/
/*第三步*/
一个小小的例子来看一下他的工作状况:
function Point(x, y) {
Point.prototype = {
print: function () { console.log(this.x, this.y); }
var p1 = new Point(10, 20);
p1.print(); // 10 20
console.log(p1 instanceof Point); // true
var p2 = New (Point)(10, 20);
p2.print(); // 10 20
console.log(p2 instanceof Point); // true
JavaScript中真正的原型继承
JS的只允许我们采用 new 运算符来进行原型继承。但是大宗师 Douglas Crockford 却发现了一种可以利用 new 来实现真正的原型继承的方式!他写下了 Object.create 函数如下:
Object.create = function (parent) {
function F() {}
F.prototype =
return new F();
这看起来蛮奇怪的,但却是相当的简洁:它创建了新的对象,并将其原型设置为你想设置的任意值。如果我们允许使用 __proto__ ,那我们也可以这样写:
Object.create = function (parent) {
return { '__proto__': parent };
下面这段代码就是让我们的 Point 采用真正的原型继承:
var Point = {
print: function () { console.log(this.x, this.y); }
var p = Object.create(Point);
p.print(); // 10 20
我们已经了解了JS原型继承是什么,以及JS如何用特定的方式来实现之。然而使用真正的原型继承(如 Object.create 以及 __proto__)还是存在以下缺点:
标准性差:__proto__ 不是一个标准用法,甚至是一个不赞成使用的用法。同时原生态的 Object.create 和道爷写的原版也不尽相同。
优化性差: 不论是原生的还是自定义的 Object.create ,其性能都远没有 new 的优化程度高,前者要比后者慢高达10倍。
附图,ECMA中的原型继承解释图:
译者的理解
实际上我觉得这篇文章所说还是十分的晦涩,没有阮一峰的原文写的深入浅出。这里还是推荐要了解原型继承和JS面向对象编程的读者阅读阮一峰的四篇博文:
这里简单的说一下我的理解:
为什么不推荐使用原型链 __proto__ 的写法?因为这样会对下游的子类开放对整个原型链的操作权限,也就是在子类中就可以对由上游父类产生的原型链进行修改,这一点是十分危险的。比如:
var P = new function(){}
P.prototype.name = 'parent'
var a = new P()
a.name // 'parent'
a.__proto__ === P.prototype //true
a.__proto__.name = 'child'
P.prototype.name // 被修改为'child'
原型继承到底继承了什么?实际上就是继承了构造函数和原型链两个东西。其中构造函数继承是用 apply() 实现的,这就意味着仅仅是把父类里面的属性复制了一遍,对其进行任何的更改,都不会影响其他的实例,在继承之后对父类进行任何更改也不会影响其子类。而对于原型链的继承,则是表示子类和父类共用原型链上的属性和方法,对于原型链的更改只能从上游源头进行修改,当然子类可以重写父类的方法,不过这样做实际上就是先给子类增添一个重名的方法,而导致JS引擎先调用此方法而不去调用原型链的方法。
大宗师的代码到底干了什么?道爷的代码主要是把刚才的构造函数继承都抛弃了,把所有父类的属性全部放在原型链上,让子类直接引用。这样是相当的节省内存的,这时子类如果想更改某一属性,则就会遵循2中所说的重写的方法。而且道爷这样写,父类就可以是任意的对象,而不必要非是函数,理解起来比JS晦涩的原生继承好的多。
本文目前还没有评论……JS继承--原型链继承和类式继承
JS继承--原型链继承和类式继承
  什么是继承啊?答:别人白给你的过程就叫继承。
  为什么要用继承呢?答:捡现成的呗。
  好吧,既然大家都想捡现成的,那就要学会怎么继承!
  在了解之前,你需要先了解构造函数、对象、原型链等概念......
  JS里常用的两种继承方式:
原型链继承(对象间的继承)类式继承(构造函数间的继承)
  原型链继承:
    复制代码 代码如下:  //要继承的对象var parent={name : "baba"    say : function(){ alert("I am baba");}}
  //新对象var child = proInherit(parent);
  //测试alert(child.name); //"baba"child.say(); //"I am baba"
  利用proInherit(obj)方法,传入对象,就能实现对象的属性及方法的继承,这个方法不是内置方法,所以要自己定义,非常简单:  复制代码 代码如下:  function proInherit(obj){function F () {}F.prototype =return new F();}
  其中F()为一个临时的空的构造函数,然后将F()的原型设置为父对象,但是同时它又通过受益于_proto_链接而具有其父亲对象的全部功能。
  链式图解:
  类式继承:
    复制代码 代码如下:  //父类构造函数function Parent() {this.name = "baba";}//父类原型方法Parent.prototype.getName = function () {return this.}
  //子类构造函数function Child() {this.name = "cc";}
  //类式继承classInherit(Parent, Child);
  //实例var child = new Child();alert(child.getName()) //“baba”
  下面我们来看看这个继承的关键方法:classInherit(Parent,Child)  复制代码 代码如下:  var classInherit = (function () {var F = function () { }return function (P, C) {F.prototype = P.C.prototype = new F();nstructor = C;}}());
  分析一下这个方法:
首先创建一个空的构造函数F(),用其实例的_proto_属性来构建父类与子类的原型链。起到一个代理的作用,目的是为了防止C.prototype = P.prototype,这样会在子类实例化后修改属性或方法时候,连同父类一起修改。整体采用即时函数并且在闭包中存储F(),防止多次继承时候创建大量的空的构造函数,从而减少消耗内存。最后一行的意思是,由于原型链的关系,C的实例对象的constructor会指向P,所以重新设置。
  链式图解:
  这种方式虽然在实例的时候继承了原型方法,但是父类的属性无法继承,下面介绍一种复制继承,算是对类式继承的补充。
  复制继承:
    复制代码 代码如下:  //复制继承function copyInherit(p, c) {var i,toStr = Object.prototype.toString,astr = "[object Array]";c = c || {}; for (i in p) {if (p.hasOwnProperty(i)) {if (typeof p[i] === "object") {c[i] = toStr.call(p[i]) == astr ? [] : {};c[i] = copy(p[i], c[i]);}else {c[i] = p[i];}}}}
  //重写Parentfunction Parent() {this.name = "pp";this.obj= {a:1,b:2};this.arr= [1, 2]}//实例var child = new Child();var parent = new Parent();copyInherit(parent, child);alert(child.name) //"baba"alert(child.arr) //1,2alert(child.obj.a) //1
  分析下copyInherit(p,c)
  当一个值赋予一个变量时候,分为传值和传引用两种方式,当你父对象内属性包含数组类型或是对象类型时候,& c[i] = toStr.call(p[i]) == astr ? [] : {};这一句会避免修改子对象属性而引起的父对象属性被篡改。
  类式继承比较普遍,因为大家都比较熟悉这种构造函数方式,但是内存占用比较大。而原型式继承,占用内存比较小,但是包含数组,或者对象类型的克隆比较麻烦。复制继承简单,而且应用广泛。
H3C认证Java认证Oracle认证
基础英语软考英语项目管理英语职场英语
.NETPowerBuilderWeb开发游戏开发Perl
二级模拟试题一级模拟试题一级考试经验四级考试资料
港口与航道工程建设工程法规及相关知识建设工程经济考试大纲矿业工程市政公用工程通信与广电工程
操作系统汇编语言计算机系统结构人工智能数据库系统微机与接口
软件测试软件外包系统分析与建模敏捷开发
法律法规历年试题软考英语网络管理员系统架构设计师信息系统监理师
高级通信工程师考试大纲设备环境综合能力
路由技术网络存储无线网络网络设备
CPMP考试prince2认证项目范围管理项目配置管理项目管理案例项目经理项目干系人管理
Powerpoint教程WPS教程
电子政务客户关系管理首席信息官办公自动化大数据
职称考试题目
就业指导签约违约职业测评
招生信息考研政治
网络安全安全设置工具使用手机安全
3DMax教程Flash教程CorelDraw教程Director教程
Dreamwaver教程HTML教程网站策划网站运营Frontpage教程
生物识别传感器物联网传输层物联网前沿技术物联网案例分析
互联网电信IT业界IT生活
Java核心技术J2ME教程
Linux系统管理Linux编程Linux安全AIX教程
Windows系统管理Windows教程Windows网络管理Windows故障
组织运营财务资本
视频播放文件压缩杀毒软件输入法微博
数据库开发Sybase数据库Informix数据库
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&

我要回帖

更多关于 js原型式继承 的文章

 

随机推荐