JS之 函数模仿块级作用域,私有变量,模块模式
模仿块级作用域
Javascript没有块级作用域的概念,意味着在块级语句中定义的变量,实际上是在包含函数中而非语句中创建的,看下面例子:
function a() { for (var i = 0; i < 2; i++) { alert(i);// 0,1 } alert(i); //2 }
在c#中,上述 i的作用域仅在 for循环之内,在之外 调用该变量将会报错.但是 javascript中却不会,它从来不会告诉你是否多次声明
同一个变量,它只会对后续的声明视而不见,但是 会执行后续声明中的初始化.看下面例子:
function a() { for (var i = 0; i < 2; i++) { alert(i);// 0,1 } var i = 10; alert(i); //10 }
匿名函数可以 用来模仿块级作用域(私有作用域) 并且避免上述问题. 下面看个例子:
(function a() { (function () { for (var i = 0; i < 2; i++) { alert(i);// 0,1 } })(); alert(i); //导致一个错误 })();
整个重写了a()函数,在for循环中插入一个私有作用域,在匿名函数中定义的变量,在执行完毕后,将会被销毁.
因此,变量i只能在for循环中 被访问.
私有变量
严格来讲,javascript中 没有私有成员的概念所有对象属性都是公有的.倒是有私有变量的概念.
任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问它们. 私有变量包括:参数,局部变量,
和在函数内部定义的其它函数.
我们可以利用闭包,创建 用于访问私有变量的公有方法.因为闭包可以通过 作用域链来访问 函数内部的所有变量.
把有权访问私有变量的公有方法 承做 特权方法 ,有两种在对象上创建特权方法的模式的方法:
1:
function object() { var privateVarible = 10; //私有变量 function privateFunction() { //私有方法 return privateVarible; }; //特权方法 this.publicMethod = function () { privateVarible++; return privateFunction(); } } var o = new object(); alert(o.privateVarible); //undefined alert(o.privateFunction()); //报错 alert(o.publicMethod()); //11
2: 可以利用私有和特权成员,来隐藏那些不应该被直接修改的成员:代码如下:
function person(name) { this.getName = function () { return name }; this.setName = function (value) { name = value }; } var p = new person("gao"); alert(p.name); //undefined alert(p.getName()); //gao p.setName("newgao"); alert(p.getName()); //newgao
在构造函数中定义 特权方法,有一个不好的地方就是,每次实例化的时候,都会同样创建一组新方法, 那么就可以使用
静态私有变量来实现特权方法.
静态私有变量
通过在私有作用域中定义私有变量或函数,同样也可以创建特权方法,基本模式如下:
(function () { //私有变量和私有函数 var privateVarible = 10; function privateFunction() { return false; } //构造函数 myObject = function () { }; //没使用var因为 要创建一个全部变量,而不是局部变量,这个外界才能调到构造函数 //公有/特权方法 myObject.prototype.publicMethod = function () { privateVarible++; return privateFunction(); } })(); var o = new myObject(); alert(o.publicMethod()); //false
这特权方法定义在 原型上,是典型的原型模式. 这样每个实例就可以共享这个 特权函数,而不必,没新建一个实例,
就实例化一个 特权函数对象.但是也有一个问题,就是 每个实例都共享函数和属性,那么每个实例就没有了自己独有的属性,看例子:
(function () { var name = ""; Person = function (value) { //定义构造函数 name = value; }; //定义特权方法 Person.prototype.getName = function () { return name; }; //闭包总是保存着包含作用域的引用 Person.prototype.setName = function (value) { name = value; }; })(); var p = new Person("gao"); alert(p.getName()); //gao var p2 = new Person("gao2"); alert(p.getName()); //gao2 p.setName("gao3"); alert(p2.getName()); //gao3
无论是新实例化对象,修改已有对象的name属性,都会导致 所有实例的name属性发生变化.这就是原型模式的不足之处.