zoukankan      html  css  js  c++  java
  • 作用域、作用域链、闭包

    作用域、作用域链

    一、Js以前没有块级作用域,不过在ES6中有let了。

    二、Js使用函数作用域

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

    三、声明提前

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

    四、Js的作用域链

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

    Inter的作用域链

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

    五、Js的作用域链在执行前已经被创建

     闭包

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

    二、闭包的特点:局部变量不会被垃圾回收;

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

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

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

    举个栗子

    复制代码
    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);
        }
    复制代码

    这样修改下就可以了。

    四、垃圾回收机制:如果一个对象不再被引用,这个对象会被GC回收。如果两个对象相互引用,这两个都会被回收。如果a被b引用,b又被c引用,就不会被回收,就是闭包第一个例子的原因。

    五、闭包的两种写法

    复制代码
    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

  • 相关阅读:
    `/usr/java/jdk1.8.0_101': not a valid identifier
    gem sources -a https://ruby.taobao.org/ 提示:Error fetching https://ruby.taobao.org/ SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: ce rtificate verify failed
    ERROR: While executing gem ... (Encoding::UndefinedConversionError) U+7CFB to IBM437 in conversion from UTF-16LE to UTF-8 to IBM437,当你执行gem 命令时,提示如上信息解决方案如下。
    ubuntu15.10安装 jdk
    ubuntu 如何安装tomcat
    Mac pro 上安装 robotframework 时的一个版本问题
    AppBuilder(四)SignatureConversions
    AppBuilder(三)BuildInternal
    AppBuilder(二)UseStageMarker
    AppBuilder(一)Use汇总
  • 原文地址:https://www.cnblogs.com/yanglang/p/6698132.html
Copyright © 2011-2022 走看看