[乐意黎原创]JS函数声明、 函数表达式与立即执行函数的理解与执行顺序

定义函数的方法

定义函数的方法主要有三种:

  1. 函数声明(Function Declaration)
  2. 函数表达式Function Expression)
  3. new Function构造函数

其中,经常使用的是函数声明和函数表达式的函数定义方法,这两种方法有着很微妙的区别和联系,而且这两种方法的使用也容易混淆,所以这篇文章主要总结下这两种函数定义方法的相关知识点,当然本文的主题依然是关于函数提前的。

函数声明的典型格式:

function functionName(arg1, arg2, ...){
    
}

函数表达式

  • 函数表达式的典型格式:

    var  variable=function(arg1, arg2, ...){
                
    }
  • 包含名称(括弧,函数名)的函数表达式:

    var  variable=function functionName(arg1, arg2, ...){
            
    }

    像上面的带有名称的函数表达式可以用来递归:

    var  variable=function functionName(x){
            if(x<=1)
                return 1;
            else
                return x*functionName(x);
    }

声明提前

声明提前是函数声明和函数表达式的一个重要区别,对于我们进一步理解这两种函数定义方法有着重要的意义。

变量在声明它们的脚本或函数中都是有定义的,变量声明语句会被提前到脚本或函数的顶部。但是,变量初始化的操作还是在原来var语句的位置执行,在声明语句之前变量的值是undefined。

上面的结论中可以总结出三个简单的点:

  1. 变量声明会提前到函数的顶部;
  2. 只是声明被提前,初始化不提前,初始化还在原来初始化的位置进行初始化;
  3. 在声明之前变量的值是undefined。
     

看一个例子。

var aerchi='aerchi';
function aerchiToShow(){
	debugger;
    console.log(aerchi); //aerchi
}
aerchiToShow();// aerchi

上面代码正确的输出结果是:aerchi

再看下面的例子

var aerchi='aerchi';
function aerchiToShow(){
	debugger;
    console.log(aerchi); // undefined 
    var aerchi='aerliho';
    console.log(aerchi); //aerliho
}
aerchiToShow();
// undefined
// aerliho

上面代码正确的输出结果是:
先输出undefined,然后输出aerliho

注: 在声明之前变量的值是undefined,只是声明被提前,初始化并未提前,初始化还在原来初始化的位置进行初始化.

 

函数声明

   函数声明创建将来代码调用的函数。函数可以在声明之前的位置被调用。示例如下:   

//可以在声明之前的位置被调用  
var size=show("call before function");    
function show(str){  
   console.log(str);  
};  
//可以在声明之后的位置被调用  
var size2=show("call after function");  

[乐意黎原创]JS函数声明、 函数表达式与立即执行函数的理解与执行顺序_第1张图片

 

函数表达式

  将函数放在本该表达式待的位置,这称为函数表达式。在函数表达式中,经常使用匿名函数。示例如下:     

//会报错,变量aa 还未保存对函数的引用,函数调用必须在函数表达式之后 
var aa = showM("call before function");    
var showM = function(str){  
   console.log(str);  
};
//VM3235:1 Uncaught TypeError: showM is not a function
    at :1:10
var showM = function(str){  
   console.log(str);  
};  
//只能在函数表达式定义之后被调用
var bb = showM("call after function");  

[乐意黎原创]JS函数声明、 函数表达式与立即执行函数的理解与执行顺序_第2张图片
函数表达式相当于是是把函数对象赋值给一个变量

 对于函数表达式,变量赋值是不会提前的,即function(arg1, arg2, ...){}是不会提前的,所以函数定义并没有被执行,所以函数表达式不能像函数声明那样进行函数声明提前。

 

立即执行函数(IIFE)

   没有名称,在解释器经过它们时执行一次。示例如下:   

var showM = (function(str){  
   console.log(str);  
})("call me from function");
16:38:45.542 VM1255:2 call me from function
16:38:45.556 undefined
16:39:30.972 (function(str){  
   console.log(str);  
}("call me from function 2"));
16:39:30.971 VM1257:2 call me from function 2
16:39:30.994 undefined
16:39:44.131 !function(str){  
   console.log(str);  
}("call me from function 2");
16:39:44.131 VM1259:2 call me from function 2
16:39:44.145 true

