目录
数组
1 delete运算符可以将单元从数组中删除,但length属性不会发生变化。
2 数组通过数字进行索引,但数组也是对象,所以也可以包含字符串键值和属性(不过不计算在数组长度内)
3.如果字符串键值能被强制转换为十进制数字,会被当数字索引处理
4.类数组转数组Array.prototype.slice.call(arguments); array.from()
5."稀疏"数组(含有空白或空缺单元
的数组)
var a=[];
a[0]=1;
a["footer"]=2;
a.length; //1
a["232"]=233;
a.length; //233
--------------------------
function foo(){
var arr=Array.prototype.slice.call(arguments);
arr.push("bam");
console.log(arr);
}
foo("bar","baz"); // ["bar","baz","bam"]
字符串
js中字符串是不可变的:字符串的成员函数不会改变原始值,而创建并返回一个新的字符串。
数组可变:数组的成员函数都是在其原始值上进行操作。
借助数组函数处理字符串
var a = "foo";
// 字符拼接
var c = Arror.prototype.join.call(a, "-"); // "f-o-o"
// 字符反转
var d = a
.split("") // 转为字符数组
.reverse() // 数组的字符进行反转
.join(""); // 字符数组拼回字符串
//"oof"
数字
JavaScript中,没有真正意义上的整数,目前只有数字类型(number)
。
二进制浮点数最大的问题:
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)
检测一个数字是否是整数,可以使用:
Number.isInteger(33); // true
Number.isInteger(33.00); // true
Number.isInteger(42.3) // false
JavaScript 能够准确表示的整数范围在-2^53
到2^53
之间(不含两个端点),超过这个范围,无法精确表示这个值。超出 2 的 53 次方之后,一个数就不精确了。
ES6 引入了Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER
这两个常量,用来表示这个范围的上下限。
检测一个数字是否是安全整数,可以使用:
Number.isSafeInteger(Math.pow(2, 53)); // false
Number.isSafeInteger(Math.pow(2, 53) - 1); // true
不是值的值
Undefined
变量在未持有值的时候为undefined。大多数开发者倾向于将undefined等同于undeclared(未申明),但在JavaScript中完全是两回事情。
已在作用域中声明但还没有赋值的变量是undefined,相反,还没有在作用域中声明过得变量是undeclared。
var a;
a; // undefined
b; // ReferenceError: b is not defined
对UNdeclared的变量执行typeof,会得到undefined,这让人抓狂,因为typeof有一个特殊的安全防范机制。这种处理使得我们比较容易判断当前环境是否已经引入了某一变量。
if(typeof abc === 'undefined') {
abc = function() {
// do some thing
}
}
判断a是否已经在当前环境中,使用typeof a === 'undefined', 而不是 if(a)
Null还是Undefined
- null指的是空值(empty value)
- undefined指的是没有值(missing value),从未赋值过
void 0
鉴于在非严格模式下,我们可以为全局标识符undefined赋值。可以看到一些人这样写代码:
var a = void 0
表达式void没有返回值,它获得一个纯粹的undefined。void并不改变表达式的结果,只是让表达式不返回值。
特殊的数字
NaN意指“不是一个数字”(not a number)。下面来看看全局工具函数 isNaN() 的用法:
var a = 2 / "foo";
var b = "foo";
a; // NaN
b; "foo"
window.isNaN( a ); // true
window.isNaN( b ); // true
以上的检验方式是:“只要不是数字,它的值就是NaN”。我们定义的变量 b 不是一个数字,但也不是NaN,所以这种检验方式并不太准确。
从ES6开始可以使用工具函数Number.isNaN(..),ES6 之前的浏览器的 polyfill 如下
if (!Number.isNaN) {
Number.isNaN = function(n) {
// 利用 NaN 不等于自身这个特点,NaN 是 JavaScript 中唯 一一个不等于自身的值。
return n !== n;
};
}
var a = 2 / "foo";
var b = "foo";
Number.isNaN( a ); // true
Number.isNaN( b ); // false
零值
JavaScript中有一个常规的0
和一个-0
var a = 0 / -1 // -0
var b = 0 * -3 // -0
加减法不会得到-0
那么如何区分他们呢?
Infinity
:无穷数
那么为什么要存在一个-0
?有些应用程序中的数据需要以级数形式来表示(如动画帧的移动速度),数字的符号位代表特殊信息(如移动的方向)
function isNegZero(n) {
n= Number(n)
return (n === 0) && (1 / n === -Infinity)
}
isNegZero(-0) // true
isNegZero(0 / -2) // true
isNegZero(0) //false
值和引用
JavaScript 对值和引用的赋值 / 传递在语法上没有区别,完全根据值的类型来决定。 下面来看一个例子:
var a = 2;
var b = a;
b++;
a; // 2
b; // 3
var c = [1,2,3];
var d = c;
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]
简单值(即标量基本类型值,scalar primitive)总是通过 值复制 的方式来赋值/传递,包括 null、undefined、字符串、数字、布尔和 ES6 中的 symbol。
值复制——例子中b是a的值的一个副本,b值的改变不会影响a的值
复合值——对象(包括数组和封装对象)和函数,则总是通过 引用复制 的方式来赋值 / 传递。
引用复制——例子中c 和 d 则分别指向同一个复合值 [1,2,3] 的两个不同引用,所以它们更改的是同一个值(如调用 .push(4)),随后它们都指向更 改后的新值 [1,2,3,4]。由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向。
注意--------------❤❤❤❤❤❤❤❤❤----------------
在函数参数传递时,实际上是将a的引用
的一个复制品
赋值给x
,通过复制的引用即x更改数组的值,也会影响到a,所以a被改变为[1,2,3,4]
,但是将x指向到另一个引用[4,5,6]
,是不会影响到a的指向的,所以a还是[1,2,3,4]
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]