该专栏总结自《你不知道的JavaScript》丛书的知识,易错易混点。
类型和值
- 通过
typeof
操作符执行时,得到的结果并不是该变量的类型,而是该变量持有的值的类型,因为JavaScript中的变量没有类型。
typeof
运算符总是返回一个字符串。
undefined 和 undeclared
- 已知在作用域中声明但是没有赋值的变量是undefined。
- 还没有在作用域中声明的变量是undeclared。输出是会报错。
typeof
操作符操作为声明的变量时,依旧返回undefined。不会报错。这是因为typeof
有一个特殊的安全防范机制。
var a; // console.log(a, b) console.log(typeof b) //undefined
数组
delete
运算符删除数组中元素时,该数组的length不会改变。
- 给数组赋值属性时,他只是在该数组本身,而不会计算在数组长度内。
var a = [] a[0] = 1; a["foo"] = 2; console.log(a.length, a.foo) // 1 2
- 如果添加的属性可以被强制转化为十进制数字的话,那么他将会被看作是数字索引来处理。
var a = [] a[0] = 1; a["12"] = "zh" console.log(a.length) // 13
所以不要在数组中添加属性,这样是不好的编程习惯。
字符串
- 字符串不可变是指字符串的成员函数不会改变其原始值。而是创建并返回一个新的字符串。
- 许多数组方法用来处理字符串很方便。可以借助数组的非变更方法来处理字符串。即不改变原数组的方法。
const a = "foo" const b = ["f", "o", "o"] console.log(b.join()) // 默认传入的是","" // join, map console.log( Array.prototype.join.call(a)) // f,o,o console.log(Array.prototype.map.call(a, item => item + ".")) // [ 'f.', 'o.', 'o.' ]
如果需要经常以字符数组的方式来处理字符串的话,倒不如直接使用数组。这样就不用在字符串和数组之间来回折腾。可以再需要时使用join("")将字符数组转换为字符串。
数字
- es6 以后严格模式下不在支持0363八进制格式,请使用0x, 0b, 0o表示进制。
- 检测整数。
Number.isInteger()
。小数点后面全为0,小数点将被忽略,被确定为整数。
console.log(Number.isInteger(9.000)) // true console.log(Number.isInteger(9.010)) // false
- 最大最小安全整数。最大安全整数
2 ^ 53 - 1
为9007199254740991。表示为Number.MAX_SAFE_INTEGER
, 最小整数-9007199254740991
, 标识为Number.MIN_SAFE_INTEGER
。 通过Number.isSafeInteger()
来判断是否是安全的整数。
console.log(Number.isSafeInteger(Number.MIN_SAFE_INTEGER)) // true
- NaN的类型依旧是number。但是NaN和NaN不相等。通过
isNaN()
来判断一个变量是否为NaN。 这个方法会存在bug。
console.log(isNaN("foo")) // true
所以我们可以通过es6的Number.isNaN()
来判断。以后使用这个方法即可。
console.log(Number.isNaN("foo")) // false
- -0转化为字符串都会变为0。字符串"-0"转化成数字时,都会变为-0。
console.log(+"-0") // -0 console.log(Number("-0")) // -0 console.log(JSON.parse("-0")) // -0
- 利用
Object.is()
来判断一些特殊数字是佛相等。例如0, -0
,NaN, NaN
console.log(Object.is(-0, 0)) // false console.log(Object.is(NaN, NaN)) // true
null 和 undefined
- undefined: 指从未赋值。
- null:表示曾赋过值,但是目前没有值。
- null是一个特殊的关键字,不是标识符,我们不能将其当做变量来使用和赋值。但是undefined却是一个标识符,可以被当做变量来使用和赋值。
let undefined = "aaa"; console.log("undefined", undefined) // undefined aaa
- void 表达式。他可以返回一个undefined。void并不改变表达式结果,只是让表达式不返回值。
- 二者的内部属性[[class]]。虽然Null()和Undefined()这样的原生构造函数并不存在,但是内部[[class]]属性值仍然是"Null""Undefined"。
console.log(Object.prototype.toString.call(null)) //[object Null] console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
基本包装类型
- 基本包装类型判断时,都返回true。因为他们被看做是一个对象。
- 并且通过
typeof
判断时,都将返回"object"。
console.log(typeof new Number(0)) // object
- 通过
valueOf()
来得到封装对象中的基本类型值。
console.log((new Number(0)).valueOf()) // 0
原生函数作为构造函数
- Array构造函数只带有一个数字参数的时候,该参数会被作为数组的预设长度。
console.log((new Array(4)).length) // 4 console.log((Array(4)).length) // 4
这样创建出来的只是一个空数组,只不过它的length属性被设置成了指定的值。
- 数组的方法对处理空单元数组和undefined数组可能会有不同。例如join和map。 join首先假定数组不为空,但是map不会这样假设。
const a = new Array(3); const b = [undefined, undefined, undefined] const c = []; c.length = 3; console.log(a.join("-")) // -- console.log(b.join("-")) // -- console.log(c.join("-")) // -- console.log(a.map((v, i) => { return i })) // [] console.log(c.map((v, i) => { return i })) // [] console.log(b.map((v, i) => { return i })) // [ 0, 1, 2 ]
我们可以通过以下代码创建一个undefined数组,而非空单元数组。
const a = Array.apply(null, {length: 3}); console.log(a) // [undefined, undefined, undefined]
总之千万不要创建和使用空单元数组。