码迷,mamicode.com
首页 > 编程语言 > 详细

JavaScript中的作用域和闭包

时间:2015-04-14 09:43:51      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:

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(); // 0
15     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);var a = 0; //undefined

alert(a);a = 0; //报错a is not defined

 

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

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

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

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

fn1 = function fn1(){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();     //undefined
7 alert(a);  //1

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

2)

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

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

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

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

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

1 var a = 1;
2 function fn1(a){
3     alert(a);
4     a = 2;
5 }
6 fn1(a);    //1
7 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();

 

JavaScript中的作用域和闭包

标签:

原文地址:http://www.cnblogs.com/yanzi89/p/4423986.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!