zoukankan      html  css  js  c++  java
  • js便签笔记(12)——浏览TOM大叔博客的学习笔记 part2

    1. 前言

    昨天写了《js便签笔记(11)——浏览TOM大叔博客的学习笔记 part1》,简单记录了几个问题。part1的重点还是在于最后那个循环创建函数的问题,也就是多个子函数公用一个闭包数据的问题。如果觉得有兴趣,可以再重新翻出来看看。

    今天继续把剩下的问题写完。

    2. 作用域链

    学js的人,即使初级入门的也都知道“原型链”,但是“作用域链”,可能好多人没有听说过。大部分人都知道或者听说过“闭包”,但是可能有好多人不知道闭包其实和作用域链有莫大的联系。如果理解闭包不从作用域链开始理解,那么你就只能理解闭包的皮毛。

    我也是从TOM大叔的这些博客中才了解到作用域链的,之前也看过了许多本书籍,都没有很清晰的展开作用域链这个概念。其实作用域链简单说来也好理解,如下代码:

            var x = 10;
            function fn() {
                var y = 20;
                return function () {
                    var z = 30
                    console.log(x + y + z);
                }
            }

    上面代码中,如果想要打印 x+y+z 的值,就必须要遍历三个层次的上下文环境或者作用域,这其实和原型链的结构表现形式类似。但要细细将来,连同闭包图文并茂的说明白,需要很多内容。

    此处不再深入进去,以后有机会再另起一篇详细介绍。

    3. 二维链查找 

    上文讲到通过作用域练向上查找变量,实际在查找变量的过程中,是使用“二维链查找”——“作用域链” + “原型链”。看如下代码:

           Object.prototype.x = 10;
            function fn() {
                var y = 20;
                return function () {
                    var z = 30
                    console.log(x + y + z);
                }
            }

    这份代码跟上文中演示作用域链的代码差不多,但是它却通过 Object.prototype.x = 10; 这么一句话,表现出了原型链在其中的作用。
    因此,在查找变量值时,是同时兼顾原型链和作用域链两个方向的,即“二维链查找”。 

    4. 独立作用域只能通过函数来创建

    这句话的下半句是——不能通过if/for等语句块来创建。后半句大家可能知道,但是它的本质确实前半句——独立作用域只能通过函数来创建(除了独立作用域之外,剩下的就是全局作用域)。既然独立作用域只能通过函数来创建,那么函数中任何地方的自由变量就都是函数层级的,因此,以下代码希望不要再次出现:

    5. 隐式全局变量的本质

    var a = 10;
    b = 20;

    以上两句代码,看似都是声明两个全局变量,但是按照TOM大叔说的,只有var才能声明一个变量,也就是 var a = 10; 是真正的声明变量。

    而下一句 b = 20,其实是相当于设置window的一个属性值而已。

    因此,第一句的本质是声明一个全局变量;第二句的本质是设置window的一个属性值。

    当然,不推荐用第二句的形式。

    6. 函数声明和函数表达式的不同

    js定义函数的方法有多种,但看看以下这段代码:

    fn();
    var fn = function() {  //函数表达式
        alert(123); // 报错
    }
    //------
    fn();
    function fn() {  //函数声明
        alert(123); // 123
    }

    两种函数定义方式,却得出不一样的结果。

    此处我当时没有详细看,因为这样使用的情况不是很多,所以就没有过深入的细看,只是做了个标记。如果有了解的朋友,不放解释一下。

    7.js使用静态作用域

    在part1中讲过,当一个函数作为参数被传入,后者作为一个值被返回的时候,连同它一块被传递的,是它的作用域。也就是咱们常说的闭包。且看如下代码:

    var x = 10;            
    function foo() {
        alert(x);
    }
    (function (funarg) {
        var x = 20;
        funarg();    // 10, 不是20
    })(foo); 

    foo是一个函数,把它作为参数传入进另一个函数中执行,连同一起传递的,是foo的作用域。而foo使用的是静态作用域,其中的变量x在传递的时候已经被静态赋值,不会受其他环境下x变量的影响。
    这个道理也同样适用于函数作为返回值。如下:

    function fn() {
        var x = 10;
        return function () {
            alert(x);
        }
    }
    var ret = fn();
    var x = 20;
    ret();   // 10,不是20

    更多内容请关注我的微博

  • 相关阅读:
    258 第七篇:Django-组件-ContentType组件
    257 第七篇:Django-组件-Auth模块
    256 第七篇:Django-组件-中间件组件
    255 第七篇:Django-组件-cookie与session组件
    254 第七篇:Django-组件-forms组件
    253 第七篇:Django-组件-分页器组件
    第二节:2_委托入门笔记
    EF-调用sql进行操作
    1.1常见的错误---登录(菜鸟常遇错误)
    EF-Lamdba
  • 原文地址:https://www.cnblogs.com/wangfupeng1988/p/3949931.html
Copyright © 2011-2022 走看看