iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 3
1
Modern Web

【這些年我似是非懂的 Javascript】系列 第 3

【這些年我似是非懂的 Javascript】Day 3 - 你一定可以入的了門 #上篇

圖片來源

這篇要與您一同進入 JS 的入門世界,從基礎開始雖然乏味但是特別扎實,如果你已經有一定的基礎,那也很適合你檢視自己的觀念,如果有異直接發問與我討論,也可以幫助我釐清錯誤的觀念 xD

今日學習清單

  • 值與型別 ( Value and type )
  • 存在 JS 的萬年臭蟲
  • 極致隱藏版運算子 Void
  • 若有似無的 undefined
  • 物件 ( Object )
  • 陣列 ( Array )
  • 函式 ( Function )
  • 內建的方法
  • 比較值
    • 相等性
    • 不等性
  • Truthy & Falsy
  • 強制轉型 ( Coercion )

型別與值

Javascript 本身支援有型別的值,但是不支援有型別的變數
什麼意思?

白話版:

一個瓶子裡面可以裝東西,
你能定義瓶子裡面裝的東西是什麼型態,
比方說:
瓶子內裝著,而你可以定義裡面是這個型態
瓶子內裝著石頭,而你可以定義裡面是石頭這個型態
但是你不能定義這個瓶子是裝的或是裝石頭的。

請不要跟我說瓶子材質不一樣的問題xDD
運用你的想像力~ (・ω´・ )

程式版:

var a = 1;  // Number 
var b = "Hi"; //String
var c = [] ; // Object

當你使用 typeof 去檢視上面三個型態時,檢查的會是值的型態,而不是變數的型態。

存在 JS 的萬年臭蟲

typeof 1; // Number
typeof "Hi"; // String
typeof true; // Boolean
...

這些我們都知道,
再來!

typeof NaN; // Number

NaN => Not a Number
他主要是指無效的數字所以理解成 Number 也還說得過去...

但是...

typeof null; // ?  <- 猜猜我是誰

答案是...

Obejct

書中提到這是一個永遠不會修復的 Bug ,
原因是 Web 上有太多 Code 是依賴這個 Bug ,
如果修復的話會造成更多更多的 Bug, // 三壓
聽起來是一個塵封已久的霸王技術債。

極致隱藏版運算子 Void

我用了 JS 好歹也有個幾個月 (講得好像很久),
從來沒用過、沒聽過和沒看過 xDDD
(當然有可能是我太菜 (((゚Д゚;))))

他主要的功能只有一個就收到任何運算式或是值然後吐回 undefined
就是一個我給你錢你快做!

總而言之現在好像很少情境需要用到,
有興趣可以看這位大大的文章感覺講的滿細的。
推推 -> JS 冷知識: 你所不知道的 void

若有似無的 undefined

var a = undefined;

你把 a 設定成 undefined
但是其實跟沒做事一樣
就像是你用

var a;

達到的效果是一樣的
而要達到該變數為 undefined 有很多方法
包括剛剛上面講的 void

物件 ( Object )

他是一個複合值,什麼意思?
一般我們在 JavaScipt 說的基本上都是長這樣

var a ={
  b: "Hi~",
  c: 1232,
  d: true
};

他可以設定在這裡面的某個位置設定任何型別。
像是
a.b 就是 string
a.c 就是 Number
a.d 就是 Boolean

而你上面看到的 . 就叫做點記號法,而還有另一種存取方式叫做方括號記號法可以參考以下範例。

a[b]
a[c]
a[d]

而哪種比較好?
"通常"會直接選用點記號法比較好閱讀,原因很簡單!
因為比較短! xD
方括號記號法用在哪?
它存在就有他的意義!
假如你的物件特性名稱有特殊字元或是你存在一個變數就是使用方括號記號法的時機了。
例如

const name = 'Robin';
const myObject = {
    'Robin':{
        'age':18,
        'phone':'0912345678',
        'identity':'A123456788'
    },
    'Kevin':{
        'age':19,
        'phone':'0921345678',
        'identity':'A213456787'
    }
}

console.log(myObject[name])

output:

{
    'age':18,
    'phone':'0912345678',
    'identity':'A123456788'
}

那你可能會想說啊我就直接都用 點記號法,不行嗎?
答案是不行 xDD
來以上面的範例來說你直接使用點記號法~

console.log(myObject.name)

output:

undefined

原因是他會去找名為 namekey 值。

相信你已經蘆薈貫通了

陣列

看完一般的物件 (Object),陣列是什麼鬼!?
他還是一個物件 (Object) ,想不到吧!?
他是一個特化版的 object 型別,也可以說是 object 的子型別。
可以儲存任一型別的 object ( 跟剛剛講的物件一樣 ),
並且以數值化的索引位置來儲存。
直接來看範例

const arrayList = [
    'Robin',
    'Ron',
    'Kevin',
    'Robert',
    'York',
    'Haru'
];

arrayList[0]; // Robin
arrayList[1];// Ron
arrayList[2]; // Kevin
arrayList[3]; // Robert
arrayList[4]; // York
arrayList[5]; // Haru
arrayList.length; // 6

不懂?
來我們來看看以下這張圖

圖片來源

就是照順序放東西進去啦!
是不是很簡單~

函式

直接跟你說函式也是 object 的子型別,
但是不同的是當你使用 typeof 時他會回傳給你 function,這是他的一個主要的型別,並且可以擁有特性,就像是上面 object 物件一樣。 ( 這個我倒是看書才知道 xD )
來看範例

function foo(){
    return 18;
};

foo.bar = 'Robin';

