您现在的位置:首页 >> 前端 >> 内容

函数声明和函数表达式的区别

时间:2017/9/13 10:33:00 点击:

  核心提示:首先,我们来完成一些小测试:test1:function foo(){function bar() {return 3;}return bar();function bar() {return 8;}...

首先,我们来完成一些小测试:

test1:

function foo(){
    function bar() {
        return 3;
    }
    return bar();
    function bar() {
        return 8;
    }
}
alert(foo());

test2:

function foo(){
    var bar = function() {
        return 3;
    };
    return bar();
    var bar = function() {
        return 8;
    };
}
alert(foo());

test3:

alert(foo());
function foo(){
    var bar = function() {
        return 3;
    };
    return bar();
    var bar = function() {
        return 8;
    };
}

test4:

function foo(){
    return bar();
    var bar = function() {
        return 3;
    };
    var bar = function() {
        return 8;
    };
}
alert(foo());

答案:8、3、3、[Type Error: bar is not a function]

什么是函数声明?

Function Declaration 可以定义命名的函数变量,而无需给变量赋值。Function Declaration 必须以“function”开头。

function bar() {
    return 3;
}

函数名在自身作用域和父作用域内是可获取的(否则就取不到函数了)。

   function bar() {
        return 3;
    }

    alert(bar()); //3
    alert(bar)  //function bar(){return 3;}

什么是函数表达式?

Function Expression 将函数定义为表达式语句(通常是变量赋值)的一部分。通过 Function Expression 定义的函数可以是命名的,也可以是匿名的。Function Expression 不能以“function”开头。

//anonymous function expression
var a = function() {
    return 3;
}

//named function expression
var a = function bar() {
    return 3;
}

//self invoking function expression
(function sayHello() {
    alert("hello!");
})();

函数名(如果有的话)在作用域外是不可获取的(与 Function Declaration 对比)。

现在来解释下前面的测试。

test1 用了 function declaration,也就是说它们 get hoisted(被提升了)

什么是 Hoisting?
这里引用 Ben Cherry的话:“Function declaration和function variable(函数变量)通常会被 JavaScript 解释器移(‘hoisted’)到当前作用域顶部”。

function declaration 被提升时,整个函数体都会随之提升,所以 test1 的代码经过解释器解释后是像这样运行的:

//**Simulated processing sequence for Question 1**
function foo(){
    //define bar once
    function bar() {
        return 3;
    }
    //redefine it
    function bar() {
        return 8;
    }
    //return its invocation
    return bar(); //8
}
alert(foo());

Function Expression 会被提升吗?

这取决于表达式。比如 test2 中的第一个表达式:

var bar = function() {
    return 3;
};

等号左边的(var bar)是 Variable Declaration。Variable Declaration 会被提升,但是 Assignment Expression(赋值表达式)不会。所以当 bar 提升时,解释器会这样初始化:var bar = undefined。而函数定义本身不会被提升。所以 test2 的代码经过解释器解释后是像这样运行的:

//**Simulated processing sequence for Question 2**
function foo(){
    //a declaration for each function expression
    var bar = undefined;
    var bar = undefined;
    //first Function Expression is executed
    bar = function() {
        return 3;
    };
    // Function created by first Function Expression is invoked
    return bar();
    // second Function Expression unreachable
}
alert(foo()); //3

test 3 和 test 1 的逻辑相似。这次是 foo 函数被提升了。
test 4 就很简单了,根本就没有函数提升……

//**Simulated processing sequence for Question 4**
function foo(){
    //a declaration for each function expression
    var bar = undefined;
    var bar = undefined;
    return bar(); //TypeError: "bar not defined"
    //neither Function Expression is reached
}
alert(foo());

还应该注意什么?

官方是禁止在非功能模块(比如 if)中使用 Function Declaration 的。但是所有浏览器都支持,但是各自的解释方式不同。

例如下面的代码段在 Firefox 3.6 中会抛错,因为它将 Function Declaration 解释成了 Function Statement(见上文),所以 x 没有定义。但是在 IE8、Chrome 5 和 Safari 5 中,会返回函数 x(和标准的 Function Declaration 一样)。

function foo() {
    if(false) {
        function x() {};
    }
    return x;
}
alert(foo());

作者:网络 来源:lwf的博客