首页 > 网站 > WEB开发 > 正文

JavaScript中的作用域和闭包

2024-04-27 14:10:52
字体:
来源:转载
供稿:网友

javaScript中的作用域和闭包

Posted on 2015-04-14 09:09 yanzi2015 阅读(...) 评论(...) 编辑 收藏

Javascript中的作用域和闭包

很多人都在说自己对闭包的理解,有的对我理解闭包很有帮助,有的我看了还是没能够理解,以下是我自己学到现在对作用域和闭包的理解,可能还比较浅显,希望给跟我一样在学习JavaScript的人们一点点帮助,也希望大家不吝指教!

先要了解全局变量和局部变量。

在最外层直接声明的变量,就叫全局变量。全局变量(或函数),在全局的任何地方都可以使用(作用范围是全局)。

在函数中声明的变量,叫做该函数的局部变量。局部变量(或函数),只在该函数内部起作用,外边访问不到。

1)函数内部可以直接读取全局变量

1 var a = 1;2 function fn(){3   alert(a);4 }5 fn(); // 1

2)函数外部无法读取函数内的局部变量

1 function fn(){2     var a = 1;3 }4 alert(a); //报错 a is not defined

3)函数内部声明变量的时候,一定要加上var,否则实际上是声明了一个隐式全局变量

1 function fn(){2     a = 1;3 }4 fn();5 alert(a); // 1

4)

1 function fn1(){2   var a = 1;3   function fn2(){ //函数fn2就是闭包4     alert(a);5   }6 return fn2();7 }8 fn1(); // 1

函数fn2被嵌套在函数fn1内,这时fn1内部的所有局部变量,对fn2都是可见的。但是反过来fn2内的局部变量对fn1都是不可见的。既然fn2可以读取fn1中的局部变量,那么只要把fn2作为返回值,我们就可以在fn1外部读取它的内部变量了。

JavaScript中的闭包,就是定义在一个函数内部的子函数,可以使用其父函数的局部变量。

1 function fn(b){2 return function(){3     b++;4     alert(b);5 }6 }7 var a = fn(0);8 a(); // 1

闭包除了可以读取其父函数的局部变量,还会让这些变量的值始终保存在内存中。消耗内存,所以不使用的局部变量需要删除。记得老师还说过在IE中可能导致内存泄露。

 1     function fn1(){ 2  3     var a = 0; 4     b = function(){ 5             a++; 6         } 7     function fn2(){ 8       alert(a); 9     }10     return fn2;11   }12 13   var result = fn1();14   result(); // 015     b();16   result(); // 1

在这段代码中,result实际上就是闭包fn2函数。它一共运行了两次,第一次的值是0,第二次的值是1。这证明了,函数fn1中的局部变量a一直保存在内存中,并没有在fn1调用后被自动清除。

原因就在于fn1是fn2的父函数,而fn2被赋给了一个全局变量,这导致fn2始终在内存中,而fn2的存在依赖于fn1,因此fn1也始终在内存中,不会在调用结束后,被垃圾回收机制回收。

b = function(){a++;}

b是一个隐式全局变量,它的值是一个匿名函数,匿名函数本身也是一个闭包,所以可以在函数外边对函数内的局部变量进行操作。

作用域:

JS作用(读、写)域(空间、范围):可以理解为在什么样的范围内可以对数据进行读写。

alert(a);vara=0;//undefined

alert(a);a=0;//报错aisnotdefined

浏览器中的“JS解析器”:读到script开始执行代码之前至少分两步

1)“找一些东西”:varfunction参数

比如找到了咱们声明的变量a之后不会去读,是先给他一个值未定义a=undefined;

所有的变量,在正式运行代码之前,都提前赋了一个值:未定义

fn1=functionfn1(){alert(2);}

所有的函数,在正式运行代码之前,都是整个函数块

这一步叫做:JS的预解析

预解析的过程中遇到重名的会只留一个(有值的),如果都是有值的就把之前的替换掉。

解读代码的时候读到表达式会修改预解析的值。函数的声明不去修改表达式的值。

2)逐行解读代码:(修改仓库里的数据)

表达式(可以改变值的):=+-*/%++--!参数......Number()

当读到alert(a);时,不会往下去读,会先去它的仓库里去找有没有a

<script></script>是一个域,一个页面中可以有多个

自上而下,处理完一个script再处理下一个script。上边的script会影响到下边的script

所以,当一个script标签,需要调用另外一个script内的东西,那这个script一定要写在另外一个script下边

if和for的{}不是作用域,相当于是通透的里边的东西和定义到全局是一样的

作用域范围:

全局作用域:

1)最外层定义的全局变量、全局函数;

2)未定义直接赋值的变量即隐式全局变量;

3)所有window对象的属性。

以上都拥有全局作用域

局部作用域:function(函数作用域)

由里到外(局部有能力改外面的值)

几段代码:

1)

1 var a = 1;2 function fn1(){3     alert(a);4     var a = 2;5 }6 fn1();     //undefined7 alert(a);  //1

刚开始还是找varfunction参数,function还是函数块;当逐行解读代码的时候,读到函数调用fn1(),函数是一个域,开启了一个新的作用域,又会发生两件事(预解析,逐行解读代码)“一个小仓库”局部的a跟外边全局的a没有关系

2)

作用域链:就近原则,先在子级找,在子级找不到会返回到父级去找

1 var a = 1;2 function fn1(){3     alert(a);4     a = 2;5 }6 fn1();     //17 alert(a);  //2

3)参数本质上就是一个局部变量

1 var a = 1;2 function fn1(a){3     alert(a);4     a = 2;5 }6 fn1();     //undefined7 alert(a);  //1

4)参数也是可以改变值的,函数调用从参数开始读

1 var a = 1;2 function fn1(a){3     alert(a);4     a = 2;5 }6 fn1(a);    //17 alert(a);  //1

5)局部是可以访问到外面的值的,所以可以改num的值。

1 var num = 0;2 function fn1(){3     num++;4 }5 fn1();6 alert(num); //1

从外面(全局)是找不到里面(函数/局部)的东西的,如果想找到至少有两种方法:

想要获取函数内的值:

1)用全局变量

1 var str = '';2 function fn1(){3     var a = 'abc';4     str = a;5 }6 fn1();7 alert(str); // abc

2)局部的函数调用

1 function fn1(){2     var a = 'abc';3     function fn2(a){4         alert(a);5     }6     fn2(a);7 }8 fn1();


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表