iT邦幫忙

2021 iThome 鐵人賽

DAY 2
1
Modern Web

每日挑戰,從Javascript面試題目了解一些你可能忽略的概念系列 第 2

每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day2

  • 分享至 

  • xImage
  •  
tags: ItIron2021 Javascript

前言

昨天我們透過了一個相當經典的題目探討了基本的作用域(scope)與變數賦值的概念,讓我們沿續這兩個概念繼續進行另一個題目的練習吧! 由於只是概念的應用複習,今天的篇幅甚至會再更短一些! 一起放輕鬆來學習吧!

本日題目與解釋

請問下方的程式碼會有什麼輸出結果?

(function(){
  var a = b = 3
})();

console.log("a defined? " + (typeof a !== 'undefined'));
console.log("b defined? " + (typeof b !== 'undefined'));

這個題目也算相對常見的基本題型之一,當時是在一間博奕公司給的現場測驗中遇到這題目,好在之前自己練習時就有遇到類似的情境才不至於翻車?

先防雷,來張思考圖片擋一下,思考結束後再往下滑吧!

jerry-think

最終的輸出結果如下

a defined? false
b defined? true

最終a是個未定義的變數,但b則是一個已經定義的變數,且其值為3,那為什麼會有這樣的結果呢? 我們一個個重點來看吧!

  • var a = b = 3 與你想像的執行結果並不相同

很多人會以為下面兩種寫法是完全等價的

var a = b = 3

-----我是分隔線-----
var a = 3
var b = 3

但事實上由於運算子相依性(associativity,也有人說運算子結合率),上方的程式碼賦值部份會是右 -> 左進行,也就是說實際上會是這樣的

b = 3
var a = b

但這樣又有什麼差別呢? 關鍵在於b變成一個類似全域變數的存在,會掛在當下指向的global object下,以瀏覽器為例便是在window物件下
global variable

而var宣告的變數我們在昨天提過,它是functional scoped,也就是說a這個變數僅存在於該立即執行函數(IIFE)中,離開那個函數便無法被使用,最終自然變成not defined的變數囉!

也因此你在很多很多的教材中都會看到永遠都要用var、const/let來宣告變數,以免造成這樣意料之外的行為,現在許多的框架都會自動套用strict mode,在嚴格模式下就會預先替你把這樣的錯誤抓出來囉!
use strict

順帶一提,一次賦值多個變數的寫法是這樣的,利用這樣的寫法修改題目後就會看到我們預期的結果囉!

global variable2

本日核心觀念與總結

核心觀念

scope、變數宣告與賦值、運算子相依性

總結

  1. 永遠都要使用關鍵字宣告變數,以免造成預期外的結果,現在的框架基本上都會幫你做把關
  2. 一次賦值多個變數的寫法並不是var a = b = c,而是需要寫var a = 3, b = 3
  3. 賦值運算子為右相依性,從右判斷到左

本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!


上一篇
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day1
下一篇
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day3
系列文
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
osl_to_engr31
iT邦新手 5 級 ‧ 2021-09-24 13:01:36

Danny大,看完文章幫助我這個小菜雞對於Scope及賦值的概念又有更深一層的思考,不過有遇到一個疑問:
在上述的例子中,var a = 3, b = 3,a、b這兩個變數為什麼會是undefined,而非皆為defined呢?(自己的理解是兩個變數都被賦值過了)

看更多先前的回應...收起先前的回應...

你的理解沒有錯! 最後的例子其實不管是a、b都是宣告且賦值過的,不過就像我們在day1提到的,var宣告的變數屬於functional scoped,也就是說a, b兩變數很遺憾地只存在於那個立即執行函數中,你在其他地方試著印出來自然會是not defined囉!

另外請教關於block scoped,是只要用括號,不管是哪一種括號,即:用{}或(),都有區隔作用域的效果嗎?
而[]是不是都只用來表示陣列呢?

另外請教關於block scoped,是只要用括號,不管是哪一種括號,即:用{}或(),都有區隔作用域的效果嗎?

不用想得這麼複雜,簡單說就是絕大多數大括號{}包起來的程式碼區域就會切成一個block,像是條件式、迴圈甚至是函數都是常見的block。

[]是不是都只用來表示陣列呢?

這問題就有點突然了,不過我想你會這樣問應該是因為物件的宣告看起來也像是一個block. 但你可以放心,在js中[]確實就是表示陣列這個資料結構,沒有其他意思了。

Danny大的解惑很清楚明瞭,謝謝!

不會~! 很高興有幫上忙,若之後有其他問題或發現文章有什麼錯誤都歡迎你提出!

我要留言

立即登入留言