为什么将函数c赋值给变量b,在函数体里面,给c赋值,为什么会失败

为什么将函数c赋值给变量b,在函数体里面,给c赋值,为什么会失败?也就是这代码执行时为什么c打印出来的不是3

var  b = function c () {
    a=1, b=2, c=3;
    console.log(a);
    console.log(b);
    console.log(c);
}
b();
阅读 4.3k
5 个回答

简单回答一下吧。

var b = function c()

函数的名字是 c 而不是 b

先理解 2 个概念:函数表达式与函数声明。

function c (){};

函数声明,因为它是程序的一部分。

var b = function c(){};

函数表达式,因为它是赋值表达式(AssignmentExpression)的一部分。

两者有一个差别就是:函数声明会在任何表达式被解析和求值之前先行被解析和求值。即使声明位于源代码中的最后一行,它也会先于同一作用域中位于最前面的表达式被求值。

在你给出的代码中:

var  b = function c () {
    a=1, b=2, c=3;
    console.log(a);
    console.log(b);
    console.log(c);
}
b();

执行的结果是:

  • a 是 1
  • b 是 2
  • c 是函数

为什么 b 不是函数呢?而 c 却是函数呢?

如果我们把最后的函数调用换成 c:

var b = function c() {
    a=1, b=2, c=3;
    console.log(a);
    console.log(b);
    console.log(c);
}
c();

运行时会报错:

平时我们都是使用匿名函数表达式,突然出现一个 var b = function c(){} 时突然懵逼了,难怪 @shangguanyuanheng 会有疑问:“还有这种操作??”

函数有名字不是很正常的事儿吗。但是这个函数名只能在函数内部使用。So,第二个疑问解开了:

为什么调用 c() 时抛出了 Uncaught TypeError: c is not a function 异常,因为 c 只在函数内部有效。

最后解释题主的疑问:

在函数体里面,给 c 赋值,为什么会失败?

前面加个 'use strict' 就清楚了。

大概查了一下规范,在具名函数表达式的规范中,可选的函数名(标识 Identifier)会执行 CreateImmutableBinding http://www.ecma-international...

可以看下这篇文章,大概意思是命名函数表达式NFE的名字是存在一个辅助特殊对象(auxiliary special object)中的,而且是只读的,所以在非严格模式下修改会静默失败,如果这段函数内部在严格模式下运行会报错Uncaught TypeError: Assignment to constant variable.,其他答案中说的c被定义成全局是不对的,可以试一下把console.log(c)改成console.log(window.c)也是undefined

感谢@Showonne指出的错误,我修改下答案:
首先根据题主的结果:

clipboard.png

a=1,b=2,c=function c(){}

其实代码执行完后,题主的代码,就相当于

var a=1; //这个地方也可能仅仅是 var a; a=1 的赋值操作还保留在下面函数内,不好验证
var  b = function c () {
    b=2; //成功覆盖了前面的 b,把 b 由function c 改成了 2;
    c=3; //函数体内存在局部变量 c 指代函数本身,但是这个局部变量不可写,所以赋值失败
    console.log(a);
    console.log(b);
    console.log(c);
}
b();

主要是两点:
1.局部变量定义 a=1 没有用 var,所以js后台会默认你定义的是全局变量,所以题主的 a 是 1;

clipboard.png

2.全局变量 b 在函数内被 b=2 重新赋值,所以输出 2;
3、重点,需要举例子

var b=function c(){
    console.log(c)
};
b();

clipboard.png

这里返回的是函数 c ,原因如下:

clipboard.png

那么 c=3; 其实就相当于重新赋值了,那这种情况下,你要看下它允不允许重新赋值了,代码:

var b = function c() {
    c = 3;
    console.log(c);
};
b();

clipboard.png

这就证明了这个赋值是失败的,函数定义表达式带名称中的函数体内的名称标识符指向的是函数本身,且不可写,严格模式下,会报错:

clipboard.png

字面理解就是赋值给了常量,所以如果你硬是要改变 c 的值,可以这样声明一个变量就好:

var b = function c() {
    var c = 3;
    console.log(c);
};
b();

最后,这种函数定义表达式带名称的用法不常见,但是用来递归的时候很方便,详情戳这里

新手上路,请多包涵

虽然讲不出为什么
但是
这种代码 可读性极差
祝早日出现大神能解答一下

var  b = function c () //还有这种操作??
推荐问题
宣传栏