问题描述:
我有两个js文件
我在第一个js文件中定义了一个这个函数
function formHeader (msg) {
let formHeaderContent = `
<caption>${msg}</caption>
<tr>
<th>商品</th>
<th>地区</th>
<th>1月</th>
<th>2月</th>
<th>3月</th>
<th>4月</th>
<th>5月</th>
<th>6月</th>
<th>7月</th>
<th>8月</th>
<th>9月</th>
<th>10月</th>
<th>11月</th>
<th>12月</th>
</tr>`;
return formHeaderContent;
}
在第二个.js中
function renderForm(data, msg) {
// 输出表头:商品、地区、1月、2月、…… 12月
// 遍历数据 {
// 输出每一行的表格HTML内容
// }
// 把生成的HTML内容赋给table-wrapper
const formHeader = formHeader(msg);
....
}
写了一个这个函数,然后报错说 Uncaught ReferenceError: formHeader is not defined
我是这么理解的:我这个函数是在另一个js文件的全局里声明定义的,为什么在这里它会报错undefined?我的理解是两个.js都属于一个全局环境,我在其中一个.js中生命函数,另外一个.js也应该能进行调用才对,不知道哪里理解的有问题
它和这个函数又什么区别呢?
function abc(val) {
return val;
}
var abc = abc('hello') // 这个就可以正常输出
这两段代码的区别就在于第一段创建了一个新的
formHeader
局部常量,第二段没有。没错,这么写是可以的:
新人最常见的错误,就是以为赋初值是先计算右边,再创建变量,再赋值。但实际上,是先创建变量,再计算右边,再赋值。程序看到
const formHeader
的时候,会立即记下formHeader
是个局部变量,再去计算右边的时候,formHeader
已经是局部的未初始化的值了,而不是外部的函数。第二段因为一直在同一个作用域内,第二次
var
没有创建新的变量,所以可以。有评论在上面讲“let/const 变量只有定义被求值后才会初始化”。如果“初始化”是指“记为本地变量”,那么这个评论就是错误的。
考虑:
foo
可能有些同学对
let
/const
产生了误解,以为它们就不会变量提升了。事实上,JS引擎还是先扫描一次所有定义,生成Scope,然后再处理代码逻辑。为了在效率和方便之间平衡,这么做是必须的。过于简化地讲,let
/const
跟var
唯一的差别就是把undefined
换成了ReferenceError
。所以我上面说,formHeader
已经是局部的未初始化的值了,就是指访问的时候会根据用的关键词返回该关键词对应的未初始化值(var
的undefined
,let
/const
的ReferenceError
)。可能我没有直接解释ReferenceError的问题,但是我觉得“变量声明的时机”才是更根本的问题,毕竟题主问题的标题是“当函数赋值给相同名称的变量”,而且就算是老手也不一定能弄明白。楼上各位都直接解释暂时性死区,但是换成
var
之后,第一段代码一样不能运行,题主又会到SF上提修改后的问题。下面的评论说“应该报的错的是 formHeader is not a function.”,实际上如果把题主的
const
换成var
,或者hack进浏览器内核禁用TDZ,报的正好是这个错误。