从一道面试题谈js函数声明

时间:2022-05-23 19:11:58

爱奇艺前端面试题有个题目如下:

a();
function a(){
    console.log('a');
}

b();
var b = function(){
    console.log('b');
}
那么函数的执行结果是?

熟悉函数变量提升的同学很容易就想到答案是:a undefined。

不熟悉的童鞋们可以接着往下看~

JS关于函数的声明,有一个很重要的特征就是函数的变量提升。意思是在执行代码之前会先读取函数的声明。这就意味着可以把函数声明放在调用它的语句后面。

sayHi();
function sayHi(){
    alert('hi');
}

这个例子不会抛出错误,因为在代码执行前会被先去函数声明。
第二种创建函数的方式是使用函数表达式。函数表达式有几种不同的语法形式。下面是最常见的一种形式。

var functionName = function(arg0,arg1){
    //函数体
};

这种形式看起来好像是常规的变量赋值语句,即创建一个函数并将它赋值给变量functionName。这种情况下创建的函数叫做匿名函数,因为function关键字后面没有标识符。匿名函数的name属性是空字符串。(匿名函数有时候也叫拉姆达函数

函数表达式和其他表达式一样,在使用前必须先赋值。以下代码会导致错误:

sayHi();
var sayHi = function(){
    alert('hi');
}

这也就是上面那道题输出结果的原因。

另外,执行以下代码的结果可能会让人意想不到。

//不要这样做!
if(condition){
    function sayHi(){}
}
else{
    function sayHi(){}
}

表面上看,以上代码在condition为true时,使用一个sayHi定义,否则使用另一个。实际上,这在ECMScript中属于无效的语法,JavaScript引擎会尝试修正错误,将其转化为合理的状态。但问题是浏览器尝试修正错误的做法并不一致。大多数浏览器会返回第二个声明,忽略condition;FIrefox会在condition为true时返回第一个声明。因此这种使用方式很危险,不应该出现在我们的代码中。
这种形式,JS引擎在预编译的过程中会注册方法到window对象下,就是window.sayHi。而不会顾及if else条件,导致重复的sayHi方法被注册,在这种情况下是无效语法。
不过,如果是使用函数表达式,那就没什么问题了。

//可以这样做
var sayHi;
if(condition){
    sayHi = function(){
        ....
    }
}
else{
    sayHi = function(){
        ....
    }
}

这个例子不会有什么意外,不同的函数会根据condition被赋值给sayHi。