JavaScript Weird Part (13) - 型別與 JavaScript

程式語言都具有資料結構,但在不同的程式語言之間會有些差異。Javascript 在變數的資料型別與其他的程式語言相當不同,它是以「動態型別」(Dynamic Typing) 處理資料型別。

動態型別

程式語言會依照語言的型別系統分成「強型別語言」和「弱型別語言」。強型別是指「程式定義的變數型別等於變數在執行的時候的型別」,這類語言的變數在宣告的時候,必須指定一種資料型別給它,如果對這個變數做錯誤型別的運算,就會出現錯誤。弱型別正好相反,因此具有語法簡潔的優點,但要注意型態轉換時產生非預期的問題。

變數是用來儲存資料和運算的基本單位,就像一個存放資料的盒子。JavaScript 是弱型別,也能說是動態的程式語言。這代表你不必特別宣告變數的型別。

JavaScript 程式在運作時,型別會自動轉換。這也代表你可以以不同的型別使用同一個變數。因為型別的資訊只在「值」或「物件」本身,變數只是用來取得值或物件的參考。

1
2
3
4
// 透過 var 宣告變數 n,因為沒有給 n 數值,因此 n 的內容為 undefined
var n;
// 透過 var 宣告變數 m,給了變數 m 一個數值,因此 m 的內容為 1
var m = 1;

它能夠辨別數值、字串和布林值。亦即我們不用自己在程式裡告知 Javascript 變數是哪種型別的資料,它會在程式執行運行時主動判別。因此一個變數可以在執行程式的不同階段,擁有不同的型別,因為型別都是在執行時才判別的。

動態型別是說不用任何關鍵字宣告變數的型別,程式執行的時候,它會自己判別要給這個變數怎樣的型別,不需要表明它隸屬於哪種資料型別。

1
2
3
var foo = 42; // foo 目前是數字
var foo = "bar"; // foo 目前是字串
var foo = true; // foo 目前是布林值

但即便變數沒有先夠過 var 宣告的時候,仍可以給某個變數值要避免這種狀況:

1
2
//對未宣告的 m 直接賦值
m = 1;

會讓已經被 var 宣告過的變數依然可以再次宣告,這是合法的:

1
2
var m = 1;
var m = 2;

但是透過 let 宣告的變數就不行;

1
2
let m = 1;
let m = 2;

什麼是型別?

以下的補充資料是 JavaScript Weird Part 課程裡面沒有提到的,主要可分為兩點:

  1. 型別究竟是什麼?內建型別有哪些?常見疑難雜症與解法。
  2. 未定義(undefined)vs 未宣告(undeclared)

「型別」是固有的、內建的特徵,能唯一識別特定值的行為。例如:數字 123 和字串 ‘123’ 就是不一樣的,數字 123 可做數學運算處理,而字串 ‘123’ 可能就是做些顯示到畫面上的操作。

JavaScript 支援的型別主要可分為基本型別(primitives)和物件型別(object)。基本型別有 numberstringbooleannullundefined。ES6 之後又多了新的型別:symbol 除了上述幾種之外,其他都可以歸類到物件型別 (Object),例如:物件、陣列、函式、日期等。:

  • number 數字,例如:12345。
  • string 字串,例如:’Hello World’。
  • boolean 布林,例如:true、false。
  • null
  • undefined
  • object 物件,例如:{ name: ‘Jack’ }、[1, 2, 3]、function foo() { … }
  • symbol

可用 typeof 檢測值的資料型別為何

1
2
3
4
5
typeof 'Hello World!' // 'string'
typeof true // 'boolean'
typeof 1234567 // 'number'
typeof {};//'object'
tyoeof [];//'object'

也會有例外狀況

1
2
3

typeof null;//'object'
tyoeof window.alert;//'function'

string 字串

依照習慣可以用 ‘’ (單引號) 或 “ “ (雙引號)收合,但不能同時混用。而且單引號內包負擔引號或雙引號內包覆雙引號就會出錯:

1
var str =' Let's go shopping ' // 錯誤

這樣可以:

1
var str = " Let's go shopping ";

如果一定要用,可以用 \ (跳脫字元,escape character) 處理:

1
var str = " Let\'s go shopping ";

多行字串也可以透過 \ 連接:

1
2
3
4
var str =
" 第一行\
第二行\
第三行";
反斜線符號後面不能有任何東西,包括空白字元

ES6 樣板字面值

