zoukankan      html  css  js  c++  java
  • 读书笔记-你不知道的JS上-函数作用域与块作用域

    函数作用域

      Javascript具有基于函数的作用域,每声明一个函数,都会产生一个对应的作用域。

        //全局作用域包含f1
        function f1(a) {
            var b = 1;
            //f1作用域包含a,b,f2
            function f2() {
                //f2有自己的
                //...代码
            }
            return a + b;
        }
        //无法从外部访问内部作用域
        console.log(b); //error

      

    IIFE

       如果需要封装某些变量,但同时不想多出一个函数名与调用函数,可以使用IIFE,立即执行函数。

        var a = 1;
        //为了封装a变量需要声明一个函数并同时调用
        function fn() {
            var a = 2;
            console.log(a); //2
        }
        fn();
        console.log(a); //1
        //可以使用IIFE
        (function() {
            var a = 2;
            console.log(a); //2
        })();

      当函数被括号包起来时,被当成一个函数表达式了,所以可以立即执行,区分函数声明和函数表达式最简单的方法就是看function关键字是否是第一个词。

        console.log(fn()); //1
        function fn() {
            return 1;
        }
        console.log(fn2()); //error
        //匿名函数表达式 不会提升声明
        (function fn2() {
            return 1;
        })

      匿名函数表达式使用很方便,但是也有几个缺点。

      1、调试时无法根据函数名进行追踪。

      2、没有函数名,调用自身只能使用被废弃的arguments.callee。

      3、缺失可读性。

      所以说,作者建议给匿名函数加个函数名就可以了。

      

      IIFE还有另外一种改进形式。

        (function() {
            var a = 1;
            console.log(a); //1
        }());

      这两种功能上是一致的。

      IIFE的一个非常普遍的进阶用法是把它们当做函数调用并传递参数进去。

        var a = 2;
        (function(global) {
            var a = 1;
            console.log(a); //1
            //将传进去的window更名为global
            //使得语义更明确 并且解析全局变量时不会一层层作用域查找
            console.log(global.a); //2
        }(window));

      另外一个应用场景是解决undefined标识符的默认值被错误覆盖。(测试不出undefined可以被改变值,暂不贴代码)

      IIFE还有一种变化的用途是倒置代码的运行顺序。将需要运行的函数放后面,IIFE执行之后当参数传进去。

        var a = 2;
        (function IIFE(def) {
            def(window);
        })(function(global) {
            var a = 3;
            console.log(a); //3
            console.log(global.a); //2
        });
        //相当于
        (function(global) {
            var a = 3;
            console.log(a); //3
            console.log(global.a); //2
        })(window);

      jQuery源码就是用这种形式,当初一脸懵逼,根本看不懂。。。

    块作用域

      除Javascript外很多编程语言都支持块作用域。

        //块状作用域
        for (var i = 0; i < 10; i++) {
            console.loe(i);
        }

      然而,JS并没有,表面上没有。

      1、with语句会创建出块级作用域。

      2、try/catch的catch分句会创建一个块级作用域。

    let

      ES6引入了let关键字,提供了另外一种变量声明方式。

      let关键字可以将变量绑定到所在的任意作用域中,简单来说,就是提供了块级作用域。

        {
            var a = 1;
        }
        console.log(a); //1
        {
            let b = 1;
        }
        console.log(b); //error

      let还有两个特性,首先,不会有变量提升。

        {
            console.log(a); //error
            let a = 1;
        }

      第二个就是暂时性死区。

      简单来说,就是在有let的块级作用域中,变量在声明前被暂时锁住,不允许在声明前进行使用。

        var a = 2; //声明全局变量
        {
            console.log(a); //还是报错了!
            let a = 1;
        }

      ES6还提供了const关键字,也可以提供块级作用域,意义参照C++。

  • 相关阅读:
    python中常见的部分错误
    不同类型指针自加所移动位置分析
    c语言,sizeof关键字,数组和指针区别
    数组名和指针能够等价的情况
    typedef与define宏定义用于声明新的类型之间的区别
    老问题了,函数返回指向常字符串的指针,形如 char *func()
    c语言运算符优先级 ., *, (), []
    const char**与char**类型的区别
    char *f[]与char (*f)[]的区别
    标准IO库函数sprintf
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/6445029.html
Copyright © 2011-2022 走看看