先直接抛出问题:
- 以下代码报错,求解该怎么具体分析这个错误发生的原因?
(目测是受 ES6 块作用域 TDZ
的影响在 编译阶段 抛出的问题)
{
var foo = 1; // 该句报错,“foo 重复声明”
function foo(){};
console.log(typeof(foo));
}
小白的心路历程
(自学 js 中)最近在看《 you-dont-know-js 》—— js 的变量提升部分(一版,中文)
在作用域-函数优先部分有如下代码:
foo(); // "b"
var a = true;
if (a) {
function foo() { console.log( "a" ); }
}
else {
function foo() { console.log( "b" ); }
}
实际运行时发现 foo(); 一行报 TypeError: foo is not a function 错误。
思考之后觉得应该是 es6 块作用域的问题,导致 foo 的变量提升不如预期。遂更换 node 版本至 4.9 果然成功输出了 "b"
我的理解如下:
var foo;
var a;
foo(); // 此次相当于 foo 已声明,但未定义,暂为 undefined 。故报错
a = true;
if(a){
foo = function(){console.log("a")};
}else{
foo = function(){console.log("b")}
}
在理解上面这个出错问题的时候发现在块作用域下 var foo 变量声明和 foo 函数声明放在一起会报 重复声明 错。如下:
{
var foo = 1; // 该句报错,“foo 重复声明”
function foo(){};
console.log(typeof(foo));
}
已知 var 可重复声明,该情况(指同标识符的变量声明与函数声明)在全局、函数作用域下无 重复声明 问题。
(后测试同样的代码 node4.9 版本无此问题,个人考虑定位至块作用域特性相关问题,调试发现在还没执行下去的时候就已报错了,应该是 编译阶段 就抛出的问题。
个人基础较差,再往下就没啥头绪了,搜索"块作用域 var 函数声明 重复声明"相关字符也没找到结果。
希望各位 dalao 不吝赐教,指点以下该怎么分析这个问题(特性? 实际代码运行的时候是怎么样的情况?
好像就是重复申明了变量啊 改了一下就对了
{
var foo = 1; // 该句报错,“foo 重复声明”
foo = function (){};
console.log(typeof(foo));
}
emm 问题不是怎么改,主要是想知道 js 具体是怎么处理和判断这个错误的。
另外有趣的是在 Edge(非 chrome 内核版本,Microsoft Edge 44.19041.1.0)、ios(13.5.1)上的 safari 以及 nodejs6.0.0 以下版本执行不报错,直接输出"number"。
Firefox,safari,chrome,nodejs6.0.0 及以上的才会报重复声明的错
The function declaration in the block uses ES6 declaration semantics (like let or const), which does not allow redeclarations.
帮你在 stackOverFlow 上查了 还是多 google 好......
这里用的是 var,不算 ES6 declaration semantics 吧。
好像是 function declaration 的行为和 let const 一样 改为 let 有同样问题
{
var foo = 1; // 该句报错,“foo 重复声明”
let foo = function(){};
console.log(typeof(foo));
}
这个要看 ecma262 的规范,才比较好理解,推荐篇两篇文章,看懂执行模型就理解了,第一篇是 08 年的,不过讲的最清楚,不了解规范会有些复杂
https://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
https://juejin.im/post/6844903704466833421
你可以理解成 function xx 声明都会被改写成
var xx // 被提前到代码最开头
//执行你声明 function 前的代码
xx=function(){}
所以你写的代码执行顺序就是
var foo // function 声明的效果
var foo = 1; // 该句报错,“foo 重复声明”
foo=function(){};
console.log(typeof(foo));
其实没必要纠结这些,你也知道不同执行环境有不同执行结果,那就要避免写出这种代码,谁写生产环境写出这种代码那他会被捶死
大佬正解,最后一句高亮,一般这样的代码是真的不会放生产的,不符合代码规范不说,一旦出现 bug 会被 leader 锤死,老老实实搬砖不香吗
```js
{
var foo = 1; // 该句报错,“foo 重复声明”
function foo(){};
console.log(typeof(foo));
}
```
最后的代码 在 ES5 中应该是会报错的吧? 我想是因为函数声明提升和变量声明提升 但是函数声明提升优先于变量声明提升, 所以变成这样了:
```js
{
var foo = function() {}
var foo = 1;
console.log(typeof(foo));
}
```
所以在做提升的时候 也就是编译阶段就已经知道重复声明变量了 会提示 Identifier 'foo' has already been declared
我理解是这样
好像是这样的
var foo // function 声明的效果
var foo // 该句报错,“foo 重复声明”
foo = 1;
foo=function(){};
console.log(typeof(foo));
1.ES6 规定,块级作用域之中,函数声明语句的行为类似于 let ;
2.函数声明还会提升到所在的块级作用域的头部。
https://es6.ruanyifeng.com/#docs/let#块级作用域
为什么楼上那么多瞎回答的还能得赞... V2EX 水平堪忧
本来呢,var 确实是可以重复声明。
但是你用块级作用域({}) + 函数声明语句( function a(){})之后,就不可以重复声明了。
ES6 规定,块级作用域之中,函数声明语句的行为类似于 let 。
只要使以上 2 个条件任意一个失效即可。
1 、块级作用域干掉,改为用 function 包裹的方式;
2 、用函数表达式声明函数,即 var foo = function(){} 。
工作几年会发现 这是个无聊的问题。。
这个问题跟 ECMAScript 语言定义有关,ES5 之前,块内的函数声明是未定义行为,具体表现跟旧浏览器的实现有关,总体来说,这种方式是不推荐的。ES6 之后引入了块级作用域,对块内函数声明的语义也进行了定义,可以理解为 let 或 const,因此会报错。https://www.ecma-international.org/ecma-262//>为了历史兼容,其实块内函数声明会带来一些“bug”,具体见 https://www.zhihu.com/question/404772996
无聊的问题
养成习惯,手动提升,万事大吉
这种问题没必要研究, 这是 js 缺陷问题。 除非考 js 各种奇淫巧计