你不知道的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]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。