JavaScript 类型细节整理


前言

javascript的类型相对来说比较简单,但也有一些容易遗漏的细节。


一、为什么有的编程规范要求用 void 0 代替 undefined?

说法一: 因为undefined有可能会被赋值,undefined是一个变量,并不是一个关键字,不存在赋值报错的情况,全局的undefined被赋值总是会失败,但是如果我们在对象的属性上创建了一个名为undefined的属性,那么情况就不同了
说法二: Undefined 类型表示未定义,它的类型只有一个值,就是 undefined。任何变量在赋值前是 Undefined 类型、值为 undefined,一般我们可以用全局变量 undefined(就是名为 undefined 的这个变量)来表达这个值,或者 void 运算来把任意一个表达式变成 undefined 值。 因为 JavaScript 的代码 undefined 是一个变量,而并非是一个关键字,这是 JavaScript 语言公认的设计失误之一,所以,我们为了避免无意中被篡改,我建议使用 void 0 来获取 undefined 值。
说法三:实际上,es5后undefined已经被改为read-only属性了。 但在局部作用域上,是会被修改的! 如考虑以下函数: const test = () =>{ var undefined = 5; console.log(typeof undefined)//輸出number } 为了避免无意中被篡改,使用void(0)还是比较好的做法 而且在进行代码压缩时,undefined也会被换成void(0), 总是要被替换的,为什么不一开始就换。

二、字符串有最大长度吗?

String 用于表示文本数据,String 有最大长度是 2^53 - 1。
因为 String 的意义并非“字符串”,而是字符串的 UTF16 编码,我们字符串的操作 charAt、charCodeAt、length 等方法针对的都是 UTF16 编码。所以,字符串的最大长度,实际上是受字符串的编码长度影响的。

说法一:也就是说length并不是直接返回直觉上字符串的长度,而是返回在Unicode编码状态下编码码点的长度。

JavaScript 字符串把每个 UTF16 单元当作一个字符来处理,所以处理非 BMP(超出 U+0000 - U+FFFF 范围)的字符时,你应该格外小心。超出这个范围的字符在 JS 中会是两个长度的字符,比如一些 emoji,从而导致的问题是,假设有只有一个超过范围的字符,你想通过 charAt(0) 访问,实际上只能访问到其中一部分。

三、 0.1 + 0.2 不是等于 0.3 么?为什么 JavaScript 里不是这样的?

JavaScript 中的 Number 类型有 18437736874454810627(即 264-253+3) 个值。JavaScript 中的 Number 类型基本符合 IEEE 754-2008 规定的双精度浮点数规则,但是 JavaScript 为了表达几个额外的语言场景(比如不让除以 0 出错,而引入了无穷大的概念)规定了几个例外情况:

  • NaN,占用了 9007199254740990,这原本是符合 IEEE 规则的数字;
  • Infinity,无穷大;
  • -Infinity,负无穷大。
    根据双精度浮点数的定义,Number 类型中有效的整数范围是 -0x1fffffffffffff 至 0x1fffffffffffff,所以 Number 无法精确表示此范围外的整数。小数在转化为二进制时,通过小数部分不停乘2取整,直到小数部分为0. 这种方式导致一些小数乘2永远做不到小数部分为0,只能取一定精度的值表示,进而导致精度误差的出现。同样根据浮点数的定义,非整数的 Number 类型无法用 ==( === 也不行) 来比较,一段著名的代码,为什么在 JavaScript 中,0.1+0.2 不能 =0.3:
  console.log( 0.1 + 0.2 == 0.3);

所以实际上,这里错误的不是结论,而是比较的方法,正确的比较方法是使用 JavaScript 提供的最小精度值:

  console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);

四、 ES6 新加入的 Symbol 是个什么东西?

Symbol 是 ES6 中引入的新类型,它是一切非字符串的对象 key 的集合,在 ES6 规范中,整个对象系统被用 Symbol 重塑。
说法一: Symbol 保证是唯一的。即使我们创建了许多具有相同描述的 Symbol,它们的值也是不同。描述只是一个标签,不影响任何东西。 — 例如,这里有两个描述相同的 Symbol —— 它们不相等:

 let id1 = Symbol("id"); let id2 = Symbol("id"); console.log(id1 == id2); // false

五、 为什么给对象添加的方法能用在基本类型上?

Object 是 JavaScript 中最复杂的类型,也是 JavaScript 的核心机制之一。Object 表示对象的意思,它是一切有形和无形物体的总称。
在 JavaScript 中,对象的定义是“属性的集合”。属性分为数据属性和访问器属性,二者都是 key-value 结构,key 可以是字符串或者 Symbol 类型。

JavaScript 中的几个基本类型,都在对象类型中有一个“亲戚”。它们是:

  • Number;
  • String;
  • Boolean;
  • Symbol。
    Number、String 和 Boolean,三个构造器是两用的,当跟 new 搭配时,它们产生对象,当直接调用时,它们表示强制类型转换。

Symbol 函数比较特殊,直接用 new 调用它会抛出错误,但它仍然是 Symbol 对象的构造器。围绕原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持。 然而,现有的原始包装器对象,如 new Boolean、new String以及new Number,因为遗留原因仍可被创建。
说法一: Object.prototype.toString(),这个对象原型上的toString方法返回一个表示该对象的字符串, “[object type]”,其中 type 是对象的类型,例如: var o = new Object(); o.toString(); // returns [object Object] 按道理这个toString方法只能用于对象类型的数据,但是我们发现其他数据类型的也可以用,如123 .toString(),这是因为其内部发生了装箱转换 使用new Number(123)生成对象后掉用toString方法. 如果我们改变toString中this的指向的数据,那就可以识别任何数据类型了。所以我们常用Object.prototype.toString.call(‘123’)来识别类型。


总结

有一个说法是:程序 = 算法 + 数据结构,运行时类型包含了所有 JavaScript 执行时所需要的数据结构的定义,所以我们要对它格外重视。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值