小昱个人博客
欢迎来到小昱的世界

勤学如春起之苗,不见其增,日有所长;辍学如磨刀之石,不见其损,日有所亏
js中关于闭包、匿名函数及其自执行的总结
  • 首页 > 前端 > JavaScript
  • 作者:小昱
  • 2017年8月29日 11:51 星期二
  • 浏览:108
  • 字号:
  • 评论:0
  • 一、普通具名函数

    function show(data) {
       console.log(data)
    }
    <button onclick="click1()">点击测试1</button>
    function click1(){
        fun1()
        function fun1(){
           show('fun1')
        }
        fun1()
    }

    上述代码中,fun1为普通命名函数,可以正常执行。

     

    二、函数表达式

    <button onclick="click2()">点击测试2</button>
    function click2(){
        try{
            fun2()
        }catch(e){
            show('报错,未定义,匿名函数表达式不会预先提升')
        }
        var fun1 = function(){
           show('fun2')
        }
        fun2()
    }

    上述代码不会执行,定义了匿名函数,使用fun1指向这个匿名函数,JS中的变量提升只提升其定义,不会提升其值或具体实现。

     

    三、匿名函数自执行

    <button onclick="click3()">点击测试3</button>
    function click3(){
        ;(function(){
            show('fun3')
        })()
    }
    

    匿名函数自执行的常见写法:

    (function () { /* code */ } ()); 

    其他写法:

    !function(){alert('iifksp')}();        // true
    +function(){alert('iifksp')}();        // NaN
    -function(){alert('iifksp')}();        // NaN
    ~function(){alert('iifksp')}();        // -1
    
    var i = function(){return 10}();       // undefined  
    1 && function(){return true}();        // true  
    1, function(){alert('iifksp')}();      // undefined  
    
    void function(){alert('iifksp')}()       // undefined  
    new function(){alert('iifksp')}()        // Object  
    delete function(){alert('iifksp')}()     // true  
    
    (function(){alert('iifksp')})()        // undefined
    (function(){alert('iifksp')}())        // undefined

    为什么将函数体部分用()包裹起来或者在函数体前加上 ! ~ - + 就可以了呢?

    原来,使用括号包裹定义函数体,解析器将会以函数表达式的方式去调用定义函数。

    也就是说,任何能将函数变成一个函数表达式的作法,都可以使解析器正确的调用定义函数。而 ! 就是其中一个,而 + - ~ 都有这样的功能。

    另外,用 ! 可能更多的是一个习惯问题,不同的运算符,性能是不同的。[引用]

    任何消除函数声明和函数表达式间歧义的方法,都可以被解析器正确识别[引用]

     

    看下例

    <button onclick="click4()">点击测试4</button>
    function click4(){
        var fun4 = function(){
            show('fun4') 
        }();
        fun4()
    }

    同上例,函数会立即执行,但使用fun4()调用会报错

    Uncaught TypeError: fun4 is not a function

     

    四、实例解析: jQuery中的立即调用函数表达式

    写法一

    (function(window, factory) {
        factory(window)
    }(this, function(window) {
        return function() {
           //jQuery的调用
        }
    }))

    写法二

    var factory = function(){
        return function(){
            //执行方法
        }
    }
    var jQuery = factory();

    写法三

    (function(window, undefined) {
        var jQuery = function() {}
        // ...
        window.jQuery = window.$ = jQuery;
    })(window);

     

    按照这种方式,写几个示例

    示例一

    var a = {
        a1: 1,
        a2: 2
    }
    
    let b = {
        b1: 1,
        b2: 2
    }
    
    console.log(a);
    console.log(b);
    console.log(window.a);
    console.log(window.b); // undefined
    console.log(window.a === a); // true
    console.log(window.b === b); // false
    
    ;(function(arg, scope, fun) {
        fun(arg, scope)
    })(a, this, function(window, scope) {
        console.log(window);
        console.log(window.a1);
        console.log(window.a2);
        console.log(scope);
    })
    
    ;(function(arg, scope, fun) {
        fun(arg, scope)
    })(b, this, function(window, scope) {
        console.log(window);
        console.log(window.b1);
        console.log(window.b2);
        console.log(scope);
    })

    这里面,使用var在全局定义了一个a,绑定到window上,可以在全局用window.a调用,使用let定义的b,并没有绑定到window上,而只是在当前作用域内有效。

    在立即执行函数中,绑定了a和b,将匿名函数用fun接收,将a和b用arg接收,执行工厂函数fun,将arg用window接收,因此window不在指向全局的window,而是传入的a和b

    将全局的window (全局可以使用this代替) 传入,使用scope接收,打印出的scope即是window

     

    示例二

    var a = {
        a1: 1,
        a2: 2
    }
    
    ;(function(arg, scope, fun) {
        fun(arg, scope)()
    })(a, this, function(window, scope) {
        return function() {  
            console.log(window);
            console.log(window.a1);
            console.log(window.a2);
            console.log(scope);
        }
    })

     

    示例三

    var a = {
        a1: 1,
        a2: 2
    }
    
    var fun = function(window, scope) {
        return function() {  
            console.log(window);
            console.log(window.a1);
            console.log(window.a2);
            console.log(scope);
        }
    }
    
    fun(a, this)()

     

    示例四

    var a = {
        a1: 1,
        a2: 2
    }
    
    ;(function(arg) {
        var fun = function(data) {
            console.log(arg);
            console.log(data);
        }
        arg.fun = fun;
    })(window)
    
    fun(a)

     

    需要注意的是

    立即执行函数前面要加一个分号,否则控制台会报错

    Uncaught TypeError: (intermediate value)(intermediate value) is not a function

     


    参考资料

    http://www.imooc.com/code/3247

    http://www.cnblogs.com/beijingstruggle/p/5970824.html

    js函数前加分号和感叹号是什么意思?有什么用?

    function与感叹号

     

      您阅读这篇文章共花了:  
    二维码加载中...
    本文作者:小昱      文章标题: js中关于闭包、匿名函数及其自执行的总结
    本文地址:http://www.xiaoyulive.top/?post=127
    版权声明:若无注明,本文皆为“小昱个人博客”原创,转载请保留文章出处。
    返回顶部| 首页| 碰碰手气| 捐赠支持| 手机版本|后花园

    Copyright © 2016-2017 小昱个人博客 滇ICP备16006294号