关于js中作用域,闭包,立即执行函数的理解
- 执行环境:
JS中非常重要的概念,全局执行环境被认为是window对象,另外,每一个函数都有自己的执行环境。当代码在环境中执行时,会创建一个作用域链。 - 作用域链:
限制变量或者函数的访问权限。
作用域的顺序为“由内而外”,也就是说,作用域的顶端是当前执行代码所在环境的变量对象。下一个变量对象来自外一层包含环境,window对象始终都是作用域链的最后一个对象。
因此在变量查询时,也是先从作用域链的顶端开始,找到则停止,找不到则继续向下进行。
作用域链的用途是:保证对执行环境有权访问的所有变量和函数的有序访问。
在这里小提一下,如果定义变量的时候没有使用关键字,则会生成一个全局变量。
一个非常简单的例子:
<script>
var a =10;
function fun()
{
var a=3;
alert(a);//3
}
fun();
alert(a);//10
</script>
对于JS来说,不存在块级作用域(所谓块级作用域就是用大括号包起来的部分,比如说if,while,for中)。看一个简单的例子。
<script>
var a = 10;
if(a==10)
{
var a=8;
}
alert(a);//8
</script>
而对于C家族语言来说,是存在块级作用域的
#include<stdio.h>
int main()
{
if(1)
{
int a=1;
}
printf("%d",a);//出现错误
}
接下来了解一下闭包:
- 什么是闭包:
- 有权访问另一个函数作用域内变量的函数
- 创建时通常需要用到函数的嵌套
- 会“阻碍”js的垃圾销毁机制,因为内部的函数会用到外部函数的变量,所以不能销毁外部函数的执行环境,因此经常会说到闭包会增大内存的开销。
- 跨作用域访问
- 大概扯到这里会有些迷,辣就来个栗子吧
function func1(){
var name="zhangsan";
function func2(){
return name;
}
return func2();
}
var thatname=func1();
console.log(thatname);//zhangsan
通常情况下,我们是不能再函数外部获取函数内的变量的,子作用域可以访问父作用域中的变量,反之不行。此时就需要用到闭包,即可以实现跨作用域的访问,外部可以访问内部啦。
再看一个栗子:
function create(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]=function(){
console.log(i);
};
}
return result;
}
var createresult=create();
createresult[5]();//10
这里返回了一个函数数组,看起来每个函数应该打印自己的索引值,但是实际上每个函数打印的都是10,这是因为i这个变量在for循环结束后变成了10,并且在for循环结束后仍然有效。
解决方法是创建一个立即执行函数。
function create(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]=(function(num){
console.log(num);
})(i);
}
return result;
}
var createresult=create();//输出0-9
这里i的值传给了num,立即执行函数我的理解就是立即执行这个函数,当然也有其他的解决办法,如ES6中的let.
- 下面说一些值得注意的地方
- 使用完闭包,建议手动销毁,以释放内存。对于如上代码片,可以用
thatname=null
销毁 - javascript函数运行在定义它的作用域中,而不是执行时的作用域中。比如说下面的例子:
- 使用完闭包,建议手动销毁,以释放内存。对于如上代码片,可以用
var name="zhangsan";
function func1(){
console.log(name);
}
function func2(){
var name="lisi";
func1();
}
func2();//zhansan
func2中去掉var是不一样的,相当于修改了全局的name的值
var name="zhangsan";
function func1(){
console.log(name);
}
function func2(){
name="lisi";
func1();
}
func2();//lisi
先这些吧,有新的想法再和大家分享