typeof foo; // function
typeof foo(); // number
typeof foo.bar; // string

內建的方法

除了剛剛提到物件的那些特性,JS 還提供很多很猛很強大的功能,就是內建方法。
剛剛有看到陣列的範例中有 array.length; ,這就是內建的方法。
例如

const name = 'robin';
const pi = 3.141592653589;

name.toUpperCase(); // 'ROBIN'
pi.toFixed(2) // 3.14
...

那你會想說為什麼 toUpperCase 和那些東西我明明沒寫啊,
他怎麼知道?
簡單來說每個型別都有一個物件包裹器 (object wrapper),我覺得我會稱為他是型別小精靈,而這型別小精靈裡面富含很多內建的方法,如果你是他的型別他就會幫你做事,做他這個型別可以幫你做的事兒~

比較值

比較值有相等性不等性,最終都會回傳布林值的 true 或是 false

相等性

不相等 不等於 不等性,所以 !=!== 不在不等性裡頭。

在昨天那篇有提到 ===== 以及 !=!==,以往我自認為差別在於說一個會檢查值得型態一個不會,這個答案是錯誤的!
答案是一個允許強制轉型一個不允許強制轉型,也因為這樣 === 被稱為嚴格相等性,反之 == 則為寬鬆相等性。

那... 我該如何知道何時該使用 == 還是 === ?
簡單兩步驟讓你不再迷惘,
第一步你應該要知道 強制轉型 是如何 (how) 發生。
第二步你應該要知道 強制轉型 後值的變化會是如何,也就是 Truthy & Falsy
第三步你應該要遵守以下的四點準則

  • 當比較兩方有任何一方有可能會是 truefalse 時,你應該要使用 === 避免使用 ==
  • 當比較兩方有任何一方有可能是這些特定的值 ( 0, '', "", [] ),你應該要使用 === 避免使用 ==
  • 在其他所有的情況下,使用 == 都是安全的,甚至能夠提升可讀性並且簡化你的程式碼。
  • 如果你都不確定,就都使用 ===,但是以上三點都是希望你能夠更能理解你到底在寫什麼和思考可能會發生的情況。

而前兩步稍等會與您一同探討,了解並遵守以上四點準則和三步驟相信我這對你來說一點都不可怕。

不等性

< , <=, >, >= 這些都是,也可以叫做關係比較
那他跟相等性一樣嗎?
不,他沒有嚴格不等性,也就是他都允許強制轉型,

  • 字串也可以比較,就是依照字典順序(就是 ASCII的值比較大小)
'boo' > 'foo' //false
'boo' < 'foo' // true

Truthy & Falsy

什麼東西被強制轉換會變 false?

  • "" or '' (空字串)
  • 0, -0 ,NaN
  • undefined
  • false

什麼東西被強制轉換會變 true?
除了以上其他東西都會被轉為 ture

  • 非空的字串
  • 不等於零的有效數字
  • 陣列 (無論有沒有值在裡頭)
  • 物件 (無論有沒有值在裡頭)
  • 函式

強制轉型

剛剛和昨天都一而再再而三的講到強制轉型
而 JS 的強制轉型有兩種,一種是明確性的強制轉型,另一種則是隱含的,而令人害怕的和畏懼的是隱含性的,甚至有人說到 "強制轉型是邪惡的" ,因為當型別轉換在你不知情的情況下你會覺得出乎你的意料。

隱含性的強制轉型他到底是指什麼?
簡單來說在 JS 的世界中當你使用剛剛所講的 == 或是!=,就代表允許強制轉型,那可以藉由以下範例我們就可以知道他是怎麼一回事。

const a = 18;
const b = '18';

a == b // true 因為他把 b 的 '18' 轉成 Number
a === b // false

寫到這邊讓我想到之前看了工程師幹話的這篇文章,
工程師幹話 - 怎樣準備技術面試

文章末有提到

0 == null // false
0 > null // false

接著...

0 >= null

會壞掉 >///<

一開始,其實只是純粹看文章有趣,但實質上其實不懂這個梗,後來花了些時間尋求答案,得出以下原因。

  • 0 == null // null 在相等性的設計上不會嘗試轉型態
  • 0 > null // null 在這邊會嘗試轉型態會變成 0 接著就是 0>0 所以回傳 false。
  • 0 >= null // null 在這邊會嘗試轉型態會變成 0 接著就 0 >= null 所以回傳 true

不得不說 null 真特別呢... 你說是吧xD (有點歪樓)

那明確的強制轉型是什麼?
就是我的確有指定他要轉為某個型態,範例如下。

let age = '18';
age = Number(age);
console.log(age); // 18
console.log(typeof age); // Number

希望看完這裡你對於強制轉型不再害怕。


第二天心得

發現在讀的過程中有和以往的觀念有衝突時,找了滿多解答並釐清觀念,收穫滿多的,以前都是以先做了快速拿到成就感,但是往往會忘記回頭去檢視自己對於自己的程式碼熟悉程度,感覺這篇寫完內心更加堅定了 (才剛開始好像講得要結束了)

寫一寫發現文章有點太長了,決定拆篇寫。
怕讀完整篇你可能會睡著xD

感謝您的收看
我們明天繼續!


參考來源:

你所不知道的 JS|導讀,型別與文法 (You Don't Know JS: Up & Going)


上一篇
【這些年我似是非懂的 Javascript】Day 2 - 程式語言超入門
下一篇
【這些年我似是非懂的 Javascript】Day 4 - 你一定可以入的了門 #下篇
系列文
【這些年我似是非懂的 Javascript】34

尚未有邦友留言

立即登入留言