你不知道的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中有幾個特別的值,須要開發者特別注意和警惕運用。
不是数字的数字
NaN
:not a number(不是一個数字:無效數值、失利數值、壞數值)const a = 2 / 'foo' // NaN typeOf a === number // true
在這裏
NaN
是指實行數學運算沒有勝利,這是失利后返回的效果
或許你會以為,推斷一個数字是不是是NaN,只須要將它與NaN作比較就行,如:2 / "foo" === NaN //false
NaN是一個特別值,它與自身不相稱,唯一一個非自反(x === x 不成立)的值。而
NaN != NaN
為true
。
那末我們能夠運用東西函數Number.isNaN(...)
來推斷一個值是不是是NaN。零值
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]