截取自读书频道
http://book.csdn.net/bookfiles/110/index.htm
3。1面向对象术语
3。1。1面向对象语言的要求
A封装:把相关信息存储在对象中的能力
B聚集:把一个对象存储在另一个对象中的能力
C继承:由另一个类(多个类)得到类的属性和方法的能力
D多态:编写能以多种方法运行函数或方法的能力
3。1。2对象的构成
在ECMAScript中,对象由特性(attribute)构成,特性可以是原始值,也可以是引用值如果特性存放的是函数,它将被看作是对象的方法(method),否则该特性被看作属性(property)
3。2对象应用
3。2。1声明和实例化
和java一样用new .不同的是:如果没有参数,可以不要括号
3。2。2对象引用
和java一样,直接使用的都是对象的引用
3。2。3对象废除
也有垃圾收集,将引用赋予null既可执行垃圾收集
3。2。4早绑定和晚绑定
早绑定(early binding)是指在对象实例化之前定义对象的特性和方法。这样编译器或解释程序就可以提前转换机器代码
晚绑定(late binding)指编译器或解释程序在运行前不知道对象的类型,ECMAScript中所有的变量都采用晚绑定
3。3对象的类型:本地对象(1)
ECMAScript中可以创建并使用的对象有3种:
3。3。1本地对象
ECMA-262把本地对象定义为“独立于宿主环境的ECMAScript实现提供的对象”。简单说来,本地对象就是ECMA-262定义的类(引用类型)。它们包括:
![](https://i-blog.csdnimg.cn/blog_migrate/cc952f36b0ccc1ce206efd0deee1b4c1.png)
1. Array类
和java不同,可以创建Array的对象,且实例化Array不用设置初始大小,Array甚至可以自动增长。这是弱类型语言晚绑定的一个特定。
toStirng(),valueOf(),join()方法:Array-->String
split():String-->Array
Array类的一个有趣之处是它提供的方法使数组的行为与其他数据类型的行为相似。Array对象提供了两个方法push()和pop()。使它像一个栈,栈又叫做后进先出(LIFO)结构。push()方法用于在Array结尾添加一个或多个项,pop()方法用于删除最后一个数组项(length-1),返回它作为函数值。
方法shift()将删除数组中的第一个项,将其作为函数值返回。unshift()方法,它把一个项放在数组的第一个位置,然后把余下的项向下移动一个位置。通过调用shift()和push()方法,可以使Array对象具有队列一样的行为。队列又叫做后进后出(LILO)结构。
reverse()方法颠倒数组项的顺序。sort()方法将根据数组项的值按升序为它们排序。要进行这种排序,首先调用toString()方法,将所有值转换成字符串,然后根据字符代码比较数组项
2. Date类
ECMAScript中的Date类基于Java中的java.util.Date类的早期版本。与Java一样,ECMAScript把日期存储为距离UTC时间1970年1月1日凌晨12点的毫秒数。
parse()和UTC()方法。这两种方法以字符串为参数,由ECMAScript的实现特定,通常是地点特定的。
3。3。2内置对象
ECMA-262把内置对象(built-in object)定义为“由ECMAScript实现提供的、独立于宿主环境的所有对象,在ECMAScript程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262只定义了两个内置对象,即Global和Math。
1. Global对象
Global对象是ECMAScript中最特别的对象,因为实际上它根本不存在。它只是做为isNaN()、isFinite()、parseInt()和parseFloat()等类似方法的载体。
encodeURI()和encodeURIComponent()方法用于编码传递给浏览器的URI(统一资源标识符)。有效的URI不能包含某些字符,如空格。
encodeURI()方法用于处理完整的URI(例如,http://www.wrox.com/illegal value.htm),而encodeURIComponent()用于处理URI的一个片断(如前面的URI中的illegal value.htm)。这两个方法的主要区别是encodeURI()方法不对URI中的特殊字符进行编码,如冒号、前斜杠、问号和英镑符号,而encodeURIComponent()则对它发现的所有非标准字符进行编码。
用于解码编码过的URI,即decodeURI()和decodeURIComponent()。
eval()方法。该方法就像整个ECMAScript的解释程序,接受一个参数,即要执行的ECMAScript(或JavaScript)字符串。
当解释程序发现eval()调用时,它将把参数解释为真正的ECMAScript语句,然后把它插入该函数所在的位置。这意味着eval()调用内部引用的变量可在参数以外定义:
2. Math对象
Math对象有几个属性,主要是数学界的专用值。还包括许多专门用于执行简单的及复杂的数学计算的方法。
3。3。3宿主对象
所有非本地对象都是宿主对象(host object),即由ECMAScript实现的宿主环境提供的对象。所有BOM和DOM对象都是宿主对象
3。4作用域
3.4.1 公用、受保护和私有作用域
ECMAScript中只存在一种作用域——公用作用域。ECMAScript中的所有对象的所有属性和方法都是公用的。
3.4.2 静态作用域并非静态的
3.4.3 关键字this
3。5定义类或对象
由于对象的属性可在对象创建后动态定义,所以许多开发者都在初次引入JavaScript时编写类似下面的代码:
执行这段代码后,就可以使用对象car。问题是可能需要创建多个car实例。
要解决此问题,开发者创造了能创建并返回特定类型的对象的工厂函数(factory function)。例如,函数createCar()可用于封装前面列出的创建car对象的操作:
虽然ECMAScript越来越正式化,创建对象的方法却被置之不理,且其规范化至今还遭人反对。一部分是语义上的原因(它看起来不像使用带有构造函数的new运算符那么正规),一部分是功能上的原因。功能问题在于用这种方式必须创建对象的方法。前面的例子中,每次调用函数createCar(),都要创建新函数showColor(),意味着每个对象都有自己的showColor()版本,事实上,每个对象都共享了同一个函数。
有些开发者在工厂函数外定义对象的方法,然后通过属性指向该方法,从而避开这个问题:
3.5.2 构造函数方式
构造函数看起来很像工厂函数。考虑下面的例子:
你可能已经注意到第一个差别了,在构造函数内部无创建对象,而是使用this关键字。使用new运算符调用构造函数时,在执行第一行代码前先创建一个对象,只有用this才能访问该对象。然后可以直接赋予this属性,默认情况下是构造函数的返回值(不必明确使用return运算符)。
就像工厂函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。不过,与工厂函数相似,也可以用外部函数重写构造函数,同样的,语义上无任何意义。这就是原型方式的优势所在。
3.5.3 原型方式
该方式利用了对象的prototype属性,可把它看成创建新对象所依赖的原型。这里,用空构造函数来设置类名。然后所有的属性和方法都被直接赋予prototype属性。重新前面的例子,代码如下所示:
在这段代码中,首先定义构造函数(Car),其中无任何代码。接下来的几行代码,通过给Car的prototype属性添加属性定义Car对象的属性。调用new Car()时,原型的所有属性都被立即赋予要创建的对象,意味着所有Car实例存放的都是指向showColor()函数的指针。从语义上讲,所有属性看起来都属于一个对象,因此解决了前面两种方式的两个问题。此外,使用该方法,还能用instanceof运算符检查给定变量指向的对象的类型。
这个构造函数没有参数。使用原型方式时,不能通过给构造函数传递参数初始化属性的值,因为car1和car2的color属性都等于"red",doors属性都等于4,mpg属性都等于23。这意味必须在对象创建后才能改变属性的默认值
真正的问题出现在属性指向的是对象,而不是函数时。函数共享不会造成任何问题,但对象却很少被多个实例共享的。而原形方法中的对象是被共享的。
3.5.4 混合的构造函数/原型方式
联合使用构造函数和原型方式,就可像用其他程序设计语言一样创建对象。即用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法)。结果所有函数都只创建一次,而每个对象都具有自己的对象属性实例。再重写前面的例子,代码如下:
所有的非函数属性都在构造函数中创建,意味着又可用构造函数的参数赋予属性默认值了。因为只创建showColor()函数的一个实例,所以没有内存浪费。由于使用了原型方式,所以仍然能利用instanceof运算符判断对象的类型。这种方式是ECMAScript主要采用的方式,它具有其他方式的特性,却没有它们的副作用。
3.5.5 动态原型方法
动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。下面是用动态原型方法重写的Car类:
直到检查typeof Car._initialized是否等于"undefined"之前,这个构造函数都未发生变化。这行代码是动态原型方法中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把Car._initialized设置为true。如果这个值定义了(它的值为true时,typeof的值为Boolean),那么就不再创建该方法。简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。
3.5.6 混合工厂方式
这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。这段代码看来与工厂函数非常相似:
与经典方式不同,这种方式使用new运算符,使它看起来像真正的构造函数:
由于在Car()构造函数内部调用了new运算符,所以将忽略第二个new运算符(位于构造函数之外)。在构造函数内部创建的对象被传递回变量var。
3.5.7 采用哪种方式
如前所述,目前使用最广泛的是混合的构造函数/原型方式。此外,动态原型方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。
3.5.8 实例
3。6修改对象
3.6.1 创建新方法
可以用prototype属性为任何已有的类定义新方法,就像处理自己的类一样。例如,Number类的toString()方法,如果给它传递16,它将输出十六进制的字符串。用toHexString()方法处理这个操作不是更好吗?创建它很简单:
3.6.2 重定义已有方法
就像能给已有的类定义新方法一样,也可重定义已有的方法。如前一章所述,函数名只是指向函数的指针,因此可以轻易地使它指向其他函数。被重写的方法被无用存储单元回收程序回收,因为它被完全废弃了。所以在覆盖原始方法前,存储它的指针比较安全,以便以后的使用。
3.6.3 极晚绑定
从技术上来说,根本不存在极晚绑定。本书采用该术语描述ECMAScript中的一种现象,即能够在对象实例化后再定义它的方法。例如:
JavaScript 中对象和类的很多行为和特点和java相关太大了。这部分比较难接受,我觉得它的动态可扩展和弱类型的特性比较突出