問題發生的過程
// <略>
const json = JSON.parse(body) // JSON 格式的字串 改成 "js的object"
// <略>
咦,奇怪了,片段程式碼呈現如上圖,都能夠成功執行 js 檔案,怎麼自從幫這行 code 加上 try catch
預抓錯誤時(如下圖),就無法順利執行 node.js 了哩?
// javascript
try {
const json = JSON.parse(body) // JSON 格式的字串 改成 "js的object"
} catch (error) {
console.log('ERROR!!!', error)
}
那就先讓我把 JavaScript 的 code 完整先貼出來吧。
hw1.js
const request = require('request')
const process = require('process')
request.get(
`https://restcountries.eu/rest/v2/name/${process.argv[2]}`,
(error, response, body) => { // body type: string
// 1st step : request() 出錯:通常是發送的過程有問題,然後沒有接到任何回應。
if (error) {
console.log(`請求錯誤: ${error}`)
}
// 2nd step :程式碼先處理Status Code 的4xx 5xx
if (response.statusCode >= 300) {
console.log(`請求錯誤,狀態碼:${response.statusCode}`)
return
}
// 3rd step:看有沒有成功把 API 的資料從「json 字串」轉成「js 的object」
try {
const json = JSON.parse(body) // JSON 格式的字串 改成 "js的object"
} catch (error) {
console.log('ERROR!!!', error)
}
// 4th step: 處理 API 資料,輸入國家,並印出國家資訊(國家、首都、貨幣、國碼)
if (json.message === 'Not Found') {
console.log('找不到國家資訊')
}
for (let i = 0; i < json.length; i++) {
console.log('============')
console.log(`國家:${json[i].name}`)
console.log(`首都:${json[i].capital}`)
console.log(`貨幣:${json[i].currencies[0].code}`)
console.log(`國碼:${json[i].callingCodes}`)
}
}
)
terminal
$ node w4hw3_sample.js tai
/Users/jeanlu/document/github/test_npm/w4hw3_sample.js:29
if (json.message === 'Not Found') {
^
ReferenceError: json is not defined
咦!!!我都設 json 為 const 了!怎麼還看不懂 json 這個變數呢?
然後參考了一下作業範例,我就嘗試了一下範例的設變數方法:
把 json 先設立一個空的 object,再到 try catch 裡面賦值。
let json = {} ;
try {
json = JSON.parse(body) // JSON 格式的字串 改成 "js的object"
} catch (error) {
console.log('ERROR!!!', error)
}
然後執行一下 node hw1.js,就成功了耶~
$ node w4hw3_sample.js tai
============
國家:Taiwan
首都:Taipei
貨幣:TWD
國碼:886
============
國家:United Kingdom of Great Britain and Northern Ireland
首都:London
貨幣:GBP
國碼:44
============
國家:Lao People's Democratic Republic
首都:Vientiane
貨幣:LAK
國碼:856
那這樣到底是發生什麼事呢?
這樣看來好像是跟Block Scope(區塊作用域)有關!
那這樣就牽扯到 let
、const
、var
設立變數的作用範圍,好像可以也可以白話稱為變數的生存範圍(我覺得這樣貼切多了!)ˋ
在 ES6 版本中,對let
、const
、var
有新的講法:
let
、const
作用於區域範疇(block-scoped),意思就是說只會生存在{}
內,出了這層{}
,就死掉沒有作用了。var
則相反,沒有此區域範疇(block-scoped)的限制,仍可以在{}
之外存活,不過他的存活範圍為function
。
講完規則,就來看看範例吧!
1. let 存活的範圍:
let credit = 3
let passGame = true
if (passGame) {
let credit = 4
console.log(`credit in if{} is ${credit}`) // 4
}
console.log(`credit outside if{} is ${credit}`) // 3
執行後,得:
// execute code:
credit in if{} is 4
credit outside if{} is 3
let 在 ES6 中新規則裡,只作用於 block-scoped
,也就是只有在 if { credit }
的 credit 為 4,出了 if
這層就死掉沒有作用。
在 if { credit }
外的 credit 為 3,因為在同一層中有設立變數 credit = 3
。
因為上面(那層)的東西看不到底下的(那層),底下(的層)的看的到上面(那層)的東西
2. var 存活的範圍:
(1) var 作用不限於 block-scoped
var credit = 1;
var passGame = true;
if (passGame) {
var credit = 2;
}
console.log(credit); // 2
var
不受 block-scoped 限制,所以可以存活於 if{}
之外,然後在 console.log
credit 時,找的是最近的一個,也就是 2
。
從近的先找,先找先贏
(2) var 作用範圍在 function 內
var a = 16
function test() {
if ( a > 15 ){
var a = 20
}
return console.log(`in function a = ${a}`)
}
test()
console.log(`outside function a = ${a}`)
執行後,得:
in function a = undefined
outside function a = 16
如果設立判斷式為 ‵if (a > 15)‵ 的話,執行 test()
會發現 a = undefined
。
咦,直覺上,我覺得:不是應該遵照上面一行的 var a =16
嗎?
但實際上在 JavaScript 都有變數的存活規則,在 var
裡生存規則就是 function
的範圍。
如果把判斷式改成 ‵if (20 > 15)‵,順利讓 function 內的 if 判斷成功,執行 var a =20
的結果如下:
in function a =20
outside function a =16
在 function 內的 a 為 20,在 function 內的 a 為 16。
Summary:
- let, const 變數生存範圍(scope)在一個 block 內(即
{}
)。 - var 變數生存範圍(scope)在一個 functions 內。
- 盡量使用 let,因為作用域越小越好,為什麼越小越好呢?因為不會干擾到其他人,比較好 debug。如果作用域太大,可能會干擾到人。
- 秘訣:
(1) 因為上面(那層)的東西看不到底下的(那層),底下(的層)的看的到上面(那層)的東西
(2) 從近的先找,先找先贏
參考
What is the Temporal Dead Zone (TDZ) in JavaScript? FreeCodeCamp
Scope MDN