做用域、做用域链、闭包

做用域、做用域链

1、Js之前没有块级做用域,不过在ES6中有let了。html

2、Js使用函数做用域闭包

function aaa(){
        var a = "a";
    }
    console.log(a);//报错

3、声明提早函数

console.log(aaa)//报错
console.log(aaa);//undefined 声明未定义
var aaa;
console.log(aaa); //undefined 声明未定义
var aaa = "aaa";

4、Js的做用域链spa

复制代码
function Fun(){
    var aaa = "aaa",
         fun = "fun";
    function Inter(){
        var aaa = "ccc";
        console.log(aaa); //ccc
        console.log(fun); //fun
    }
    Inter();
}
Fun();
复制代码

Inter的做用域链翻译

找到就中止查找返回数据,找不到就延做用域链查找,直到Global也查不到就返回报错;debug

5、Js的做用域链在执行前已经被建立rest

 闭包

1、闭包:是指有权访问另外一个函数做用域中的变量的函数;code

2、闭包的特色:局部变量不会被垃圾回收;htm

 

//定义一个函数时,实际是保存它的做用域链。当调用这个函数时,会建立一个新的对象来保存局部变量,而且把这个新的对象添加到做用域链上。当函数返回时,将做用域链中的这个对象删除。对象

//若是这个函数定义了嵌套函数,并将它做为返回值返回或者存储在某处的属性里,就会有一个外部的引用指向这个嵌套函数。

3、上面那句是书上的话,很差理解。我翻译下就是父函数内建立的变量,子函数调用。只要子函数没有被销毁,父函数和建立的变量就不会被销毁。

举个栗子

复制代码
function counter(){
        var a = 0;
        function rest(){
            console.log(a++);
        }
        return rest;
    }
    var scope = counter();
    scope();//0
    scope();//1
    scope();//2
复制代码

建立闭包的常见方式,就是在一个函数内部建立另外一个函数,外部函数将内部函数做为返回值返回。有的时候这个外部是全局。

for(var i = 0;i<elements.length;i++){
        elements[i].onclick = function(){
            console.log(i);  //elements.length
        }
    }

上面每次点击,输出的都是elements.length。由于onclick是一个点击的函数,不能被销毁,因此i也不能被销毁保存在Global中。因此点击输出的是elements.length。

复制代码
for(var i = 0;i<elements.length;i++){
        function F(n){
            elements[n].onclick = function(){
                console.log(n);
            }
        }
        F(i);
    }
复制代码

这样修改下就能够了。

4、垃圾回收机制:若是一个对象再也不被引用,这个对象会被GC回收。若是两个对象相互引用,这两个都会被回收。若是a被b引用,b又被c引用,就不会被回收,就是闭包第一个例子的缘由。

5、闭包的两种写法

复制代码
function counter(){
        var a = 0;
        function rest(){debugger
            return a;
        }
        return rest();
    }
    counter();
复制代码

定义调用在同一做用域

复制代码
    function counter(){
        var a = 0;
        function rest(){debugger
            return a;
        }
        return rest;
    }
    //counter()();
    var scopt = counter();
    scopt();
复制代码

定义调用不在同一做用域

原文:http://www.cnblogs.com/taohuashan/p/6689619.html

相关文章
相关标签/搜索