ES6 新增一種樣板字面值 (template literal),增加字串靈活性。這種樣板字面值是由一組反引號 ` 包覆。多行字串不需要再加上 \。

1
2
3
4
5
var str = `
第一行
第二行
第三行
`;

組合變數與字串不用再加+連接,可直接塞進字串:

1
2
3
4
var amount = 30;
var str = `I buy ${amount} bottles of cola `;
console.log(str);
// I buy 30 bottles of cola.

或者運算式

1
2
3
var a = 4;
var b = 3;
console.log(`Seven is ${a + b} and not ${a * b}.`);

number 數字

除了常見的整數與小數點,還有一種特殊的數字 NaN (不是數值,Not a Number), NaN 表示是無效的數字,但依舊還是數字,因此在資料型別的檢測 typeof NaN 結果就是 number,不要被字面上的意思「不是數字」(not a number)給弄糊塗了。

1
typeof NaN; //number

另外,NaN 與任何數字運算都會得到 NaN,並且 NaN 不大於、不小於也不等於任何數字,也就是說,包含 NaN 它自己。

1
NaN === NaN; // false

Q1:如何檢測變數是否為 NaN?

可以透過 isNaN (value) 來判斷:

1
2
3
4
5
isNaN(NaN); // true

isNaN(123); //false
isNaN("123"); //false,因為字串 '123' 會透過隱含的 Number()轉型成數字
isNaN("NaN"); //true,因為字串 "NaN" 無法轉成數字

boolean 布林值

布林值通常用在判斷式,當做控制程式流程的用途。JavaScript 判斷比較的運算式裡,所有東西都可以轉換成布林值。

1
2
var a = true;
var b = false;

null 與 undefined

多數程式語言都有 null 及空值的設定,但是 JavaScript 又多了一種 undefined。兩者的共通點是都只有一種值:null 就只有一種 null 值,而 undefined 就只有 undefined 值。

1
2
3
var a; //undefined,尚未給值,未定一

var b = null; //null,明確代表此數沒有值

這兩種值透過 Boolean()型轉的時候,都是 false,但確切一似的差別是:

  1. undefined 代表此變數還沒有給一個值,所以不知道是什麼
  2. null代表「曾經有值,或曾經也沒值」,但現在沒有值

object 物件

物件是零至多種屬性的集合,物件就像是屬性的容器。屬性就是鍵 (key) 與值 (value) 的組合。在值中可以放入任何型別的值,當然也包括物件、函式。

物件及屬性

目前常見建立物件的方法,直接使用大括號 {} 建立物件,並直接指定屬性到物件裡面,這稱為「物件實體」(Object literal) 方法。

1
2
3
4
5
6
7
var person = {
name:'David'
job:'Teacher',
sayName:function(){
alert(this.name);
}
};

物件屬性存取

透過 「.」 存取

1
2
3
4
5
6
7
8
9
var person = {
name:'David'
job:'Teacher',
sayName:function(){
alert(this.name);
}
};

var person.name; // 'David'

透過 [ ] 存取

1
2
3
4
5
6
7
8
9
var person = {
name:'David'
job:'Teacher',
sayName:function(){
alert(this.name);
}
};

var person['name']; // 'David'

屬性新增

如果要為物件新增屬性,直接用 = 指定

1
2
var obj = {};
obj.name = "Object";

屬性刪除

透過 delete 關鍵字刪除屬性

1
2
3
4
5
var obj = {};
obj.name = "Object";
delete object.name;

object.name; //刪除後屬性變成 undefined

陣列

陣列是一種特別的物件,裡面可以是原始資料類型、另一個陣列、物件或函式。與物件不同的地方是,陣列是有順序性的集合,只能夠過 [] 加上索引存取。現今建立陣列多用陣列實體 (Array literal),例如:

1
2
3
4
5
6
var a = [];
a [0] = 'apple';
a [1] = 'boy';
a [2] = 'cat';

a.length =; //3

要在陣列末端新增元素,可以透過 push() 方法:

1
2
3
4
5
var array = ["a", "b"];
array.length; //3

array.push("c");
console.log(array); //['a','b','c']

如何判別是不是陣列

利用 typeof 檢查陣列,會得到 object 的結果,但是實務上如果要判別變數是陣列而非物件,ES6 新增 isArray() 方法方便判斷

1
2
Array.isArray([]); //true
Array.isArray(null); //false

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 CYC'S BLOG All Rights Reserved.

UV : | PV :