《JavaScript高级程序设计》学习笔记(对象3)
面向对象术语
ECMA-262把对象(object)定义为“属性的无序集合,每个属性存放一个原始值、对象或函数”。严格说来,这意味着对象是无特定顺序的值的数组。
每个对象都由类定义,可以把类看作对象的配方。类不仅要定义对象的接口(interface)(开发者访问的属性和方法),还要定义对象的内部工作(使属性和方法发挥作用的代码)。编译器和解释程序都根据类的说明构建对象。
程序使用类创建对象时,生成的对象叫做类的实例(instance)。
由类创建对象实例的过程叫做实例化(instantiation)。
如第2章所述,ECMAScript并没有正式的类。相反,ECMA-262把对象定义描述为对象的配方。这是ECMAScript的一种逻辑上的折中方案,因为对象定义实际上是对象自身。
对象定义存放在一个函数——构造函数中。构造函数不是一种特殊函数,它只不过是用于创建对象的常规函数。
面向对象语言
面向对象语言四种基本能力:
(1) 封装——把相关的信息(无论数据或方法)存储在对象中的能力。
(2) 聚集——把一个对象存储在另一个对象内的能力。
(3) 继承——由另一个类(或多个类)得来类的属性和方法的能力。
(4) 多态——编写能以多种方法运行的函数或方法的能力。
ECMAScript支持这些要求,因此可被看作面向对象的。
对象的构成
在ECMAScript中,对象由特性(attribute)构成,特性可以是原始值,也可以是引用值。
如果特性存放的是函数,它将被看作对象的方法(method),否则该特性被看作属性(property)。
对象应用
对象的创建或销毁都在JavaScript执行过程中发生
声明和实例化
对象是用关键字new后跟要实例化的类的名字创建的
例如:
var myObject = new Object(); // 创建没有属性的通用对象。
var myBirthday = new Date(1961, 5, 10); // 创建一个 Date 对象。
var myCar = new Car(); // 创建一个用户定义的对象,并初始化其属性。
如果构造函数无参数,括号则不是必需的
例如:
var myObject = new Object;
对象引用
在ECMAScript中,不能访问对象的物理表示,只能访问对象的引用。
每次创建对象,存储在变量中的都是该对象的引用(类似指针),而不是对象本身。
对象废除
ECMAScript有无用存储单元收集程序,意味着不必专门销毁对象来释放内存。
当再没有对对象的引用时,称该对象被废除(dereference)了。
运行无用存储单元收集程序时,所有废除的对象都被销毁。每当函数执行完它的代码,无用存储单元收集程序都会运行,释放所有的局部变量,还有在一些其他不可预知的情况下,无用存储单元收集程序也会运行。
把对象的所有引用都设置为null,可以强制性的废除对象。
例如:
var myObject = new Object;
myObject = null;
当变量myObject设置为null后,对第一个创建的对象的引用就不存在了。
这意味着下次运行无用存储单元收集程序时,该对象将被销毁。
每用完一个对象后,就将其废除,来释放内存,这是个好习惯。废除对象和它的所有特性是确保内存使用正确的最好方法。
注意:废除对象的所有引用时要当心。如果一个对象有两个或更多引用,则要正确废除该对象,必须将其所有引用都设置为null。
早绑定和晚绑定
绑定(binding),即把对象的接口与对象实例结合在一起的方法。
早绑定(early binding)是指在实例化对象之前定义它的特性和方法,这样编译器或解释程序就能提前转换机器代码。ECMAScript不是强类型语言,所以不支持早绑定。
晚绑定(late binding)指的是编译器或解释程序在运行前,不知道对象的类型。
使用晚绑定,无需检查对象的类型,只需要检查对象是否支持特性和方法即可。ECMAScript中的所有变量都采用晚绑定方法,这样就允许执行大量的对象操作,而无任何惩罚。
在ECMAScript中,所有对象并非同等创建的。一般说来,可以创建并使用的对象有三种。
本地对象:独立于宿主环境的ECMAScript实现提供的对象
内置对象:由ECMAScript实现提供的、独立于宿主环境的所有对象,在ECMAScript程序开始执行时出现
宿主对象:由ECMAScript实现的宿主环境提供的对象。所有BOM和DOM对象都是宿主对象,所有非本地对象都是宿主对象
作用域
某些变量的适用范围。
1 公用、受保护和私有作用域
公用作用域中的对象属性可以从对象外部访问,即开发者创建对象的实例后,就可使用它的公用属性。
私有作用域中的属性只能在对象内部访问,即对于外部世界来说,这些属性并不存在。这也意味着如果类定义了私有属性和方法,则它的子类也不能访问这些属性和方法。
受保护作用域,一般说来,它都用于定义私有的属性和方法,只是这些属性和方法还能被其子类访问。
ECMAScript中只存在公用作用域。ECMAScript中的所有对象的所有属性和方法都是公用的。因此,定义自己的类和对象时,必须格外小心。记住,所有属性和方法默认都是公用的。
2 静态作用域并非静态的
静态作用域定义的属性和方法任何时候都能从同一个位置访问。
严格说来,ECMAScript并没有静态作用域。不过,它可以给构造函数提供属性和方法。
因为构造函数是函数,函数是对象,对象可以有属性和方法。
例如:
function msg(){alert("hello");}
msg.hi = function(){alert("hi");}
msg();
msg.hi();
这里,方法hi()实际上是函数msg的方法。调用msg()将输出"hello",调用msg.hi()将输出"hi"。
即使如此,hi()也是msg()公用作用域中的方法,而不是静态方法。
3 关键字this
关键字this总是指向调用该方法的对象
this.property
例如:
function Car(color){
this.color = color;
}
var new_car= new Car("red");
alert(new_car.color);
这里this指的是新创建的Car对象,并给属性赋值
在实例化对象时,很多时候不能确定开发者会使用什么样的变量名。
使用this,即可在任意多个地方重用同一个函数。
例如:
function msg(){alert(this.value);}
var a = new Object;
a.value = "a"
a.msg = msg;
var b = new Object;
b.msg = msg;
b.value = "b"
a.msg();
b.msg();
如果不用对象或this关键字引用变量,ECMAScript就会把它看作局部变量或全局变量。