zl程序教程

您现在的位置是:首页 >  前端

当前栏目

JavaScript变量作用域及闭包

JavaScript变量 作用域 闭包
2023-06-13 09:14:11 时间
实例一:
复制代码代码如下:

<scripttype="text/javascript">
vari=1;
//弹出内容为1true的提示框
alert(window.i+""+(window.i==i));
</script>

分析:
在全局定义的变量其实就是window对象的属性。
上面的例子可以看到,我们定义全局变量的同时,window对象会产生一个相应的属性,如何让我们的代码避免产生这个属性呢,看下面的例子。
实例二:
复制代码代码如下:

<scripttype="text/javascript">
vardocument=1;
window.onload=function(){
alert(document);
}
//弹出内容为1的提示框
alert(window.document);
</script>

这种情况是我们不想看到的,我们可以这么做:
复制代码代码如下:
<scripttype="text/javascript">
functiontest(){
vardocument=1;
window.onload=function(){
alert(document);
}
}
test();
//弹出内容为[object]的提示框
alert(window.document);
</script>

为了使代码更加简洁,我们可以这样:
复制代码代码如下:
<scripttype="text/javascript">
(function(){
vardocument=1;
window.onload=function(){
alert(document);
}
})();
//弹出内容为[object]的提示框
alert(window.document);
</script>

分析:
这种运行匿名方法的形式,在JavaScript的主流框架中经常见到,这样做可以避免产生不必要的window对象的属性,减少冲突的可能。
实例三:
复制代码代码如下:
<scripttype="text/javascript">
(function(){
if("1"=="1"){
vari=1;
}
//弹出内容为1的提示框
alert(i);
})();
</script>

分析:
变量的作用域是整个函数,不是{}块。
实例四:
复制代码代码如下:
<scripttype="text/javascript">
vari=1;
//弹出内容为1的提示框
alert(i);
vari=2;
//弹出内容为2的提示框
alert(i);
</script>

分析:
一个变量可以被重新定义,这个看起来有些怪,因为在很多其他语言里这样是行不通的。
实例五:
复制代码代码如下:
<scripttype="text/javascript">
functiontest(){
i=1;
}
test();
//弹出内容为1的提示框
alert(window.i);
</script>

分析:
如果对一个没有初始化的变量进行赋值操作,那么这个变量会作为全局变量。

实例六:
复制代码代码如下:
<scripttype="text/javascript">
window.onload=function(){
vari=1;
functiontest(){
alert(i);
}
//弹出内容为1的提示框
test();
}
</script>

分析:
内部函数可以访问外部函数的变量,这个就引出了一个新的概念,那就是闭包。
闭包
什么是闭包呢,简单的说就是一个函数A,它的内部函数B可以访问A内定义的变量,即使函数A已经终止。下面通过实例进行了解。
实例七:
复制代码代码如下:
<scripttype="text/javascript">
window.onload=function(){
vari=1;
window.onunload=function(){
alert(i);
}
}
</script>

分析:
当整个页面加载完成时,会触发onload事件,这个onload事件方法里给窗口的onunload事件注册了一个方法,这个方法里用到了onload事件方法里声明的变量,然后onload事件方法运行结束,这时候我们点击关闭窗口,会弹出内容为1的提示框,说明onunload的事件方法成功的调用了onload事件方法里声明的变量。
为了进一步了解闭包的特性,看下面的例子
实例八:
复制代码代码如下:
<scripttype="text/javascript">
functioninitX(oarg){
//定义一个变量
varx=oarg;
//定义一个显示变量的方法
varfunGet=function(){
alert(x);
}
//定义一个对变量进行修改的方法
varfunSet=function(iarg){
x=iarg;
}
//返回这两个方法
return[funGet,funSet];
}
//运行一个方法实例,返回值为包含get和set方法的数组
varfunArr=initX(1);
//得到get方法
varfunGet=funArr[0];
//得到set方法
varfunSet=funArr[1];
//运行get方法,显示initX方法实例内的x变量,结果为1
funGet();
//运行set方法,对initX方法实例内的x变量进行赋值
funSet(2);
//运行get方法,显示initX方法实例内的x变量,结果为2
funGet();
</script>

分析:
当内部函数对外部函数定义的变量进行调用时,实际上引用的是这个变量的内存块,所以当我们调用内部函数时,引用的变量值是当前这个变量的实际内容。
闭包功能虽然强大,但是如果不注意,它也会给我们带来困扰。看下面的例子。
实例九:
复制代码代码如下:
<buttonid="main">run</button>
<scripttype="text/javascript">
(function(){
varobj=document.getElementById("main");
varfunArr=["onclick","onkeypress"];
for(vari=0;i<funArr.length;i++){
vartemp=funArr[i];
obj[temp]=function(){
alert(temp);
}
}
})();
</script>

写代码的原意是给id是main的按钮注册点击事件和按键事件,事件的内容是分别弹出事件名称的提示框。但是结果有点匪夷所思,两个事件的提示框全是onkeypress,根据闭包的原理,我们仔细分析,就会发现当两个事件方法被调用时temp变量指向的是funArr[1]的内容,我们可以这样修改来解决这个问题:
复制代码代码如下:
<buttonid="main">run</button>
<scripttype="text/javascript">
(function(){
varobj=document.getElementById("main");
varfunArr=["onclick","onkeypress"];
for(vari=0;i<funArr.length;i++){
(function(){
vartemp=funArr[i];
obj[temp]=function(){
alert(temp);
}
})();
}
})();
</script>

把for循环内的代码放入一个函数内,这样,每循环一次都会产生一个函数实例,让函数实例记录funArr数组中的每个值,这样就避免了上面碰到的问题。