串接 API -- block-scoped 問題


問題發生的過程

// <略>
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(區塊作用域)有關!
那這樣就牽扯到 letconstvar 設立變數的作用範圍,好像可以也可以白話稱為變數的生存範圍(我覺得這樣貼切多了!)ˋ

在 ES6 版本中,對letconstvar有新的講法:

  1. letconst 作用於區域範疇(block-scoped),意思就是說只會生存在 {} 內,出了這層 {},就死掉沒有作用了。
  2. 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:

  1. let, const 變數生存範圍(scope)在一個 block 內(即 {} )。
  2. var 變數生存範圍(scope)在一個 functions 內。
  3. 盡量使用 let,因為作用域越小越好,為什麼越小越好呢?因為不會干擾到其他人,比較好 debug。如果作用域太大,可能會干擾到人。
  4. 秘訣:
    (1) 因為上面(那層)的東西看不到底下的(那層),底下(的層)的看的到上面(那層)的東西
    (2) 從近的先找,先找先贏
參考

What is the Temporal Dead Zone (TDZ) in JavaScript? FreeCodeCamp
Scope MDN

#block-scoped






你可能感興趣的文章

[第三週] NPM簡介

[第三週] NPM簡介

JavaScript 程式執行原理:JS實現物件導向

JavaScript 程式執行原理:JS實現物件導向

VSCode 終端機無法執行指令碼

VSCode 終端機無法執行指令碼






留言討論