1. 程式人生 > >JavaScript 變數型別

JavaScript 變數型別

變數型別

JavaScript 中的變數型別分為值型別(又稱為簡單型別、基本資料型別)以及引用型別。

【值型別】:

  • Number
  • String
  • Undefined
  • Null
  • Boolean

【引用型別】:

  • Object
  • Array
  • Function

值型別和引用型別的區別

  • 儲存方式的不同:每宣告一個值型別變數,都會在記憶體中單獨分配出一塊區域用以儲存,變數之間不會相互影響;而引用型別返回的是儲存地址,因此若是變數之間的賦值,實際是將地址的引用進行賦值。
// 值型別
var a = 100, b = a;
console.log(a); // 100
console.log(b); // 100
b = 50;
console.log(a); // 100
console.log(b); // 50

// 引用型別
var a = { number: 100 }, b = a;
console.log(a.number); // 100
console.log(b.number); // 100
b.number = 50;
console.log(a.number); // 50
console.log(b.number); // 50

typeof 運算子

typeof 運算子把型別資訊當作字串返回。

var number = 100,
    string = "Hello",
    boolean = true,
    variable,
    variable2 = null,
    fun = function() {},
    object = {},
    array = [];
    
console.log(typeof number); // "number"
console.log(typeof string); // "string"
console.log(typeof boolean); // "boolean"
console.log(typeof variable); // "undefined"
console.log(typeof variable2); // "object"
console.log(typeof fun); // "function"
console.log(typeof object); // "object"
console.log(typeof array); // "object"
  • typeof 只能區分值型別:number、string、undefined、boolean。
  • 引用型別除函式外,物件和陣列都為 object(注意,基本型別中的 null 也為 object)。
  • 函式在JS中為一等公民,因此能夠被 typeof 識別為 function。

如何區分陣列?

  • 鴨式辨型法:
var array = [1, 2, 3];
if (typeof array.sort === "function") {
    // 思想:判斷當前物件是否擁有陣列物件專有的 sort 函式。
    console.log("haha");
}
// 缺陷
var array = {
    data: [],
    sort: function() {}
}
if (typeof array.sort === "function") {
    // 也能成功執行
    console.log("hoho");
}
  • Kangax 方案:
var array = [1, 2, 3];
if (Object.prototype.toString.call(array) === "[object Array]") {
    // 思想:呼叫某個值的內建 toString() 方法在所有瀏覽器中都會返回標準的字串結果。
    // 對於陣列來說,返回的字串為 “[object Array]”.
    console.log("haha");
}
// 缺陷:對於自定義物件使用這種方法會存在問題,比如內建 JSON 物件將返回 “[object JSON]”
  • isArray() 方法:
var array = [1, 2, 3];
if (Array.isArray(array)) {
    // ECMAScript5 將 Array.isArray() 正式引入 JavaScript。
    console.log("haha");
}
// 相容低版本寫法
function isArray(value) {
    if( typeof Array.isArray === "function") {
        return Array.isArray(value);
    } else {
        return Object.prototype.toString.call(value) === "[object Array]";
    }
}

型別轉換

JavaScript 是一種弱型別語言,所以無法確定變數儲存具體型別的值,並且變數的型別也可以隨時發生變換。

轉換規則

【示例】:

var a = 100,
    b = "50",
    c = true,
    d = null,
    e,
    f = function() {},
    g = {},
    h = [],
    i = { data: 1 },
    j = [1, 2];

// Number
console.log("Number + String", a + b); // "10050"
console.log("Number + Boolean", a + c); // 101
console.log("Number + Null", a + d); // 100
console.log("Number + Undefined", a + e); // NaN
console.log("Number + Function", a + f); // 100function() {}
console.log("Number + Object(Empty)", a + g); // 100[object Object]
console.log("Number + Array(Empty)", a + h); // 100
console.log("Number + Object", a + i); // 100
console.log("Number + Array", a + j); // 100

