今天开始一个小系列,我们从作用域开始,分别讲述作用域、作用域链、执行环境,最终为了学习理解JavaScript中一个很经典的概念:闭包。
闭包是JavaScript中比较高级的概念和技巧,也是难理解的部分,必须熟练掌握函数表达式、作用域、变量的生存周期等概念后,才能掌握闭包的技巧。
作用域
我们已经知道了变量的概念,不管变量是基本数据类型还是引用类型,其都有一个作用范围,称之为作用域,超出该变量的作用域,则不能被访问,否则将会异常。如果该变量能被所有代码访问,称之为全局变量,其作用域为整个代码环境,反之为局部变量,其作用域为局部。可以将作用域的机制想象为行政管辖范围:县长只能管辖整个县、而市长可以管辖整个市、省长可以管辖整个省。
我们先来看以下代码:
var name=""张三";
function setname(){
name="李四";
}
function showname(){
alert(name);
}
showname(); //显示“张三”
setname();
showname(); //显示“李四”
分析以上代码,我们首先声明了一个变量name并给其赋值为“张三”,由于该变量的声明不在任何函数内,因此其为全局变量,作用域为全局环境,可在整个代码中对其访问,所以可以在函数setname()对其改写,并在函数showname()中对其访问。
接下来对代码做如下修改:
function setname(){
var name="李四";
alert(name);
}
function showname(){
alert(name);
}
showname(); //显示空
setname(); //显示“李四”
showname(); //显示空
我们把变量name的声明移至函数setname()内部,因此name的作用域范围只是函数setname()内部,而在函数showname()中访问不到变量name,因此显示为空。
继续看以下的代码:
function setname(){
var name="李四";
alert(name);
}
function setothername(){
var name="张三";
alert(name);
}
setname(); //显示“李四”
setothername(); //显示“张三”
虽然在函数setname()和setothername()都声明了name变量,但由于两个变量name的作用域均为函数内部,因此这两个变量name仅仅是名称相同而已,实际上是完全不同的两个变量,具有了不同的值。
接下来我们看一个较复杂的例子,函数内嵌套函数,可以更好的诠释变量声明的位置如何决定其所拥有的作用域:
var name="张三";
function changename(othername){
function swapname(){
var tempname=othername;
othername=name;
name=tempname;
//此处可以访问name、tempname、othername
}
swapname();
//此处可以访问name、othername,但不能访问tnepname
}
changename("李四");
alert(name); //显示“李四”
//此处仅可访问name
分析以上代码,这是个改变姓名的函数,首先我们声明了全局变量name,其能被所有代码访问,接下来声明函数changename(),其传入参数为othername,因此函数changename()可以访问name、othername两个变量,在函数changename()中又声明了函数swapname(),在其内部又声明了局部变量tempname,所以函数swapname()可以访问name、othername、tempname三个变量。但变量tempname不能被函数swapname()以外的代码访问,同样传入参数othername也不能被函数changename()以外的代码访问。
下一讲我们将学习执行环境、作用域链。
欢迎加入技术QQ交流群:364595326
网友评论