你不知道的JavaScript :值

你不知道的JavaScript系列—第二章:值

2.1 數組

  • JavaScript內里的數組能夠包容任何範例的值。
  • “希罕”數組(含有空白或空白單位的數組)

    var a = []
    a[0] = 1
    a[2] = [3]
    a[1] // undefined
    a.length // 3

    个中,a[1]隱式賦值為undefined

  • 索引
    數組經由過程数字舉行索引,但JavaScript中的數組也是對象,也能夠經由過程字符串鍵值舉行索引(但不盤算在數組長度內)

    var a = []
    a[0] = 1
    a["foobar"] = 2
    
    a.length // 1
    a["foobar"] // 2
    a.foobar // 2

    當字符串鍵值能夠強制性轉換為十進制数字的話,它就會被當作数字索引處置懲罰

    var a = []
    a["12"] = 1
    a.length // 13

    固然我們不發起這麼做(在數組中到場字符串鍵值/屬性),一般要寄存字符串鍵值/屬性,只管運用對象,數組寄存数字索引值

  • 類數組
    即一系列經由過程数字索引的值,如:es6之前的arguments對象(類數組),能夠經由過程東西函數將它轉換為真正的數組

    function foo () {
        var arr = Array.prototype.slice.call(arguments)
        arr.push('amm')
        console.log(arr)
    }
    foo("foo","bar") // ["foo","bar","amm"]

    ES6中的Array.from(…)也能夠完成一樣功用

    ...
    var arr = Array.from(arguments)
    ...

2.2 字符串

字符串經常被當做字符數組,但它與數組又有極大的差別,我覺得連類數組也算不上,只是看上去類似罷了。
比方下面兩個值

var a = "foo"
var b = ["f","o","o"]

然則它們兩確實很類似,都有length屬性,indexOf(…)以及concat(…)要領

a.length // 3
b.length // 3
a.indexOf("o") // 1
b.indexOf("o") // 1
var c = a.concat("bar") // foobar
var d = b.concat(["b","a","r"]) // ["f","o","o","b","a","r"]
a === c // false
b === d // false
a // foo
b // ["f","o","o"]

然則它們又有許多差別

a[1] = "O"
b[1] = "0"
a // foo
b // ["f","O","o"]

在JavaScript中,字符串是不可變的數組可變,而且a[1]並非正當語法(老版本IE不支持),正確的應該是a.charAt(1)
字符串不可變是指字符串的成員函數不會轉變其原始值,而是建立並返回一個新的字符串,而數組的成員函數都是在其原始值上舉行操縱。

var c = a.toUpperCase()
a === c // fasle
a // foo
c // FOO

b.push("!")
b // ["f","o","o", "!"]

2.3 数字

JavaScript中,沒有真正意義上的整數,現在只要数字範例(number)

2.3.1 較小的數值

二進制浮點數最大的題目:

0.1 + 0.2 === 0.3 // false

從數學的角度來講,此處應該是true,然則二進制浮點數中0.1與0.2並非非常正確,他們相加即是0.30000000000000004,所以效果為false。
那末我們怎樣來推斷0.1 + 0.2 和 0.3 是不是相稱呢?
最常見的要領是設置一個機器偏差,關於JavaScript中的数字來講,這個值一般是2^-52.
ES6最先,該值定義在Number.EPSILON中,在指定偏差範圍內,比較兩個數是不是相稱:

function numbersCloseEnoughEqual(n1, n2) {
    return Math.abs( n1 - n2 ) < Number.EPSILON
}
const a = 0.1 + 0.2
const b = 0.3
numbersCloseEnoughEqual(a, b) // true
numbersCloseEnoughEqual(0.0000001, 0.0000002)

2.3.2 特別數值

JavaScript中有幾個特別的值,須要開發者特別注意和警惕運用。

  1. 不是数字的数字
    NaN:not a number(不是一個数字:無效數值、失利數值、壞數值)

    const a = 2 / 'foo' // NaN
    typeOf a === number // true

    在這裏NaN是指實行數學運算沒有勝利,這是失利后返回的效果
    或許你會以為,推斷一個数字是不是是NaN,只須要將它與NaN作比較就行,如:

    2 / "foo" === NaN //false

    NaN是一個特別值,它與自身不相稱,唯一一個非自反(x === x 不成立)的值。而
    NaN != NaNtrue
    那末我們能夠運用東西函數Number.isNaN(...)來推斷一個值是不是是NaN。

  2. 零值
    JavaScript中有一個通例的0和一個-0

    var a = 0 / -1 // -0
    var b = 0 * -3 // -0

    加減法不會獲得-0
    那末怎樣辨別他們呢?

    function isNegZero(n) {
        n= Number(n)
        return (n === 0) && (1 / n === -Infinity)
    }
    isNegZero(-0) // true
    isNegZero(0 / -2) // true
    isNegZero(0) //false

    Infinity:無限數
    那末為何要存在一個-0?有些應用程序中的數據須要以級數情勢來示意(如動畫幀的挪動速率),数字的標記位代表特別信息(如挪動的方向)

2.4 值和援用

關於賦值與參數的通報能夠經由過程對值複製,或許援用複製來完成,取決於詳細的語法。
那末在JavaScript中,我們看一個例子:

var a = 2
var b = a // b 是 a 的一個副本
b ++
a // 2 
b // 3

var c = [1, 2, 3]
var d = c // d 是 [1, 2, 3] 的一個援用
d.push(4)
c // [1, 2, 3, 4]
d // [1, 2, 3, 4]

簡樸值(基礎範例)老是用過值複製的體式格局賦值/通報
複合值————對象和函數,則是經由過程援用複製的體式格局來複制/通報

在JavaScript中,援用指向的是值自身而非變量,所以一個援用沒法轉變另一個援用的指向:

var a = [1,2,3]
var b = a
a // [1,2,3]
b // [1,2,3]

// 然後
b = [4,5,6]
a // [1,2,3]
b // [4,5,6]

b=[4,5,6]並不影響a的指向[1,2,3],除非b指向的是a的指針,但JavaScript中不存在指針,就不存在這個狀況!

那末以下狀況,你或許也會邃曉了:

function foo(x){
    x.push(4)
    x // [1,2,3,4]
    
    x = [4,5,6]
    x.push(7)
    x // [4,5,6,7]
}

var a = [1,2,3]

foo(a)

a // [1,2,3,4]

在函數參數通報時,實際上是將a的援用的一個複製品賦值給x,經由過程複製的援用即x變動數組的值,也會影響到a,所以a被轉變成[1,2,3,4],然則將x指向到另一個援用[4,5,6],是不會影響到a的指向的,所以a照樣[1,2,3,4]

    原文作者:Winer
    原文地址: https://segmentfault.com/a/1190000014851340
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