最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Function 知识储备

    正文概述 掘金(Des bisous)   2021-01-20   386

    Function 的使用

    // Function
    const fun1 = new Function('a', 'b', 'c', 'console.log(a + b + c)');
    const fun2 = new Function('a, b, c', 'console.log(a + b + c)');
    fun1(1, 2, 3);
    fun2(4, 5, 6);
    

    特点

    我们先从一个案例题目来看看,Function 的一个特点

    var a = 1,
      b = 2;
      
    function test() {
      var b = 3;
    
      return new Function('c', 'console.log(a + b + c)');
    }
    
    var t = test();
    t(4); // 7
    

    从这个案例中,可以知道,最后 console.log 输出的值为:7。

    一般来说,对于这个题目,有时候会傻傻分不清,输出的是7、还是8。

    这里就涉及到一个 Function 的特点,Function 声明的函数,是全局作用域下的。针对于上题中的 new Function,其实并不是声明在局部的 test 函数作用域下的,而是在全局作用域下的,所以对于 b 的取值,取的是全局作用域下的 2。

    关于这点,可以查看 MDN Web 文档中 Function 介绍,它里面有这一段描述:

    官方案例:

    var x = 10;
    
    function createFunction1() {
        var x = 20;
        return new Function('return x;'); // 这里的 x 指向最上面全局作用域内的 x
    }
    
    function createFunction2() {
        var x = 20;
        function f() {
            return x; // 这里的 x 指向上方本地作用域内的 x
        }
        return f;
    }
    
    var f1 = createFunction1();
    console.log(f1());          // 10
    var f2 = createFunction2();
    console.log(f2());          // 20
    

    注意点:

    1. new Function()Function 其实是一样的,是一个声明 + 定义一个函数,更重要的是不要看 new Function() 有一个 new,其实它并没有返回一个对象,却返回了一个函数;
    2. 例题中的 t(4)f1() 如果是在 Node.js 环境下执行的话,那会报错(找不到变量 a 或者 x 的 ReferenceError 错误),这是因为在 Node 环境下定义的 var xvar b 是在当前 Module 作用域下的,而不是全局作用于 global 这个对象上的。

    延伸

    eval

    阅读 MDN Web 文档后,文档中有说到由 Function 构造器创建的函数和使用 eval 执行创建函数是不同的,这里同样采用上面案例题目进行测试:

    var a = 1,
      b = 2;
      
    function test() {
      var b = 3;
    
      // return new Function('c', 'console.log(a + b + c)');
      eval('!function _ (c) { console.log(a + b + c) }(4)') // 输出 8
    }
    
    var t = test();
    // t(4); // 7
    

    在函数作用域中使用 eval 在函数声明的话,是存在于函数作用域中的,并且会形成闭包,由此这里可以验证 MDN 所描述的:由 Function 构造器创建的函数和使用 eval 执行创建函数是不同的。

    匿名函数自执行

    从上面延伸知识点的 eval 节可以看到,匿名函数自执行的时候,在前面加了一个 !,这是什么意思呢?

    其实这是告诉解析器,这是一段函数表达式,并且也只是匿名函数自执行的其中一个方法。

    +function () { console.log("self 1"); }();
    
    !function () { console.log("self 2"); }();
    
    (function() { console.log("self 3"); })();
    
    (function() { console.log("self 4"); }());
    
    [function() { console.log("self 5"); }()];
    

    以上几种方法都是匿名函数自执行的方法。

    考题学知识

    以下是一道面试题,能够全面认识到 function 的相关知识

    // func1
    function Foo() {
      getName = function () {
        console.log(1);
      }
      console.log(this);
      return this;
    }
    
    // func2
    Foo.getName = function () {
      console.log(2);
    }
    
    // func3
    Foo.prototype.getName = function () {
      console.log(3)
    }
    
    // func4
    var getName = function () {
      console.log(4);
    }
    
    // func5
    function getName() {
      console.log(5)
    }
    
    // print 1
    Foo.getName() // 2
    
    // print 2
    getName() // 4
    
    // print 3
    Foo().getName() // 1
    
    // print 4
    getName() // 1
    
    // print 5
    new Foo.getName() // 2
    
    // print 6
    new Foo().getName() // 3
    
    print 7
    new new Foo().getName() // 3
    
    // print 8
    new new Foo() // error,Uncaught TypeError: (intermediate value) is not a constructor
    

    看到上面执行的输出是不是有一些感到困惑,现在来分析一下,整个流程是怎么跑的。

    我们先来看看所有函数的声明和定义:

    1. 首先代码在执行的时候会进行一个预编译处理,而这个预编译的过程,按照从上到下声明一个 Foo 函数,也就是 func1,接下来会声明 getName,也就是 func5

    2. 预编译完成后,游览器执行这段代码,func2 会给 Foo 定义一个静态属性,func3 会给 Foo 定义一个原型属性,func4 执行的时候,会对全局 window 属性进行重新赋值,也就是上面第一点中的 getName 在这个时候会进行重新赋值

    到此函数的声明和定义就都完成了,在这里可以发现,func5 已经被覆盖掉了,将不会有进行调用它的机会了,下面我们来看看输出结果:

    // 这里执行的就是 Foo 的静态方法 fun2
    Foo.getName() // 2
    
    // 这里执行的是 func5,这里的 getName 的演变从 func5 -> func4
    getName() // 4
    
    // 这里首先执行的是 Foo,Foo 执行的时候,内部的 this 为全局 winsow 对象
    // Foo 中会进行 getName 重新赋值,所以 getName 的演变从 func5 -> func4 -> func1 中的 getName
    // 所以 Foo() 执行后返回 this -> window 然后执行 func1 中的 getName
    Foo().getName() // 1
    
    // 这里就是执行全局的 getName,他的演变过程为 func5 -> func4 -> func1 中的 getName
    getName() // 1
    
    // 这里就是执行 Foo 的静态属性 func2,只不过这个 func2 作为 new 的构造函数了一下
    new Foo.getName() // 2
    
    // 首先 Foo 作为构造函数 new 了一个实例,这时候 Foo 返回的 this 指的就是这个 new 出来的实例,然后使用该实例 this 调用 getName 就会执行 func3 的原型方法
    new Foo().getName() // 3
    
    //  Foo 作为构造函数 new 了一个实例, 然后返回的实例 this 执行了原型方法 getName 并且作为第一个 new 的构造函数
    new new Foo().getName() // 3
    
    // Foo 作为构造函数 new 了一个实例,然后这个返回的的实例对象作为第一个 new 的构造函数,这时候就会报错了,说了 new 的时候这个中间值不是一个构造函数
    new new Foo() // error,Uncaught TypeError: (intermediate value) is not a constructor
    

    下载网 » Function 知识储备

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元