任何程序设计语言的程序员都懂得作用域的概念,即某些变量的适用范围。
3.4.1 公用、受保护和私有作用域
在传统的面向对象程序设计中,主要关注于公用和私有作用域。公用作用域中的对象属性可以从对象外部访问,即开发者创建对象的实例后,就可使用它的公用属性。而私有作用域中的属性只能在对象内部访问,即对于外部世界来说,这些属性并不存在。这也意味着如果类定义了私有属性和方法,则它的子类也不能访问这些属性和方法。
最近,另一种作用域流行起来,即受保护作用域。虽然在不同语言中,受保护作用域的应用的规则不同,但一般说来,它都用于定义私有的属性和方法,只是这些属性和方法还能被其子类访问。
对ECMAScript讨论这些作用域几乎毫无意义,因为ECMAScript中只存在一种作用域——公用作用域。ECMAScript中的所有对象的所有属性和方法都是公用的。因此,定义自己的类和对象时,必须格外小心。记住,所有属性和方法默认都是公用的。
许多开发者都在网上提出了有效的属性作用域模式,解决了ECMAScript的这种问题。由于缺少私有作用域,开发者们制定了一个规约,说明哪些属性和方法应该被看作私有的。这种规约规定在属性名前后加下划线。例如:
![]()
这段代码中,属性color是私有的。记住,这些下划线并不改变这些属性是公用属性的事实,它只是告诉其他开发者,应该把该属性看作私有的。
有些开发者还喜欢用单下划线说明私有成员,例如obj._color。
3.4.2 静态作用域并非静态的
静态作用域定义的属性和方法任何时候都能从同一个位置访问。在Java中,类可具有静态属性和方法,无需实例化该类的对象,即可访问这些属性和方法,例如java.net.URLEncoder类,它的函数encode()即是静态方法。
严格说来,ECMAScript并没有静态作用域。不过,它可以给构造函数提供属性和方法。还记得吗,构造函数只是函数。函数是对象,对象可以有属性和方法。例如:
![]()
![]()

这里,方法alternate()实际上是函数sayHi的方法。可以像调用常规函数一样调用sayHi()输出"hi",也可以调用sayHi.alternate()输出"hola"。即使如此,alternate()也是sayHi()公用作用域中的方法,而不是静态方法。
3.4.3 关键字this
在ECMAScript中,要掌握的最重要的概念之一是关键字this的用法,它用在对象的方法中。关键字this总是指向调用该方法的对象,例如:
![]()

这里,关键字this用在对象的showColor()方法中。在此环境中,this等于car,下面的代码与上面代码的功能相同:
![]()

那么为什么使用this呢?因为在实例化对象时,总是不能确定开发者会使用什么样的变量名。使用this,即可在任意多个地方重用同一个函数。考虑下面的例子:
![]()

在这段代码中,首先用this定义函数showColor(),然后创建两个对象(oCar1和oCar2),一个对象的color属性被设置为"red",另一个对象的color属性被设置为"blue"。两个对象都被赋予了属性showColor,指向原始的showColor()函数(注意这里不存在命名问题,因为一个是全局函数,而另一个是对象的属性)。调用每个对象的showColor()方法,oCar1的输出"red",而oCar2的输出"blue"。这是因为调用oCar1.showColor()时,函数中的this关键字等于oCar1,调用oCar2.showColor()时,函数中的this关键字等于oCar2。
注意,引用对象的属性时,必须使用this关键字。例如,如果采用下面的代码,showColor()方法不能运行:
![]()
如果不用对象或this关键字引用变量,ECMAScript就会把它看作局部变量或全局变量。然后该函数将查找名为color的局部或全局变量,但是不会找到的。结果如何?该函数将在警告中显示"null"。







