JS:模仿块级作用域及私有变量

来源:互联网 发布:js设置css样式display 编辑:程序博客网 时间:2024/05/16 05:29

模仿块级作用域

JavaScript没有块级作用域
例如:

function outputNumber(){    for(var i = 0;i<count;i++){         alert(i);     }     alert(i);}

函数中定了一个for循环,在Java,C++等语言中,变量i只在for循环语句中有定义,循环一旦结束,变量就会被销毁。可是在JavaScript中,变量i是定义在outputNumber()活动对象中的,因此,从它有定义开始,就可以在函数内部随处访问它。即使像下面这样错误的重新声明同一个变量,也不会改变它的值。

function outputNumbers(count){           for(var i = 0;i<count;i++){            console.log(i);           }           var i;           alert(i);//5        }        outputNumbers(5)

JS从来不会告诉你是否多次声明了同一个变量;遇到这种情况,它只会对后续的声明视而不见(但是如果对i进行重新赋值,i的值会发生变化)。匿名函数可以用来模仿块级作用域并且避免这个问题。
用作块级作用域的(通常称为私有作用域)的匿名函数的语法如下所示:

(function(){  //这里是块级作用域})();

无论在什么地方,只要临时需要一些变量,就可以使用私有作用域,例如将上文中提到的代码修改为:

function outputNumbers(count){        (function(){           for(var i = 0;i<count;i++){            console.log(i);           }         })();         console.log(i);// i is not defined at outputNumbers        }        outputNumbers(5)

在这个重写的函数内部,我们在for循环外部插入了有个私有作用域。在匿名函数中定义的任何变量,都会在执行结束的时候销毁。因此变量i只能在循环内部引用,不能再for循环外部引用,使用之后立即被销毁。而私有作用域能够访问变量count,是因为这是一个匿名函数闭包,它能够访问包含作用域中的所有变量。
这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。要做到尽量少向全局作用域中添加变量和函数。在一个有多人共同参与开发的项目中,过多的全局变量可能会导致命名冲突。通过创建私有变量作用域可以解决这个问题:
例如:

(function(){            var now = new Date();            if(now.getMoth() == 0&&now.getDate() == 1){                alert("Haapy new year!");            }        })();

在新年的时候向用户发送新年祝福,其中变量now现在是匿名函数中的局部变量,而我们不必在全局作用域中创建它。

私有变量

在任何函数中定义的变量都可以认为是私有变量,因为不能再函数外部访问这些变量,私有变量包括函数参数,局部变量和函数内部定义的其他函数。
我们可以在函数内部创建一个闭包,那么我们就可以通过闭包函数的作用域链访问这些私有变量。利用这一点我们就可以创建用于访问私有变量的公有方法。
例如:

function MyObject(){            //私有变量和私有函数            var privateVariable = 10;            function privateFunction(){                return false;            }            //特权方法            this.publicMethod = function(){                privateVariable++;                return privateFunction();            }        }

这个模式在构造函数内部定义了所有私有变量和函数,然后又继续创建了能够访问这些私有成员的特权方法。在构造函数中定义特权方法,特权方法作为闭包有权访问在构造函数中定义的所有变量和函数。对于这个例子而言,变量privateVariable和函数privateFunction()只能通过特权方法publicMethod()来访问。
利用私有成员和特权成员,可以隐藏那些不应该直接被修改的数据,例如:

 function Person(name){            this.getName = function(){                return name;            };            this.setName = function(value){                name = value;            };        }        var person3 = new Person("Bob");        alert(person3.getName());//Bob        var person4 = new Person("Marry");        alert(person4.getName());//Marry

以上构造函数中定义了两个特权方法:getName()和setName()。这两个函数都可以在构造函数外部使用,而且有权访问到私有变量name。在Person构造函数外部没有任何方法可以访问到这个变量,但是特权方法作为闭包可以通过其作用域链访问到这个变量。私有变量在Person的每一个实例都不同,因为每次调用构造函数都会重新创建这两个方法。

静态私有变量

通过在私有作用域中定义私有变量或函数,同样也可以创建特权方法,其基本模式如下:

(function(){   //私有变量和私有函数   var privateVariable = 10;   function privateFunction(){        return false;   }   //构造函数   MyObject = function(){};//没有使用var 声明,可以在全局执行环境中访问到   //公有/特权方法   MyObject.prototype.publicMethod = function(){           privateVariable++;           return privateFunction();   };})();

这个模式与构造函数中定义的特权方法的主要区别在于:
私有变量和函数是由实例所共享的,即私有作用域中的privateVariable和函数privateFunction()是由所有实例所共享的。
下面举例具体说明:

        (function(){            var name = "";            Person = function(value){                name = value;            };            Person.prototype.getName = function(){                return name;            };            Person.prototype.setName = function(value){                name = value;            };        })();        var person1 = new Person("Bob");        alert(person1.getName());//Bob        var person2 = new Person("Marry");        alert(person1.getName());//Marry        alert(person2.getName());//Marry

这里的name变成了一个静态的由所有实例共享的属性。
具体分析:当实例化对象person2时,传入的value的值为”Marry”,value的值被赋给name,这是实例person1调用此方法输出的是name的值,此时name的值已经被修改为”Marry”,所以说name是一个在匿名函数私有变量作用域内部,被所有实例所共享的属性。

原创粉丝点击