// 引用型別
console.log(f.toString()); // function() {}
console.log(g.toString()); // [object Object]
console.log(h.toString()); // 
console.log(i.toString()); // [object Object]
console.log(j.toString()); // 1,2

// String
console.log("String + Boolean", b + c); "50true"
console.log("String + Null", b + d); "50null"
console.log("String + Undefined", b + e); "50undefined"
console.log("String + Function", b + f); "50function() {}"
console.log("String + Object", b + g); "50[object Object]"
console.log("String + Array", b + h); "50"

// Boolean
console.log("Boolean + Null", c + d); "1"
console.log("Boolean + Undefined", c + e); "NaN"
console.log("Boolean + Function", c + f); "truefunction() {}"
console.log("Boolean + Object", c + g); "true[object Object]"
console.log("Boolean + Array", c + h); "true"

// Null
console.log("Null + Undefined", d + e); "NaN"
console.log("Null + Function", d + f); "nullfunction() {}"
console.log("Null + Object", d + g); "null[object Object]"
console.log("Null + Array", d + h); "null"

// Undefined
console.log("Undefined + Function", e + f); "undefinedfunction() {}"
console.log("Undefined + Object", e + g); "undefined[object Object]"
console.log("Undefined + Array", e + h); "undefined"

【規則】:

  • 所有型別都能夠轉換為 String 型別。引用型別會呼叫 toString() 方法進行型別轉換。而值型別則將值轉換為 String 型別(100 => “100”,true => “true”)。
  • 型別轉換遵循向運算元型別優先順序高的一方轉換的原則。例如,Number 和 String 相加,將 Number 轉換為 String。
  • Boolean 和 Null 型別可以轉換為 Number 型別(true:1,false:0,null:0)。
  • Undefined 型別無法轉換為 Number 型別,因此和 Number 型別執行加算術運算時會得到 NaN。

【注意】:當運算元中不存在 String 型別,+ 表示算術運算中的加法運算,因此在進行型別轉換時,會轉換為 Number 型別。若存在 String 型別,+ 表示連字元操作,因此會轉換為 String 型別。在判斷型別轉換時,必須要明確當前具體要執行的操作。

【問】:為什麼 Number 型別和引用型別相加時,最後的結果卻是 String?按照上述規則中的“型別轉換遵循向運算元型別優先順序高的一方轉換的原則”,不應該是將引用型別轉化為 Number 型別嗎?

【答】:引用型別在執行 + 操作時,會呼叫其自身的 toString() 方法,此時引用型別已經轉換為 String。而 String 的優先順序大於 Number,會將 Number 轉換為 String,因此最後的結果是 String。

【Boolean 型別轉換規則】:

型別 true false
String 非空字串 空字串 “”
Number 非 0 和 NaN 0 和 NaN
Undefined 不適用 Undefined
Null 不適用 Null
Object 任何物件 不適用
Array 任何陣列 不適用
Function 任何函式 不適用

【示例】:

var a = 100,
    a_2 = 0,
    b = "50",
    b_2 = "",
    c = true,
    c_2 = false,
    d = null,
    e,
    f = function() {},
    g = {},
    h = [],
    i = { data: 1 },
    j = [1, 2];

console.log(!!a); // true
console.log(!!a_2); // false
console.log(!!b); // true
console.log(!!b_2); // false
console.log(c); // true
console.log(c_2); // false
console.log(!!d); // false
console.log(!!e); // false
console.log(!!f); // true
console.log(!!g); // true
console.log(!!h); // true
console.log(!!i); // true
console.log(!!j); // true

強制型別的場景

  • 字串拼接
  • == 等於運算子
  • if () 條件判斷
  • 邏輯運算子

小技巧:轉換為 Boolean 型別

【示例】:

var a = 100;
a = !!a;
// 先通過取反操作,將其轉換為 Boolean 型別
// 然後再取反,獲得正確的值