我的情况下,函数声明和函数表达式的区别是什么?

7

请有人解释一下这里到底发生了什么。

 var y = 1;
 if (function f(){return 'some text';}) {
     y += typeof f;
 }
 console.log(y);// "1undefined"

如果我将它改为函数表达式
 var y = 1;
 if (a = function f(){return 'some text';}) {
     y += typeof a;
 }
 console.log(y);// "1function"

5
这是两种表达方式,而在一个函数表达式中,其名称只能在函数内部被访问。 - georg
说实话,当我看到第一个片段中 typeof f 的输出时,我不得不再看一遍,直到我记起它实际上不是函数声明。 - Patrick Roberts
你应该看一下 https://kangax.github.io/nfe/ 。 - Felix Kling
4个回答

4

if语句的条件始终是一个表达式。在第二种情况下,它是一个赋值表达式,将全局变量a设置为一个函数;在第一种情况下,它只是一个函数表达式,该函数无处存储(未被存储)。f仅仅是函数内部(用于递归)函数的名称。因此,f在其外部未定义。


2

函数声明会在当前作用域中创建一个同名变量。

function a() {
    function b() {
    }
}

在上面的例子中,变量b是在a的作用域中创建的。
函数表达式会在其自身的作用域中创建一个同名变量。
function a() {
    (function b() {
    })
}

在上面的例子中,变量bb的范围内创建,但不在a的范围内。
在您的第一个例子中(一个命名函数表达式),f在函数外部不存在,因此它是undefined
在您的第二个例子中(也是一个命名函数表达式),您明确地将函数分配给a(一个隐式全局变量),因此它被定义。
您的两个例子都没有函数声明,尽管您的问题标题是这样的。将function关键字放在if()条件内使其成为表达式,就像将其放在=的RHS一样。

0

看看这些例子:

// function declaration
function A() { return 'AAAA'; }
console.log('A: ', typeof A); // A: function

// mixing function declaration and expression - wrong way 
b = function B() { return 'BBBB'; };
console.log('b: ', typeof b); // b: function
console.log('B: ', typeof B); // B: undefined
// Why?
// 'B' is declared inside an expression and 'dies' after the expression
// ends, i.e. after b get assigned the right side of '='
// 'b', on the other side, got the function assigned and lives
// further on the scope.

// function declaration - right way
b2 = function() { return 'BBBB'; };
console.log('b2: ', typeof b2); // b2: function

// declaring the function inside the 'if' expression... same as with B
if(function C() { return 'C';}) {
 console.log('C (in): ', typeof C); // undefined
}
console.log('C: (out)', typeof C); // undefined
// ... it's the same as in here:
x = (function D() { return 'D';});
console.log('x: ', typeof x); // function
console.log('D: ', typeof D); // undefined

// assigning a variable (same as with 'B' example)
if(z = function Z() { return 'Z'; }) {
 console.log('z: ', typeof z); // function
  console.log('Z: ', typeof Z); // undefined
}
// ... and the same as with Z
y = (z2 = function Z2() { return 'Z2'; });
console.log('y: ', typeof y); // function
console.log('z2: ', typeof z2); // function
console.log('Z2: ', typeof Z2); // undefined


0

两者的区别在于第一个示例展示了一个函数表达式作为if语句的条件表达式。函数表达式不会在封闭范围中产生命名实体,根据ECMA-262[2015] §14.1.20加粗是我自己添加的):

注2

FunctionExpression中的BindingIdentifier可以从FunctionExpressionFunctionBody内部引用,以允许函数递归调用自身。但是,与FunctionDeclaration不同,FunctionExpression中的BindingIdentifier不能被引用并且不影响封闭FunctionExpression的范围。

它被解释为FunctionExpression而不是FunctionDeclaration的原因是,它作为if语句的条件表达式给出,如ECMA-262 [2015] §13.6.7中所定义:

运行时语义:评估

IfStatement : if ( Expression ) Statement else Statement

您的第二个示例有效,因为if条件表达式是一个赋值表达式,其评估将function expression(即函数对象)的结果分配给已在封闭范围中声明的变量a

这里提供的参考文献是ECMAScript 2015,但规范的早期版本中也提供了几乎相同的条款。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接