- 浏览: 1344475 次
- 性别:
- 来自: 湖南澧縣
-
文章分类
最新评论
-
虾米小尹:
不行啊!2.2-0.25=1.9500000000000002 ...
JavaScript浮点数运算 —— 精度问题 -
heluping000000:
引用String a= "abc",首先在 ...
String,到底创建了多少个对象? -
mack:
谢谢分享matcher.appendReplacement(s ...
string.replaceAll()中的特殊字符($ \)与matcher.appendReplacement -
wzt3309:
完全理解,比网上其他资料都要详细
String,到底创建了多少个对象? -
u014771876:
Java中十六进制转换 Integer.toHexString()
所有开发者定义的类都可作为基类。出于安全原因,本地类和宿主类不能作为基类。有时,你可能想创建一个不能直接使用的基类,它只是用于给子类提供通用的函数。在这种情况下,基类被看作抽象类。尽管ECMAScript并没有像其他语言那样严格地定义抽象类,但有时它的确会创建一些不允许使用的类。通常,我们称这种类为抽象类。
创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。记住,所有属性和方法都是公用的,因此子类可直接访问这些方法。子类还可添加超类中没有的新属性和方法,也可以覆盖超类中的属性和方法。
JavaScript中的继承机制并不是明确规定的,而是通过模仿实现的。
-
对象冒充
构造原始的ECMAScript时,根本没打算设计对象冒充(object masquerading)。它是在开发者开始理解函数的工作方式,尤其是如何在函数环境中使用this关键字后才发展出来的。
其原理如下:构造函数使用this关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使ClassA的构造函数成为ClassB的方法,然后调用它。ClassB就会收到ClassA的构造函数中定义的属性和方法。
所有的新属性和新方法都必须在删除父类构造函数的代码行后定义,否则,可能会覆盖子类的相关属性和方法。
多层继承代码示例如下:
function classA(sColor) { this.color = sColor; this.sayColor = function () { alert(this.color); }; } //classB继承classA function classB(sColor, sName) { this.newMethod = classA; this.newMethod(sColor); delete this.newMethod; //以下是自己的属性与方法,一般在调用父类构造后定义 this.name = sName; this.sayName = function () { alert(this.name); }; } //classC继承classB function classC(sColor, sName, iNum) { this.newMethod = classB; this.newMethod(sColor, sName); delete this.newMethod; //以下是自己的属性与方法,一般在调用父类构造后定义 this.iNum = iNum; this.sayNum = function () { alert(this.iNum); }; } var objC = new classC("blue", "name", 10); objC.sayColor();//blue objC.sayName();//name objC.sayNum();//10
对象冒充可以支持多重继承 :
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 = "red"; //The color is red, a very nice color indeed. sayColor.call(obj, "The color is ", ", a very nice color indeed.");
在这个例子中,函数 sayColor() 在对象外定义,即使它不属于任何对象,也可以引用关键字 this 。对象 obj 的 color 属性等于 "red " 。调用 call() 方法时,第一个参数是 obj ,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj 。第二个和第三个参数是字符串。它们与 sayColor() 函数中的参数 prefix 和 suffix 匹配。
要与继承机制的对象冒充方法一起使用该方法,只需将前三行的赋值、调用和删除代码替换即可:
function classB(sColor, sName) { //this.newMethod = classA; //this.newMethod(sColor); //delete this.newMethod; ClassA.call(this, sColor); this.name = sName; this.sayName = function () { alert(this.name); }; }
-
apply()方法
apply()方法有两个参数,用作this的对象和要传递给函数的参数的数组。例如:
function sayColor(sPrefix, sSuffix) { alert(sPrefix + this.color + sSuffix); } var obj = new Object(); obj.color = "red"; //The color is red, a very nice color indeed. sayColor.apply(obj, new Array("The color is ", ", a very nice color indeed."));
这个例子与前面的例子相同,只是现在调用的是 apply() 方法。调用 apply() 方法时,第一个参数仍是 obj ,说明应该赋予 sayColor() 中的 this 关键字值是 obj 。第二个参数是由两个字符串构成的数组,与 sayColor() 的参数 prefix 和 suffix 匹配。
该方法也用于替换前三行的赋值、调用和删除新方法的代码:
function classB(sColor, sName) { //this.newMethod = classA; //this.newMethod(sColor); //delete this.newMethod; ClassA.apply(this, new Array(sColor)); this.name = sName; this.sayName = function () { alert(this.name); }; }
-
原型链
继承这种形式在ECMAScript中原本是用于原型链的。prototype对象的任何属性和方法都被传递给那个类的所有实例 。 原型链利用这种功能来实现继承机制。如果用原型方式重定义前面例子中的类,它们将变为下列形式:
function ClassA() { } ClassA.prototype.color = "red"; ClassA.prototype.sayColor = function () { alert(this.color); }; function classB() { } ClassB.prototype = new ClassA();
注意,调用 ClassA 的构造函数时,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
子类的所有属性和方法都必须出现在prototype属性被赋值后,因为在它之前赋值的所有方法都会被删除 。为什么?因为prototype属性被替换成了新对象,添加了新方法的原始对象将被销毁。所以,为ClassB类添加name属性和sayName()方法的代码如下:
function ClassA() { } ClassA.prototype.color = "red"; ClassA.prototype.sayColor = function () { alert(this.color); }; function ClassB() { } ClassB.prototype = new ClassA(); //下面的属性与方法赋值一定要在原型属性赋值后, //prototype默认为object ClassB.prototype.name = ""; ClassB.prototype.sayName = function () { alert(this.name); }; var objA = new ClassA(); var objB = new ClassB(); objA.color = "red"; objB.color = "blue"; objB.name = "name"; objA.sayColor();//red objB.sayColor();//blue objB.sayName();//name
此外,在原型链中, instanceof 运算符的运行方式也很独特。对 ClassB 的所有实例, instanceof 为 ClassA 和 ClassB 都返回 true 。例如:
var objB = new ClassB(); alert(objB instanceof ClassA);//true alert(objB instanceof ClassB);//true
在 ECMAScript 的弱类型世界中,这是极其有用的工具,不过使用对象冒充时不能使用它。
原型链的弊端是不支持多重继承 。记住,原型链会关键是用另一类型的对象重写类的原有默认 prototype 属性 。
原型链持多层继承
虽然原型链不支持多重继承,但支持多层继承,请看:
function Base1() { } Base1.prototype.base1Name = "base1Name"; Base1.prototype.getBase1 = function () { alert(this.base1Name); }; //Base2继承Base1 function Base2() { } Base2.prototype = new Base1(); Base2.prototype.base2Name = "base2Name"; Base2.prototype.getBase2 = function () { alert(this.base2Name); }; //Base3继承Base2 function Base3() { } Base3.prototype = new Base2(); Base3.prototype.base3Name = "base3Name"; Base3.prototype.getBase3 = function () { alert(this.base3Name); }; var base3 = new Base3(); //Base3可以访问从父类Base2继承过来的方法 base3.getBase2();//base2Name //Base3可以访问从超类Base1继承过来的方法 base3.getBase1();//base1Name //当然更可以访问自己的方法 base3.getBase3();//base3Name //因为原型链方法,所以支持instanceof alert(base3 instanceof Base1);//true alert(base3 instanceof Base2);//true alert(base3 instanceof Base3);//true
-
混合方式
这种继承方式使用构造函数定义类,并未使用任何原型。对象冒充的主要问题是必须使用构造函数方式。 这不是最好的选择。不过如果使用原型链,就无法使用带参构造函数了 。开发者该如何选择呢?答案很简单,两者都用。
创建类的最好方式是用构造函数方式定义属性,用原型方式定义方法 。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 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("red"); var objB = new ClassB("blue", "name"); objA.sayColor();//red objB.sayColor();//blue objB.sayName();//name
-
不能采用动态原型方法实现继承
继承机制不能采用动态化的原因是,prototype对象的独特本性。看下面代码:
function ClassA(name) { this.name = name; if (typeof ClassA._initialized == "undefined") { ClassA.prototype.get = function () { alert(name); }; ClassA._initialized = true; } } function ClassB(name, age) { ClassA.call(this, name); this.age = age; if (typeof ClassB._initialized == "undefined") { //不能在ClassB里改变他的prototype属性,即使改变后 //也只是下一新对象起作用 ClassB.prototype = new ClassA(); ClassB.prototype.get = function () { alert(name + " " + age); }; ClassB._initialized = true; } } var o1 = new ClassB("name", 1); //第一次创建的对象时,prototype未生效,以下方法找不着 //o1.get(); o1 = new ClassB("name", 1); //第二次创建的对象时,prototype才生效 o1.get();//name 1
上面的代码展示了用动态原型定义ClassA与ClassB,错误在于设置ClassB.prototype属性的代码。从逻辑上讲,这个位置是正确的,但从功能上讲,却是无效的。从技术上说来,在代码运行前,对象已被实例化,并与原始的prototype对象联系在一起了。虽然用晚绑定可用在其他非 prototype属性值,但替换prototype对象却不会对该对象产生任何影响。只从第二个对象实例才会反映出这种改变,这就使上面实例变得不正确。
而正确的作法是把ClassB.prototype = new ClassA();提出来放在函数的外面即可,这样从创建第一个对象开始就能生效。
发表评论
-
HTML、JS、JSON特殊字符
2010-12-13 23:47 25914JS到HTML特殊字符转换 这几天做项目,发现从服务器端以J ... -
HTML — HTTP URL 中的特殊字符
2009-10-31 18:16 33501. + URL中的+号表示空格 ... -
HTML — CSS选择器
2009-10-25 21:11 2219一个样式规则由两部分组成:选择器和样式声明。选择器表明要为哪一 ... -
部分解决JsUnit无法在firefox3、safari 测试的问题
2009-10-25 07:03 1465在上一篇中出现了一个问题,就是用 jsunit2.2alpha ... -
JsUnit——eclipse插件(四)
2009-10-25 06:59 2478这节我们来看看如何通过JsUnit插件来运行前几节所测试过的测 ... -
10、JavaScript跨浏览器需注意的问题——ajax基础笔记
2009-10-21 22:19 1402向表中追加行 创建表格行时,我们要把创建的 tr 追加到 t ... -
JsUnit详解——Web服务方式(三)
2009-10-21 00:21 2486上两节提到过以Web方式来运行JsUnit,不过不是很详细,这 ... -
JsUnit详解——《ajax基础》笔记(二)
2009-10-20 22:38 2581使用标准/定制查询串 如此说来,测试运行工具是很强大的,但是 ... -
JsUnit详解——《ajax基础》笔记(一)
2009-10-20 19:57 2658JsUnit与JUnit对比 JsUnit也有setUp() ... -
使用Firefox的Web开发插件
2009-10-18 17:53 1492Firefox的Web开发插件为Firefox浏览器增加了大量 ... -
9、访问WEB服务(REST)——ajax基础笔记
2009-10-18 17:24 4080最其名的WEB服务实现是S ... -
8、读取响应头部——ajax基础笔记
2009-10-18 17:20 6784你有时可能需要从服务器获取一些内容,例如,可能想“ping”一 ... -
7、使用JSON向服务器发送数据——ajax基础笔记
2009-10-18 17:20 5262看过前面的例子后(使用XML向服务器发送复杂的数据结构),你可 ... -
6、请求参数作为XML发送——ajax基础笔记
2009-10-18 17:20 1828如果只是使用一个包含 名/值 对的简单查询串,这可能不够健壮, ... -
4、将使用W3C DOM动态生成页面——ajax基础笔记
2009-10-18 17:19 1488使用W3C DOM动态生成页面 dynamicContent ... -
3、将响应解析为XML——ajax基础笔记
2009-10-18 17:18 1089将响应解析为XML parseXML.xml清单: < ... -
2、使用innerHTML属性创建动态内容——ajax基础笔记
2009-10-18 17:17 1983使用innerHTML属性创建动态内容 如果结合作用HTML ... -
1、使用XMLHttpRequest对象——ajax基础笔记
2009-10-18 17:17 2046XMLHttpRequest最早是在 IE5 中以active ... -
30、JavaScript代码优化
2009-10-16 21:25 1633JavaScript代码的速度被分成两部分:下载时间和执行速度 ... -
JavaScript代码优化(二)
2009-10-16 01:32 1221◆字符串的使用 在IE6和IE7中因字符串级联导致的主要问题 ...
相关推荐
本篇文章将深入探讨JavaScript中实现继承的几种常见方式。 1. 原型链继承 JavaScript的原型(prototype)机制是实现继承的基础。每个函数都有一个prototype属性,这个属性指向一个对象,这个对象的属性和方法可以被...
本文将深入探讨JavaScript继承的实现方式,以及其中的问题和解决方案。 首先,我们来看混合方式的实现,这种方式结合了原型链和对象冒充。在JavaScript中,构造函数是用于创建特定类型对象的函数。例如,`Employee`...
本篇文章将深入探讨JavaScript实现继承的七种常见方式,帮助你更好地理解和运用这一概念。 1. 原型链继承(Prototype Chain Inheritance) 原型链是JavaScript实现继承的基础。每个函数都有一个`prototype`属性,这...
在Java或C++等语言中,继承通常只需要一个关键字,如`extends`,但在JavaScript中,实现继承需要采用一系列技术。 JavaScript使用的是原型式继承,这是它与其他语言的一大区别。原型(Prototype)是JavaScript实现...
本文将深入探讨 JavaScript 中的继承实现方式,并结合提供的 "zinherit.js" 文件来解析相关知识点。 在 JavaScript 中,继承主要通过原型链(prototype chain)、构造函数继承、组合继承、原型式继承、寄生式继承、...
而实例则是类的一个具体实现。 我们还知道,面向对象编程有三个重要的概念 - 封装、继承和多态。 但是在JavaScript的世界中,所有的这一切特性似乎都不存在。 因为JavaScript本身不是面向对象的语言,而是基于对象...
在本文中,我们将深入探讨JavaScript继承机制的实现方式,并对基于原型的继承、构造函数方式继承、组合继承、寄生式继承等继承机制进行了总结归纳和分析。 基于原型的继承 JavaScript是一门基于原型的语言,它不像...
在JavaScript中,面向对象编程是通过构造函数、原型链和继承实现的。继承是面向对象编程的核心概念之一,它允许我们创建一个新对象,该对象继承现有对象的属性和方法。在JavaScript中,实现继承有多种方式,每种方式...
zInherit是一种常用的JavaScript继承实现方式,它通过修改对象的`__proto__`属性来实现继承。`__proto__`指向父对象的原型,从而使得子对象能够访问父对象的属性和方法。但是,`__proto__`并不是所有浏览器都支持的...
javascript中如何实现封装,继承和多态
在JavaScript中,继承是面向对象编程的一个核心概念,它允许我们创建基于现有对象的新对象,同时还能继承其属性和方法。本篇将深入探讨一种实现继承的工具函数方法,主要聚焦于`source.js`文件中可能包含的内容。...
继承是面向对象编程的基本机制之一,它可以实现代码复用、提高编程效率和增强代码的可维护性。 在 JavaScript 中,继承是通过 prototypeChain 来实现的。当我们创建一个对象时,它会自动继承其 prototype 中的所有...
JavaScript支持多种继承实现方式,包括以下四种: 1. **构造函数继承**(Constructor Inheritance) 这种方法通过在子构造函数中调用父构造函数来实现继承。例如,`ArrayList01`的构造函数中,`this.base = ...
在本章中,我们将分析Prototypejs中关于JavaScript继承的实现。 Prototypejs是最早的JavaScript类库,可以说是JavaScript类库的鼻祖。 我在几年前接触的第一个JavaScript类库就是这位,因此Prototypejs有着广泛的...
### JavaScript继承机制原理 #### 一、JavaScript与继承的起源 JavaScript作为一种被广泛使用的脚本语言,最初由Brendan Eich在短短十天内设计完成,并被命名为Mocha,后改为LiveScript,最终确定为JavaScript。...
本文将深入探讨JavaScript继承的实现,并分析其潜在的问题和解决方案。 首先,我们来看混合方式的实现,这是一种常见的继承策略,结合了原型链和构造函数继承。在JavaScript中,对象的属性和方法可以通过原型链进行...
JavaScript继承机制探讨及其应用 JavaScript是一门弱类型语言,具有函数式编程和面向对象编程的特点。随着近几年JavaScript生态圈的发展和成熟,项目的编码量和复杂度也在呈几何级数增长。JavaScript面向对象编程中...
这里我们将深入探讨JavaScript继承的特性以及实践应用。 首先,JavaScript的继承基于原型链。每个对象都有一个`__proto__`属性,指向创建它的构造函数的原型对象。当试图访问对象的一个属性时,JavaScript会沿着...
JavaScript继承的实现方式多样,除了原型链之外,还有如下几种常见方式: 1. **构造函数继承**:通过调用父构造函数来初始化子对象,但不能避免方法重复。 2. **原型链继承**:通过修改子构造函数的原型使其指向父...