你不知道的JavaScript丛书总结(一)

175 阅读4分钟

该专栏总结自《你不知道的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]

总之千万不要创建和使用空单元数组。