問題描述:
我有兩個js文件
我在第一個js文件中定義了一個這個函數(shù)
function formHeader (msg) {
let formHeaderContent = `
<caption>${msg}</caption>
<tr>
<th>商品</th>
<th>地區(qū)</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) {
// 輸出表頭:商品、地區(qū)、1月、2月、…… 12月
// 遍歷數(shù)據(jù) {
// 輸出每一行的表格HTML內(nèi)容
// }
// 把生成的HTML內(nèi)容賦給table-wrapper
const formHeader = formHeader(msg);
....
}
寫了一個這個函數(shù),然后報錯說 Uncaught ReferenceError: formHeader is not defined
我是這么理解的:我這個函數(shù)是在另一個js文件的全局里聲明定義的,為什么在這里它會報錯undefined?我的理解是兩個.js都屬于一個全局環(huán)境,我在其中一個.js中生命函數(shù),另外一個.js也應該能進行調(diào)用才對,不知道哪里理解的有問題
它和這個函數(shù)又什么區(qū)別呢?
function abc(val) {
return val;
}
var abc = abc('hello') // 這個就可以正常輸出一點一點說:
第一,你的原話是這樣的: "我是這么理解的:我這個函數(shù)是在另一個js文件的全局里聲明定義的,為什么在這里它會報錯undefined?我的理解是兩個.js都屬于一個全局環(huán)境,我在其中一個.js中生命函數(shù),另外一個.js也應該能進行調(diào)用才對";
你的全局聲明引用是沒問題的,前提是引入順序正常。
下面說說為什么會報錯,錯誤發(fā)生在你的第二個函數(shù)里面
先詳細說明一下es6規(guī)定的let和const特性,
es6出的 let 和 const都存在一種特性,沒有之前var的變量聲明提升,而引入了一個綁定區(qū)域,也叫暫時性死區(qū)。
什么意思呢?就是說在未對這個變量聲明之前不可使用,哪怕上層作用域已經(jīng)聲明了這個變量,如下:
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
當然你的 錯誤并不是 暫時性死區(qū) 引發(fā)的。
你這個屬于在 變量聲明完成之前使用變量錯誤,正在創(chuàng)建變量,還沒有創(chuàng)建完畢,
這兩段代碼的區(qū)別就在于第一段創(chuàng)建了一個新的formHeader局部常量,第二段沒有。
我的理解是兩個.js都屬于一個全局環(huán)境,我在其中一個.js中生命函數(shù),另外一個.js也應該能進行調(diào)用才對
沒錯,這么寫是可以的:
function renderForm(data, msg) {
const formHeaderValue = formHeader(msg);
}
為什么在這里它會報錯undefined?
新人最常見的錯誤,就是以為賦初值是先計算右邊,再創(chuàng)建變量,再賦值。但實際上,是先創(chuàng)建變量,再計算右邊,再賦值。程序看到const formHeader的時候,會立即記下formHeader是個局部變量,再去計算右邊的時候,formHeader已經(jīng)是局部的未初始化的值了,而不是外部的函數(shù)。
第二段因為一直在同一個作用域內(nèi),第二次var沒有創(chuàng)建新的變量,所以可以。
有評論在上面講“l(fā)et/const 變量只有定義被求值后才會初始化”。如果“初始化”是指“記為本地變量”,那么這個評論就是錯誤的。
考慮:
function foo() {} { };
(function () {
debugger;
const bar = foo();
const foo = bar;
})()
foo
可能有些同學對let/const產(chǎn)生了誤解,以為它們就不會變量提升了。事實上,JS引擎還是先掃描一次所有定義,生成Scope,然后再處理代碼邏輯。為了在效率和方便之間平衡,這么做是必須的。過于簡化地講,let/const跟var唯一的差別就是把undefined換成了ReferenceError。所以我上面說,formHeader已經(jīng)是局部的未初始化的值了,就是指訪問的時候會根據(jù)用的關(guān)鍵詞返回該關(guān)鍵詞對應的未初始化值(var的undefined,let/const的ReferenceError)。
可能我沒有直接解釋ReferenceError的問題,但是我覺得“變量聲明的時機”才是更根本的問題,畢竟題主問題的標題是“當函數(shù)賦值給相同名稱的變量”,而且就算是老手也不一定能弄明白。樓上各位都直接解釋暫時性死區(qū),但是換成var之后,第一段代碼一樣不能運行,題主又會到SF上提修改后的問題。
下面的評論說“應該報的錯的是 formHeader is not a function.”,實際上如果把題主的const換成var,或者hack進瀏覽器內(nèi)核禁用TDZ,報的正好是這個錯誤。
北大青鳥APTECH成立于1999年。依托北京大學優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
達內(nèi)教育集團成立于2002年,是一家由留學海歸創(chuàng)辦的高端職業(yè)教育培訓機構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
北大課工場是北京大學校辦產(chǎn)業(yè)為響應國家深化產(chǎn)教融合/校企合作的政策,積極推進“中國制造2025”,實現(xiàn)中華民族偉大復興的升級產(chǎn)業(yè)鏈。利用北京大學優(yōu)質(zhì)教育資源及背
博為峰,中國職業(yè)人才培訓領(lǐng)域的先行者
曾工作于聯(lián)想擔任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔任項目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍懿科技有限責任公司從事總經(jīng)理職務負責iOS教學及管理工作。
浪潮集團項目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗,技術(shù)功底深厚。 授課風格 授課風格清新自然、條理清晰、主次分明、重點難點突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應用開發(fā)經(jīng)驗。曾經(jīng)歷任德國Software AG 技術(shù)顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。