javaScript作用域与闭包


首先给js的作用域这个话题打标签:2,var, 全局变量,局部变量,函数,undefined, 作用域提升,赋值不会提升,ReferenceError, 同名覆盖。
打完标签之后,我们来说跟作用域有关的几条铁打的规则:
1: JS的作用域有2种:全局作用域,函数作用域。

把作用域想象成一个房间,而{}是房间的门。门上装了一个猫眼,所以房间里面可以看清楚外面,但是外面却看不见里面。那在JAVA或者C里面,大括号可能会出现的情况有两种:一个function定义的时候和一个块定义(比如if,for, while)的时候,所以此时的作用域有三种类型:全局作用域,函数作用域,块级作用域。但是在JS里面,虽然{}出现的情况也有两种,但是只有function的{}才起到栅栏的作用。

2: 声明在全局作用域里的变量是全局变量,声明在函数里面的变量是局部变量

3: 怎么创造一个全局变量和局部变量?

创造全局变量的方法有两种:

   1: 在全局作用域内用var定义: var a;
   2: 声明一个变量,不带var(无论是在全局,在函数里面还是在一个块里面):b

创造局部变量的方法只有一种:

   在函数体里面,带var声明一个变量: function func(){var b;}

3: 使用一个没有声明过的变量,会得到一个ReferenceError。无论什么情况下。
4: 不同作用域内,同名的变量,越小的作用域的变量会覆盖越大的作用域的。

4: 作用域提升:变量在声明之前就可以引用了!
这个不是和第三点矛盾了吗?其实并没有。它背后的真正原理是:并不是作用域被提升(我们前面说了,一个变量的作用域会被框在一对栅栏{}里面,一旦这个栅栏确定了,那这个作用域是不可能变化的),其实是变量的‘声明’在其作用域里面被放到任何代码之前(当然包括引用它的代码之前)。看一段代码:

var scope = 'global';
function func(){
    console.log(scope); //输出‘undefined’,而不是‘global’
    var scope = 'local';
    console.log(scope); //输出‘local’
}

看到第一个console,可能以为会输出‘global’, 因为通过猫眼可以看见外面的变量。但是,一旦我们进到一个函数体里面,遇到任何的变量的引用,首先要先在当前的房间里面找,只有在当前的房间里面找不到时,才到父层去找。那为什么是‘undefined呢?其实以上的代码等价于:

var scope = 'global';
function func(){
    var scope; //变量的声明会提升到最前面,但是赋值并不会,所以此刻scope的值还只是undefined.
    console.log(scope); //输出‘undefined’,而不是‘global’
    scope = 'local'; //赋值在这里完成
    console.log(scope); //输出‘local’
}

============闭包的分割线===========
1: 什么是闭包?
我看过看多不同的书,对必包的定义都不一样,而且就算是我知道了闭包的定义,对我真正理解它的工作原理还是没有什么用。所以,我就不去纠结它到底是什么,我接下来只关注它是怎么工作的。
2: 什么时候会形成闭包?
以下内容非原创,这里只是我自己的一个学习笔记。我看了http://www.jianshu.com/p/7312…这篇文章(在这里感谢作者),跟着文章里面的例子(代码根据自己的喜好改了一些)走一遍:
1: When? 闭包出现的时刻?


function foo() {
    var a = 2;
    function baz() { 
        console.log( a );
    }
    return baz;
}
var fn = foo()
fn();//2

javaScript作用域与闭包
在断点的过程中,运行完第9行代码的时候,调试窗口里并没有出现任何闭包;直到我运行了第10行代码,跳到第5行的时候(也就是baz这个方法被调用的时候),调试窗口出现了闭包(Closure)。并且可以看到说foo是closure, 它包含一个变量a,值为2。

结论:虽然很多书上说闭包跟函数定义的时候的作用域有关,跟它执行时候的作用域无关,但是它在浏览器里面出现的时机却是在执行的时候。

2 How? 闭包出现的条件?

function foo() {
    var a = 2;
    function baz(m) { 
        console.log(m);
    }
    return baz;
}
var fn = foo()
fn(20); //20
![图片描述][2]


发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>