一、JavaScript作用域
执行环境是JavaScript中最为重要的一个概念。
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。
每个执行环境都有一个与之关联的变量对象,就好比全局的window可以调用变量和属性一样。
局部的环境也有一个类似window的变量对象,环境中定义的所有变量和函数都保存在这个对象中。(我们无法访问这个变量对象,但解析器会处理数据时后台使用它)
当执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。如果是全局环境下,需要程序执行完毕,或者网页被关闭才会销毁。
1.全局执行环境
全局执行环境是最外围的执行环境。在Web浏览器中,全局执行环境被认为是window对象。因此所有的全局变量和函数都是作为window对象的属性和方法创建的。
var color = 'blue';
function setColor (value){
color = value;
}
setColor('yellow');
//window.setColor('yellow');//这样写也是可以的,全局的变量就是window对象的属性。
alert(color);
//alert(window.color);//这样写也是可以的,全局的函数就是window对象的方法。
2.函数里的局部作用域
当变量名相同时,局部变量会屏蔽全局变量。会先从局部作用域内寻找变量,如果在局部作用域内没有声明则去全局寻找。
函数的参数也是局部变量。
var color = 'blue';
function setColor (value){
var color = value;//局部变量,外部无法访问
otherColor = value;//局部作用域中未声明的变量,会被当做全局变量
return color;//要想拿到局部变量需要return返回
}
var inColor = setColor('yellow');
alert(color);//blue; 全局变量
alert(otherColor);//yellow 全局变量
alert(inColor);//yellow 局部变量
PS:每个函数被调用时都会创建自己的执行环境。当执行到这个函数时,函数的环境就会被推到环境栈中去执行,而执行后又在环境栈中弹出(退出),把控制权交给上一级的执行环境。
PS:当代码在一个环境中执行时,就会形成一种叫做作用域链的东西。它的用途是保证对执行环境中有访问权限的变量和函数进行有序访问。作用域链的前端,就是执行环境的变量对象。
PS:一般确定变量都是通过搜索来确定该标识符实际代表什么。 变量查询中,访问局部变量要比全局变量更快,因为不需要向上搜索作用域链。
二、块级作用域
1.JavaScript没有块级作用域的概念。
if语句没有块级作用域
if(1){
var age = 18;//age是个全局变量
}
alert(age);//可以访问到age
for语句没有块级作用域
for(var i = 0;i<5;i++){
var color = 'blue';//全局变量
}
alert(i);//5 全局可以访问到变量i;
alert(color);//blue 全局可以访问到变量color;
2、模仿块级作用域
(function (){
//通过匿名函数创建一个块级作用域
//让匿名函数自执行,当程序执行到此就会执行作用域内的代码
})();
(function(){
//在块级作用域内创建一个for循环
for(var i = 0;i<5;i++){
var color = 'blue';
}
})();
alert(i);//会报错 RefereneError:i is not defined;
alert(color);//会报错 ReferenceError:color is not defined;
使用了块级作用域(私有作用域)后,匿名函数中定义的任何变量,都会在执行结束时被销毁。这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。一般来说,我们都应该尽可能少向全局作用域中添加变量和函数。在大型项目中,多人开发的时候,过多的全局变量和函数很容易导致命名冲突,引起灾难性的后果。如果采用块级作用域(私有作用域),每个开发者既可以使用自己的变量,又不必担心搞乱全局作用域。
function Box (value){
var user = value;//私有变量 外部是无法访问的
function run (){};//私有方法外部是无法访问的。
//下面是对象的属性 set方法与get方法。
this.getUser = function(){
return user;
};
this.setUser = function (value){
user = value;
};
}
var box = new Box('lee');//lee 创建对象的同时创建了对象构造方法内的属性。
alert(box.getUser());//通过定义的特权方法访问user;get方法
box.setUser('wang');//通过定义的特权方法给局部变量user赋值。set方法
alert(box.getUser());//wang
静态私有变量( 所谓静态属性,即共享于不同对象中的属性 )
(function() {
var age = 18;//私有变量
function run (){//私有方法
return '正在运行中....';
}
Box = function (){};//没有var声明就是全局的变量
Box.prototype.go = function(){//原型属性
return age + run();
}
})();
var box = new Box();
alert(box.go());//所有的Box类型的对象都可以通过go方法访问age和run,而且访问的是同一个age和run。
(function (){
var user = '';
Person = function(value){
user = value;
};
Person.prototype.getUser = function(){
return user;
};
Person.prototype.setUser = function(value){
user = value;
};
})();
person = new Person('lee');
person1 = new Person('wang');
person1.setUser('zhang');
alert(person.getUser());
4、模块模式
var box = function(){
var age = 18;
function run () {
return '运行中...';
}
var obj = {
go:function (){
return age + run();
}
};
return obj;//返回这个对象
};
alert(box().go());
function Desk() {};
var box = function () {
var age = 100;
function run() {
return '运行中...'; }
var desk = new Desk();//可以实例化特定的对象。
desk.go = function () {
return age + run();
};
return desk;
}();
alert(box.go());