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

模仿块级作用域

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是一个在匿名函数私有变量作用域内部,被所有实例所共享的属性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值