一段代码及输出如下:
b = c;
b();
console.log(a); //1
console.log(b); //2
console.log(c); //3
function c() {
a = 1, b = 2, c = 3;
};
将上述代码稍作修改:
b = function c() {
a = 1, b = 2, c = 3;
};
b();
console.log(a); //1
console.log(b); //2
console.log(c); //Uncaught ReferenceError: c is not defined
再次将上述代码稍作修改:
b = function c() {
a = 1, b = 2, c = 3;
console.log(a); //1
console.log(b); //2
console.log(c); //fuction c(){...
};
b();
不知所以然,如何才能正确解释上述三段代码中的变量c
?
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
众所周知,JS的变量和函数声明都会被存储到执行上下文的变量对象(或活动对象)中,即声明提前。
函数声明 的优先级 高于 变量声明的优先级,但 不会 覆盖变量赋值。
记住一点: 命名函数表达式的标示符(即函数名称)在外部作用域是无效的
参考:深入理解JavaScript系列(2):揭秘命名函数表达式
上面问题主要就是,命名函数表达式的问题
命名函数表达式
规范规定:标示符不能在函数体外的作用域内有效
所以,bar只在定义的函数作用域内有效,也不能被覆盖
函数声明
函数声明不存在作用域的问题,但是为污染函数定义
第一个,是变量声明提升和变量作用域。
函数
c
的声明会被自动提到最前。见 http://segmentfault.com/q/1010000003843499/a-1020000003843572
在函数中,一个变量定义不加
var
是全局变量,所以函数执行之后会覆盖初始值。也就是在函数中那几个变量是全局变量。第二个,是 函数声明和函数表达式 的区别
参考 http://segmentfault.com/q/1010000003864900/a-1020000003866303
第三个,如上,在
词法记录器
中定义的那个c
是只读变量,可以被重新定义,但是不能被重新赋值。也就是说这个c
是只读的。当然你也可以重新声明一个c
。当然这c
与原本那个就没有关系了。第一段代码
要理解这段代码要知道三点
不用
var
声明的变量为全局属性变量声明和函数声明会提前
同名的变量声明不会覆盖函数声明(注意是声明不是赋值)
知道了这三个后,其实上面的代码真正的运行情况是这样的
第二段代码
这个和上面的类似,其实就是值的覆盖,但是有问题的是为什么 c is not defined
当我们在表达式的位置写函数的时候,不管函数是否有函数名,都为函数表达式,函数表达式若有函数名,该名字不可以在外部使用,只能在内部使用
当函数表达式有函数名,并且执行的时候,函数里就会多出一个特殊的对象,这个对象只有一个属性,属性名为该函数名,值为对这个函数的引用,所以才能在自身调用 详情看这里
所以当
b
执行的时候,a
为全局属性,b
为全局属性,c
是对自身函数的引用,然而不能对c
进行修改(详情看评论),所以c
还是局部变量,不能在外部访问,所以报错 - 谢谢@FE的指出第三段代码
第三段代码和第一段一样,因为 c 已经赋值为 3
typeof c = 'number'
所以就报 c is not a function这个考的应该是具名函数表达式。
依我粗鄙的理解:
具名函数表达式和一般的函数表达式最大的区别是 在具名函数内部可以同过标识符foo(函数名)访问到函数自身。
那么第二段代码容易理解了
第三段函数内 c 的值没有覆盖,我就无法解释原因了
第二段代码,和第三段代码 c 为啥没有被全局变量覆盖?
这个问题可以了解一下, 深究就没什么必要了.
只要命名的时候加个var, 就能避免很多乱七八糟的问题