JavaScript 中没有块级作用域的概念
因为没有块级作用域,所以该函数可以直接运行,而不报错。
这里有个比较有意思的是,重写声明变量 i, 不会报错,而且也不会改变变量i的值。
JavaScript 中不会提示用户声明同一个变量,遇到这种情况,它只会对后续的声明视而不见。
匿名函数可以模仿块级作用域,避免在块级后使用块级中的变量
模仿块级作用域中匿名函数的语法如下:
(function( ){
//这里是块级作用域
})( );
以上代码定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号表示立即调用这个函数。
另一种表现形式:定义函数的形式来创建
var someFunction = function( ){
//这里是块级作用域
}
someFunction( )
函数表达式后加上()立即执行该函数。
function( ){ } 为一个函数声明,声明后面不能跟圆括号,即function( ) { } ( ) 会出错。
将函数声明加上圆括号 即 (function( ){ }) 为函数表达式,在加上()会立即执行该函数表达式。
采用闭包模仿块级作用域的好处
可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链。
私有变量
严格说,JavaScript中没有私有成员的概念,所有的对象属性都是公有的。但是具有私有变量的概念。任何在函数中定义的变量,都可以认为是私有变量,函数外部不可以访问这些变量。私有变量包括函数的参数,局部变量和在函数内部定义的其他函数。
因为在函数内部可以访问这些私有变量,函数外部不可以访问。可以利用闭包的特性,在函数内部创建一个闭包,闭包通过自己的作用域链中可以访问这些变量。所以可以实现创建用于访问私有变量的公有方法。
特权方法
有权访问私有变量和私有函数的公有方法称为特权方法。
有两种方式可以创建特权方法
1.构造函数中定义特权方法
以上代码的构造函数中定义了一个特权方法:publicFunction( )。这个方法可以在构造函数外部使用。而且有权访问私有变量 privateNum 和私有方法privateFunction。在构造函数外部,没有办法访问私有变量和私有方法。
变量privateNum 和函数 privateFunction 在MyFunctionObject中每个实例都不相同,因为每次调用构造函数都会重写创建这个变量和方法。构造函数中定义的特权方法的缺点是,必须使用构造函数模式来达到这个目的,针对每个实例都会创建同一组新方法。可以使用静态私有变量来实现特权方法避免这个问题。
静态私有变量
通过私有作用域中定义私有变量和函数,同样可以创建特权方法
该模式创建了一个私有作用域,并在其中封装了一个构造函数,及相应的方法。
在私有作用域中首先定义私有变量,然后定义构造函数,注意,这个地方定义构造函数并没有使用函数声明,而是使用函数表达式,函数声明只能创建局部变量不是我们想要的。同时在声明Person没有使用Var,可以自动添加到全局变量中。公有方法是在原型上定义的。由于原型上的定义方法,所有的实例都使用同一个函数,而这个特权方法,作为一个闭包,总是保存着对包含作用域的引用。
可以看出这种方式创建静态私有变量会因为使用原型而增进代码复用,但每个实例都没有自己的私有变量。
模块模式
道格拉斯所说的模块模式是为单例创建私有变量和特权方法。 JavaScript是以对象字面量的方式创建单例对象。