- 浏览: 589517 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (214)
- javaweb学习 (20)
- 算法 (7)
- oracle数据库 (18)
- PHP学习 (3)
- mysql数据库 (8)
- css (9)
- ajax (2)
- it生活 (1)
- 数据结构 (2)
- jsp (1)
- 设计模式 (3)
- struts1 (0)
- struts2 (0)
- spring (6)
- hibernate (2)
- tomcat (2)
- xml (0)
- javascript (16)
- java基础 (19)
- ASP.基础 (1)
- 非技术 (8)
- 女人的反常行为,女人爱哭,鲜花,爱,男人,电话,闺蜜,恋爱 (1)
- 计算机 (4)
- 互联网新闻 (1)
- 面试题 (1)
- c++ (1)
- 浏览器 (1)
- MyEclipse (0)
- 关系数据库 (1)
- 开发工具 (2)
- HTTP协议 (2)
- oracle性能优化 (1)
- java性能优化 (1)
- android (0)
- jquery (2)
- jdbc (2)
- 计算机系统 (1)
- linux (22)
- 网络安全 (1)
- java架构 (2)
- 软件工具 (1)
- nginx (4)
- chrome (1)
- SVN (1)
- jetty (1)
- 研发管理 (4)
- hadoop (3)
- eclipse (2)
- JSON (3)
- mysql (14)
- restful (1)
- vbox (1)
- maven (3)
- netty (1)
- Web前端 (1)
- HTML (1)
- 设计 (1)
- Redis (1)
- cassandra (1)
最新评论
-
itlang01:
推荐mybatis插件https://github.com/y ...
mysql设置修改时间,更新记录当前时间 -
longen2011:
客户端可以发送包含“Content-Encoding: gzi ...
HTTP消息头详细介绍 -
Tiro_Li:
很抱歉你指出了我博文中的错误,这个问题是由于maven-ar ...
mvn构建web项目异常处理 -
chen_lian:
似乎有点问题的是如果 输入 000009能够验证通过
js验证输入的值是否钱数 -
nicegege:
起来Rails的一个五颜六色的羽毛帽,现在是在地面上。 Twi ...
oracle数据库导出命令EXP
继承机制的实现
要用 ECMAScript 实现继承机制,您可以从要继承的基类入手。所有开发者定义的类都可作为基类。出于安全原因,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可以被用于恶意攻击。
选定基类后,就可以创建它的子类了。是否使用基类完全由你决定。有时,你可能想创建一个不能直接使用的基类,它只是用于给子类提供通用的函数。在这种情况下,基类被看作抽象类。
尽管 ECMAScript 并没有像其他语言那样严格地定义抽象类,但有时它的确会创建一些不允许使用的类。通常,我们称这种类为抽象类。
创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。记住,所有属性和方法都是公用的,因此子类可直接访问这些方法。子类还可添加超类中没有的新属性和方法,也可以覆盖超类的属性和方法。
继承的方式
和其他功能一样,ECMAScript 实现继承的方式不止一种。这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适用的继承方式。
下面为您介绍几种具体的继承方式。
对象冒充
构想原始的 ECMAScript 时,根本没打算设计对象冒充(object masquerading)。它是在开发者开始理解函数的工作方式,尤其是如何在函数环境中使用 this 关键字后才发展出来。
其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 ClassA 构造函数成为 ClassB 的方法,然后调用它。ClassB 就会收到 ClassA 的构造函数中定义的属性和方法。例如,用下面的方式定义 ClassA 和 ClassB:
function ClassA(sColor) { this.color = sColor; this.sayColor = function () { alert(this.color); };}function ClassB(sColor) {}
还记得吗?关键字 this 引用的是构造函数当前创建的对象。不过在这个方法中,this 指向的所属的对象。这个原理是把 ClassA 作为常规函数来建立继承机制,而不是作为构造函数。如下使用构造函数 ClassB 可以实现继承机制:
function ClassB(sColor) { this.newMethod = ClassA; this.newMethod(sColor); delete this.newMethod;}
在这段代码中,为 ClassA 赋予了方法 newMethod(请记住,函数名只是指向它的指针)。然后调用该方法,传递给它的是 ClassB 构造函数的参数 sColor。最后一行代码删除了对 ClassA 的引用,这样以后就不能再调用它。
所有新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法:
function ClassB(sColor) { this.newMethod = ClassA; this.newMethod(sColor); delete this.newMethod; this.name = sName; this.sayName = function () { alert(this.name); };}
为证明前面的代码有效,可以运行下面的例子:
var objA = new ClassA("blue");var objB = new ClassB("red", "John");objA.sayColor(); //输出 "blue"objB.sayColor(); //输出 "red"objB.sayName(); //输出 "John"
对象冒充可以实现多重继承
有趣的是,对象冒充可以支持多重继承。也就是说,一个类可以继承多个超类。用 UML 表示的多重继承机制如下图所示:
例如,如果存在两个类 ClassX 和 ClassY,ClassZ 想继承这两个类,可以使用下面的代码:
function ClassZ() { this.newMethod = ClassX; this.newMethod(); delete this.newMethod; this.newMethod = ClassY; this.newMethod(); delete this.newMethod;}
这里存在一个弊端,如果存在两个类 ClassX 和 ClassY 具有同名的属性或方法,ClassY 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。
由于这种继承方法的流行,ECMAScript 的第三版为 Function 对象加入了两个方法,即 call() 和 apply()。
call() 方法
call() 方法是与经典的对象冒充方法最相似的方法。它的第一个参数用作 this 的对象。其他参数都直接传递给函数自身。例如:
function sayColor(sPrefix,sSuffix) { alert(sPrefix + this.color + sSuffix);};var obj = new Object();obj.color = "blue";sayColor.call(obj, "The color is ", "a very nice color indeed.");
在这个例子中,函数 sayColor() 在对象外定义,即使它不属于任何对象,也可以引用关键字 this。对象 obj 的 color 属性等于 blue。调用 call() 方法时,第一个参数是 obj,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj。第二个和第三个参数是字符串。它们与 sayColor() 函数中的参数 sPrefix 和 sSuffix 匹配,最后生成的消息 "The color is blue, a very nice color indeed." 将被显示出来。
要与继承机制的对象冒充方法一起使用该方法,只需将前三行的赋值、调用和删除代码替换即可:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.call(this, sColor); this.name = sName; this.sayName = function () { alert(this.name); };}
这里,我们需要让 ClassA 中的关键字 this 等于新创建的 ClassB 对象,因此 this 是第一个参数。第二个参数 sColor 对两个类来说都是唯一的参数。
apply() 方法
apply() 方法有两个参数,用作 this 的对象和要传递给函数的参数的数组。例如:
function sayColor(sPrefix,sSuffix) { alert(sPrefix + this.color + sSuffix);};var obj = new Object();obj.color = "blue";sayColor.call(obj, new Array("The color is ", "a very nice color indeed."));
这个例子与前面的例子相同,只是现在调用的是 apply() 方法。调用 apply() 方法时,第一个参数仍是 obj,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj。第二个参数是由两个字符串构成的数组,与 sayColor() 函数中的参数 sPrefix 和 sSuffix 匹配,最后生成的消息仍是 "The color is blue, a very nice color indeed.",将被显示出来。
该方法也用于替换前三行的赋值、调用和删除新方法的代码:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply(this, new Array(sColor)); this.name = sName; this.sayName = function () { alert(this.name); };}
同样的,第一个参数仍是 this,第二个参数是只有一个值 color 的数组。可以把 ClassB 的整个 arguments 对象作为第二个参数传递给 apply() 方法:
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply(this, arguments); this.name = sName; this.sayName = function () { alert(this.name); };}
当然,只有超类中的参数顺序与子类中的参数顺序完全一致时才可以传递参数对象。如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。此外,还可使用 call() 方法。
原型链(prototype chaining)
继承这种形式在 ECMAScript 中原本是用于原型链的。上一章介绍了定义类的原型方式。原型链扩展了这种方式,以一种有趣的方式实现继承机制。
在上一章学过,prototype 对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。
如果用原型方式重定义前面例子中的类,它们将变为下列形式:
function ClassA() {}ClassA.prototype.color = "blue";ClassA.prototype.sayColor = function () { alert(this.color);};function ClassB() {}
ClassB.prototype = new ClassA();
原型方式的神奇之处在于突出显示的蓝色代码行。这里,把 ClassB 的 prototype 属性设置成 ClassA 的实例。这很有意思,因为想要 ClassA 的所有属性和方法,但又不想逐个将它们 ClassB 的 prototype 属性。还有比把 ClassA 的实例赋予 prototype 属性更好的方法吗?
注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
与对象冒充相似,子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。为什么?因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。所以,为 ClassB 类添加 name 属性和 sayName() 方法的代码如下:
function ClassB() {}ClassB.prototype = new ClassA();ClassB.prototype.name = "";ClassB.prototype.sayName = function () { alert(this.name);};
可通过运行下面的例子测试这段代码:
var objA = new ClassA();var objB = new ClassB();objA.color = "blue";objB.color = "red";objB.name = "John";objA.sayColor();objB.sayColor();objB.sayName();
此外,在原型链中,instanceof 运算符的运行方式也很独特。对 ClassB 的所有实例,instanceof 为 ClassA 和 ClassB 都返回 true。例如:
var objB = new ClassB();alert(objB instanceof ClassA); //输出 "true"alert(objB instanceof ClassB); //输出 "true"
在 ECMAScript 的弱类型世界中,这是极其有用的工具,不过使用对象冒充时不能使用它。
原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。
混合方式
这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。开发者如何选择呢?答案很简单,两者都用。
在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。用这两种方式重写前面的例子,代码如下:
function ClassA(sColor) { this.color = sColor;}ClassA.prototype.sayColor = function () { alert(this.color);};function ClassB(sColor, sName) {
ClassA.call(this, sColor);
this.name = sName;}
ClassB.prototype = new ClassA();
ClassB.prototype.sayName = function () { alert(this.name);};
在此例子中,继承机制由两行突出显示的蓝色代码实现。在第一行突出显示的代码中,在 ClassB 构造函数中,用对象冒充继承 ClassA 类的 sColor 属性。在第二行突出显示的代码中,用原型链继承 ClassA 类的方法。由于这种混合方式使用了原型链,所以 instanceof 运算符仍能正确运行。
下面的例子测试了这段代码:
var objA = new ClassA("blue");var objB = new ClassB("red", "John");objA.sayColor(); //输出 "blue"objB.sayColor(); //输出 "red"objB.sayName(); //输出 "John"
原文链接http://blog.163.com/jiang_tao_2010/blog/static/1211268902009111731343832/
发表评论
-
列表转换树形
2018-01-18 00:33 802今日,java程序中碰到菜单权限枚举(Enum),把一组权 ... -
js单线程问题
2015-05-13 15:33 767最近想做一个东西,大概是这样的。浏览器的滚动条在body头 ... -
cdn无法访问的时候,访问原文件
2015-04-22 18:58 851访问cdn无法访问的时候,访问源文件 <script ... -
JS中的!=、== 、!==、===的用法和区别
2015-04-21 10:04 701... -
js文件\u开头的编码原来是unicode编码
2015-04-15 18:07 3367在js文件中发现一串编码,\u开头。起初以为是ASIIC码 ... -
js数组操作总结
2013-04-22 08:32 0js数组操作大全(转) ... -
一个简单数学问题用程序实现
2013-04-01 09:25 883现在盒子中有10个棋子,在盒子中加入20个棋子以后,白棋和黑 ... -
[转]详细总结js中的json对象
2012-11-06 11:29 21789使用JSON 进行数据传 ... -
[转]Node.js安装攻略
2012-11-06 10:03 1464什么是Node.js?还服务器端javascript?对于这个 ... -
面向对象语言的特征
2012-11-05 11:34 11251.java和javascript是面向对 ... -
ECMAScript的Object类
2012-11-05 10:36 8851.ECMAScript中的object类与java里的jav ... -
[转]玩转IE之自动切换代理服务器
2012-08-28 10:25 2081今天和一个朋友聊到了chrome的自动代理功能,很多人感觉这个 ... -
web页面框架之间的数组访问
2012-05-17 17:45 0xx -
给大家推荐一个学习JavaScript的好地方
2012-04-27 17:41 9391.给大家推荐一个学习JavaScript的好地方,在线学习J ... -
查看js对象的所有属性而引发的问题
2012-03-22 17:32 23741.查看document.iframe1对象的所有属性。 ... -
js验证输入的值是否钱数
2011-11-09 17:11 55851.text文本框接受输入的值,输入的值要符合如下规则: ( ... -
JS正则总结
2011-11-03 16:12 10381.什么是正则表达式? ...
相关推荐
JavaScript中的继承和原型链是其核心特性之一,尤其对于从基于类的语言背景转到JavaScript的开发者来说,理解这一概念至关重要。在JavaScript中,没有传统的类,而是基于对象和原型进行继承。每个对象都有一个指向其...
要用ECMAScript实现继承机制,首先从基类入手。所有开发者定义的类都可作为基类。出于安全原因,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可以被用于恶意攻击。
原型链是JavaScript实现继承的机制,它允许一个对象访问另一个对象的属性和方法。继承是指新创建的对象可以继承其原型对象的属性和方法。下面详细探讨这两个概念。 **原型链** 在JavaScript中,每个对象都有一个...
通过理解`prototype`以及与之相关的概念,如原型链、方法重写和`call()`,开发者可以更有效地利用JavaScript的面向对象特性,实现复杂的继承和扩展。在实际开发中,熟练掌握这些知识对于编写可维护和高效的代码至关...
在ECMAscript中描述了原型链的概念,并将原型链作为实现继承的主要方法,其基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法。 构造函数和原型还有实例之间的关系: 每个构造函数都有一个原型...
原型链继承通过将子构造函数的prototype属性指向一个父构造函数的实例来实现。这样,所有通过子构造函数创建的实例都能访问父构造函数原型链上的属性和方法。 问题在于,如果父对象中包含引用类型的属性,子对象对...
大多OO语言都支持两种继承方式: 接口继承和实现继承 ,而ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现,下文给大家技术js实现继承的六种方式,需要的朋友参考下
原型链是JavaScript实现继承的关键机制。 3. **作用域链与闭包**:在ECMAScript中,变量的作用域决定了其可见性和生命周期。作用域链(Scope Chain)是由当前执行上下文的变量对象组成的链,用于在不同作用域查找...
随着 ECMAScript 标准的不断更新,新的继承方式提供了更加简洁和高效的实现手段,但原型链和构造函数的继承机制依然是理解 JavaScript 继承特性的基础。通过阮一峰老师的总结,我们可以看到,JavaScript 的继承实现...
由于原型链是动态的,开发者可以灵活地改变对象的原型,实现更加丰富的继承机制和对象行为。而instanceof提供了在运行时检查对象原型链的能力,可以用于判断对象类型或验证继承关系。通过这些机制,JavaScript对象的...
在深入探讨JavaScript实现继承的具体机制之前,首先需要了解JavaScript本身的一些核心概念,包括函数、对象以及原型链。 JavaScript中的函数不仅可以用来定义行为,而且在ES6之前,函数还可以用来定义类。这与传统...
在JavaScript(ECMAScript)中,继承机制是通过多种方式实现的,包括但不限于原型链、构造函数借用、组合继承等。JavaScript的类并非传统意义上的类,而是通过函数来模拟的。当一个函数被用作构造函数时,它可以创建...
当我们谈论`prototype`时,实际上是在讨论JavaScript的原型链机制。 首先,我们来理解`prototype`的基本用法。当我们创建一个函数(构造函数)时,该函数的`prototype`属性会自动被初始化为一个对象,这个对象有一...
本文将详细总结JavaScript实现继承的四种方法:原型链继承、构造继承、实例继承、拷贝继承。 1. 原型链继承 原型链继承是最本质的继承方式,它利用了原型对象上定义的属性和方法可以被子类实例访问的特性。在原型...
组合继承是JavaScript中最常用的继承模式,它结合了构造函数继承和原型链继承,但同时也存在两次调用父类构造函数的问题,导致了不必要的属性复制。为解决这个问题,我们使用寄生组合式继承: ```javascript ...
5. 原型链的用途:原型链机制使得JavaScript能够实现基于原型的继承。新创建的对象可以通过原型链继承构造函数原型对象的属性和方法。这种继承方式和基于类的继承不同,它是一种动态的原型继承。 6. Function原型与...
2. 支持原型链继承:通过重写一个对象的prototype属性指向另一个对象的实例,可以实现一种原型链继承机制,使得子对象可以继承父对象的属性和方法。 文章中提到了三个关于prototype属性使用的示例,分别是: 1. 为...
ES6(ECMAScript 2015)引入了一系列新的特性,其中就包括对原型对象的改进,使得对象继承更加简洁易用。在本教程中,我们将深入探讨ES6中的原型扩展以及如何使用`XExtends Core v1.0.0`提供的核心功能,如`core.js`...
在ES5中,我们通常使用原型链(prototype chain)来实现继承。我们可以使用`Object.create`方法来创建一个新的对象,这个对象的原型是另一个对象,从而实现继承: ```javascript function Student(name, grade) { ...