您的位置:首页 > Web前端 > JavaScript

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

2017-10-19 12:08 441 查看

模仿块级作用域

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是一个在匿名函数私有变量作用域内部,被所有实例所共享的属性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  函数