• Javascript 进阶 作用域 作用域链


    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/25076713

    一直觉得Js很强大,由于长期不写js代码,最近刚好温故温故。

    1、Javascript没有代码块作用域的概念,局部作用域是针对函数来说的。

            function fun()
            {
                for( var i = 0 ; i < 10 ; i++)
                {}
                //如果在Java中i此时应当属于未声明的变量,但是Js中i的作用域依然存在
                console.log(i);//10
    
                if(true)
                {
                    var b = "helloworld";
                }
                console.log(b);//helloworld
            }
            fun();
    


    2、如果不使用var声明的变量,默认为全局变量

            function fun02()
            {
                a = "helloworld";
                var b = "welcome";
            }
            fun02();
            console.log(a); //     helloworld
            console.log(b); //   b is not defined
    

    3、Js中的作用域链

    先看个简单的例子:只有一个函数对象,函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

      var a = "hello";
    
            function fun04()
            {
                 a = "world";
                  var b ="welcome";
            }
    
    作用域链的图:


    注:图中省略了,Global Scope中的window,document等,每个函数对象中的arguments,this等均未画出。

      function fun03()
            {
                var a = 10;
                return function(){
                    a*= 2 ;
                    return a ;
                };
            }
    
            var f = fun03();
            f();
            var x = f();
           console.log(x);  //40
    
            var g = fun03();
            var y = g();
            console.log(y); //20

    观察上面代码,存在fun03,f,g三个函数对象。

    下面是作用域链的图:


    注:每个函数对象一个作用域链,这里直接画在了一起;对于变量的查找,先从链的0开始找。

    函数对象 f 在代码中执行了2 次,所以a*2*2 = 40 ; 函数对象 g 在代码中执行了1次, 所以 a *2 = 20 ; 

    4、闭包

    上面的例子可以看到,在fun03执行完成后,a的实例并没有被销毁,这就是闭包。个人对闭包的理解是:函数执行完成后,函数中的变量没有被销毁,被它返回的子函数所引用。

    下面以一个特别经典的例子,同时使用作用域链解析:

    window.onload = function()
            {
                var elements = document.getElementsByTagName("li");
                for(var i = 0; i < elements.length ; i ++)
                {
                    elements[i].onclick = function()
                    {
                        alert(i);
                    }
                }
    
            }

    相信上面的代码肯定大家都写过,本意是点击每个li,打印出它们的索引,可是事实上打印出的都是elements.length。这是为什么呢?


    看下上面的简易的作用域链(省略了很多部分,主要是理解),此时每个onclick函数的i,指向的都是 onload 中的i 此时的 i = element.length.

    下面看解决方案:

     window.onload = function ()
            {
                var elements = document.getElementsByTagName("li");
                for (var i = 0; i < elements.length; i++)
                {
                    (function (n)
                    {
                        elements[n].onclick = function ()
                        {
                            alert(n);
                        }
                    })(i);
                }
    
            }

    在onclick函数的外层,包了一层立即执行的函数,所以此时的n指向的 n 是立即执行的,所有都是1~elements.length 。




    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    git简单使用
    Kafka初入门简单配置与使用
    Hbase简单配置与使用
    Oozie简单配置与使用
    Flume初入门简单配置与使用
    sqoop简单配置与使用
    Android基础系列合集
    Java 基础系列合集
    TCP 和 UDP 区别
    http get和post区别
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4924962.html
Copyright © 2020-2023  润新知