定义类或对象
1 工厂方式
对象的属性可在对象创建后动态定义
问题是可能需要创建多个car实例。
所有这些问题引发了开发者定义的构造函数的出现。
2 构造函数方式
在构造函数内部无创建对象,而是使用this关键字。
现在,用new运算符和类名car创建对象,就更像创建ECMAScript中一般对象了。你也许会问,这种方式在管理函数方面是否存在与前一种方式相同的问题呢?是的。
就像工厂函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。
3 原型方式
该方式利用了对象的prototype属性,可把它看成创建新对象所依赖的原型。
这里,用空构造函数来设置类名。
然后所有的属性和方法都被直接赋予prototype属性。
首先,这个构造函数没有参数。使用原型方式时,不能通过给构造函数传递参数初始化属性的值,
因为car1和car2的color属性都等于"red",doors属性都等于4,mpg属性都等于23。
这意味必须在对象创建后才能改变属性的默认值,这点很令人讨厌,但还不至于是世界末日。
真正的问题出现在属性指向的是对象,而不是函数时。
函数共享不会造成任何问题,但对象却很少被多个实例共享的。
由于创建对象时有这么多问题,你一定会想,是否有种合理的创建对象的方法呢?答案是联合使用构造函数和原型方式。
4 混合的构造函数/原型方式
联合使用构造函数和原型方式,就可像用其他程序设计语言一样创建对象。
这种概念非常简单,即
用构造函数定义对象的所有非函数属性,
用原型方式定义对象的函数属性(方法)。
function Car (sColor, iDoors, iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","Sue");
}
Car.prototype.showColor = function(){
alert(this.color);
};
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("black", 5, 24);
oCar1.drivers.push("Matt");
alert(oCar1.drivers);//outputs Mike Sue Matt
alert(oCar2.drivers);//outputs Mike Sue
这种方式是ECMAScript主要采用的方式,它具有其他方式的特性,却没有它们的副作用。不过,有些开发者仍觉得这种方法不够完美。
5 动态原型方法
动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。
function Car (sColor, iDoors, iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","Sue");
if(typeof Car._initialized == "undefined"){
Car.prototype.showColor = function(){
alert(this.color);
};
}
}
直到检查typeof Car._initialized是否等于"undefined"之前,这个构造函数都未发生变化。
这行代码是动态原型方法中最重要的部分。
如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把Car._initialized设置为true。
如果这个值定义了(它的值为true时,typeof的值为Boolean),那么就不再创建该方法。
简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。
该方法只创建并赋值一次,为取悦传统的OOP开发者,这段代码看起来更像其他语言中的类定义了。
6 混合工厂方式
这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。
这种方式在对象方法的内部管理方面与经典方式有着相同的问题。
强烈建议:除非万不得已(请参阅第15章),还是避免使用这种方式。
7 采用哪种方式
如前所述,目前使用最广泛的是混合的构造函数/原型方式。
此外,动态原型方法也很流行,在功能上与构造函数/原型方式等价。
可以采用这两种方式中的任何一种。
不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。
8 实例
对象令人感兴趣的一点是用它们解决问题的方式。ECMAScript中最常见的一个问题是字符串连接的性能。
与其他语言类似,ECMAScript的字符串是不可变的,即它们的值不能改变。考虑下面的代码:
var str = "hello";
str += "world";
实际上,这段代码在幕后执行的步骤如下:
(1) 创建存储"hello"的字符串。
(2) 创建存储"world"的字符串。
(3) 创建存储连接结果的字符串。
(4) 把str的当前内容复制到结果中。
(5) 把"world"复制到结果中。
(6) 更新str,使它指向结果。
每次完成字符串连接都会执行步骤2到6,使得这种操作非常消耗资源。如果重复这一过程几百次,甚至几千次,就会造成性能问题。
解决方法是用Array对象存储字符串,然后用join()方法(参数是空字符串)创建最后的字符串。想像用下面的代码代替前面的代码:
var arr = new Array();
arr[0] = "hello";
arr[1] = "world";
var str = arr.join("");
这样,无论在数组中引入多少字符串都不成问题,
因为只在调用join()方法时才会发生连接操作。
此时,执行的步骤如下:
(1) 创建存储结果的字符串。
(2) 把每个字符串复制到结果中的合适位置。
虽然这种解决方法很好,但还有更好的方法。
问题是这段代码不能确切反映出它的意图。要使它更容易理解,可以用StringBuffer类打包该功能:
function StringBuffer(){
this._strings_ = new Array;
}
StringBuffer.prototype.append = function(str){
this._strings_.push(str);
};
StringBuffer.prototype.toString = function(){
return this._strings_.join("");
};
第一点要注意的是,这段代码是strings的属性,本意是私有属性。
它只有两个方法,即append()和toString()方法。
append()方法有一个参数,它把该参数附加到字符串数组中,
toString()方法调用数组的join()方法,返回真正连接成的字符串。
要用StringBuffer对象连接一组字符串,可以用下面的代码:
var buffer = new StringBuffer();
buffer.append("hello");
buffer.append("world");
alert(buffer.toString());
可用下面代码测试StringBuffer对象和传统的字符串连接方法的性能:
这段代码对字符串连接进行两个测试,第一个使用加号,第二个使用StringBuffer类。每个操作都连接10000个字符串。日期值d1和d2用于判断完成操作需要的时间。记住,创建新Date对象时,如果没有参数,赋予对象的是当前的日期与时间。要计算连接操作历经多少时间,把日期的毫秒表示(getTime()方法的返回值)相减即可。这是衡量JavaScript性能的常用方法。该测试的结果应该说明使用StringBuffer类比使用加号节省了100%~200%的时间。
分享到:
相关推荐
NULL 博文链接:https://shaw-n-lu.iteye.com/blog/1881210
Window对象 窗口操作 Window对象对操作浏览器窗口非常有用,开发者可以移动或调整浏览器窗口的大小。可用四种方法实现这些操作: moveBy(dx,dy):把浏览器窗口相对当前位置水平移动dx个像素,垂直移动dy个像素。...
继承是面向对象语言的必备特征,即一个类能够重用另一个类的方法和属性。在JavaScript中继承方式的实现方式主要有以下五种:对象冒充、call()、apply()、原型链、混合方式
ECMAScript中的引用类型,主要包括Object类、Boolean类、Number类、String类、instanceof运算符
js定义类或对象的介绍,需要的朋友可以参考下
l ECMAScript,有ECMA-262定义,明确javascript这门语言的规则和约定,好比为开始一场游戏指定的游戏规则、规范、约定。 l DOM:提供访问和操作网页内容的方法和接口 l BOM,提供与浏览器交互的方法和接口 ECMA-262规定...
Function类 定义 Function类可以表示开发者定义的任何函数,用Function类直接创建函数的语法如下: var function_name=new Function(agrument1,agrument2,…,argumentN,function_body); 每个argument都是一个参数,...
内置对象 定义:由ECMAScript实现提供的、独立于宿主环境的所有对象,在ECMAScript程序开始执行时出现。 由定义可知开发者不必明确实例化内置对象,它已被实例化了。在ECMAScript-262只定义了两个内置对象,即Global...
要注意的是在JavaScript中月份的值是从0到11(0表示1月)。 设置日期和时间值 设置日期和时间值有两种方法: 1、只声明距离1970年1月1日凌晨12点的毫秒数 a、直接用距离1970年1月1日凌晨12点的毫秒数 var d=new Date...
创建Array对象 代码如下: //one var aValues=new Array(); //two var aValues=new Array(20); //three var aColors=new Array(); aColors[0]=”red”; aColors[1]=”green”; aColors[2]=”blue”;...
一、事件流 IE中是冒泡型事件,即从最特定的事件目标到最不特定的事件... 如果在JavaScript中分配事件处理函数,则首先要获得要处理的对象的引用,然后将函数赋值给对应的事件处理函数属性,像这样(事件处理函数名称
一、错误分类 1、语法错误:也称解析错误,发生在传统语言的编译时,在JavaScript中发生在解释时。这些错误是由代码中的意外字符直接引起的,然后就不能直接编译/解释。发生语法错误时,就不能继续执行代码。在...
一、IE中的XML DOM支持 IE对XML的支持是基于ActiveX的MSXML库。 1、DOM创建 对每个新版本的MSXML,都会创建出不同的XML DOM对象,所以尽量选择新的XML DOM版本。 2、载入XML 载入XML分两种,即: 载入XML字符串:...