[乐意黎原创]JS函数声明、 函数表达式与立即执行函数的理解与执行顺序_第3张图片

 

            //情况1  
            //结果会被输出  
            var fn=function(){  
                console.log("函数表达式赋值给一个变量");  
            }();  

            //情况2  
            //结果不会被输出,JavaScript引擎只解析函数声明,忽略后面的括号,函数声明不会被调用  
            function fn(){  
                console.log("函数声明");  
            }();  

            //情况3, 会输出:函数声明
            (function fn(){  
                console.log("函数声明");  
            })();  

            //情况4  
            //语法错误,匿名函数属于函数表达式,未执行赋值操作,不能被调用  
            function(){  
                console.log("函数表达式");  
            }();  
            //Uncaught SyntaxError: Function statements require a function name

            //情况5
            //输出  
            (function(str){  
                console.log(str);  
            })("函数表达式");  

经典的立即执行函数样式

(function(a){  console.log(a); })(123);  //123
(function(a){  console.log(a); }(1234));  1234
!function(a){  console.log(a); }(12345);  //12345
+function(a){  console.log(a); }(123456);  //123456
-function(a){  console.log(a); }(1234567);  //1234567
//而加上(),!,+,-等符号可以执行,是因为加上这些符号就可以告诉JavaScript引擎这不是函数声明了

注意:

只有函数表达式才能实现立即执行,匿名函数也是函数表达式为何不能立即执行呢,因为匿名函数开始的function会被JavaScript引擎识别为函数声明的开始,所以加上括号也不会被执行,而加上(),!,+,-等符号可以执行,是因为加上这些符号就可以告诉JavaScript引擎这不是函数声明了

函数声明、 函数表达式的执行顺序

函数声明:

1 function 函数名称 (参数:可选){
函数体
}

函数表达式:

1 function 函数名称(可选)(参数:可选){
函数体
}

 

function foo(){} // 声明,因为它是程序的一部分
var bar = function foo(){}; // 表达式,因为它是赋值表达式的一部分

new function bar(){}; // 表达式,因为它是new表达式

(function(){
	function bar(){} // 声明,因为它是函数体的一部分
})();
function foo(){} // 函数声明
(function foo(){}); // 函数表达式:包含在分组操作符内
  
try {
	(var x = 5); // 分组操作符,只能包含表达式而不能包含语句:这里的var就是语句
} catch(err) {
	// SyntaxError
}

来看一个函数声明、 函数表达式的执行顺序的例子

var getName = function () { 
    console.log('var getName 1');
};
function getName() { 
    console.log('function getName 1');
}

//下面的 getName 由于与最上的相同,故被重新赋新值
var getName = function () { 
    console.log('var getName 2'); //此函数表达式会被执行
};
function getName() { 
    console.log('function getName 2');
}
getName();

[乐意黎原创]JS函数声明、 函数表达式与立即执行函数的理解与执行顺序_第4张图片

上述代码的执行结果是:var getName 2
原因是这样的,
var声明的变量和函数声明function都会被提升,但是函数声明的提升的级别是比var要高的.

另一个示例:

var currying = function(fn) {
    // fn 指官员消化老婆的手段
    var args = [].slice.call(arguments, 1);
    // args 指的是那个合法老婆
    return function() {
        // 已经有的老婆和新搞定的老婆们合成一体,方便控制
        var newArgs = args.concat([].slice.call(arguments));
        // 这些老婆们用 fn 这个手段消化利用,完成韦小宝前辈的壮举并返回
        return fn.apply(null, newArgs);
    };
};

// 下为官员如何搞定7个老婆的测试
// 获得合法老婆
var getWife = currying(function() {
    var allWife = [].slice.call(arguments);
    // allwife 就是所有的老婆的,包括暗渡陈仓进来的老婆
    console.log(allWife.join(";"));
}, "合法老婆");

// 获得其他6个老婆
getWife("大老婆","小老婆","俏老婆","刁蛮老婆","乖老婆","送上门老婆");
//合法老婆;大老婆;小老婆;俏老婆;刁蛮老婆;乖老婆;送上门老婆

// 换一批老婆
getWife("超越韦小宝的老婆");
//合法老婆;超越韦小宝的老婆

本文地址: https://blog.csdn.net/aerchi/article/details/79805301

 

你可能感兴趣的:(Web,前端乱炖)