JavaScript 类型

  • 为什么有的编程规范要求用 void 0 代替 undefined?
  • 字符串有最大长度吗?
  • 0.1 + 0.2 不是等于 0.3 吗?为什么 JavaScript 里不是这样?
  • ES6 里新增的 symbol 是什么?
  • 为什么给对象添加的方法能用在基本类型上?

7 种语言类型

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Object
  • Symbol

Undefined、Null

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

Undefined 类型表示未定义,它的值只有 undefined。 任何变量在赋值前都是 Undefined 类型,值是 undefined,一般可以用全局变量 undefined 来表示这个值,或者用 void 运算来把任何表达式变成 undefined 值。

JavaScript 的 undefined 是一个变量,不是关键字,所以为了避免无意中被串改,建议使用 void 0 来获取 undefined 值。

null 表示定义了但是为空。实际编程中,不会为变量赋值为 undefined,可以保证所有为 undefined 的变量都是未赋值的状态。

Null 类型只有一个值--null。它的语义表示为空值。

补充:

在现代浏览器中,可以用下面的代码将变量与 undefined 进行比较。

var a;
if (a === undefined) {}

在老的浏览器中,undefined 变量可以直接被赋值修改。

undefined = 'test';
var a;
if (a === undefined) {}

在被重新赋值后,直接使用 undefined 将不能正确的检测一个变量是否被赋值。

Boolean

略...

String

字符串是否有最大长度。

String 用于表示文本数据,最大长度为 2^53-1。

String 的意义是字符串的 UTF-16 编码。所以,字符串的最大长度是受字符串的编码长度影响的。

JavaScript 把每个 UTF-16 单元当作一个字符处理。

Number

JavaScript 中的 Number 类型有 2^64-2^53+3 个值。

JavaScript 中的 Number 类型基本符合 IEEE 754-2008 规定的双精度浮点数规则。

额外的语言场景:

  • NaN
  • Infinity(不让除以 0 出错,引入了无穷大的概念)
  • -Infinity

在除法时,需要区分 JavaScript 中的 +0 和 -0。

区分的方式:

1 / 0; // Infinity
1 / -0; // -Infinity

根据双精度浮点数的定义,Number 类型中有效的整数范围是 -0x1fffffffffffff 至 0x1fffffffffffff,所以 Number 无法精确表示此范围外的整数。

0.1 + 0.2; // 0.30000000000000004 <-- 超出了上面所说的范围

正确的比较方法:

Number.EPSILON

代表最小精度,如果误差小于这个值可认为没有意义,即不存在误差了。

Number.EPSILON; // 2.220446049250313e-16
Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON; // true

参考:

Symbol

Object

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

定义:属性的集合。

  • 数据属性
  • 访问器属性

概念:类。

JavaScript 的”类“仅仅是运行时对象的一个私有属性。JavaScript 中无法自定义类型。

JavaScript 的几种基本类型与对象类型相对应:

  • Number
  • String
  • Boolean
  • Symbol

3 是 JavaScript 的 Number 类型,new Number(3) 是对象类型。

Number、String、Boolean 三个构造器是两用的,当和 new 关键字搭配时,生成对象;直接调用时,表示强制类型转换。

Symbol 函数用 new 调用时,会抛出错误,但仍是 Symbol 对象的构造器。

答案:运算符提供了装箱操作,会根据基础类型构造一个临时对象,使得我们能在基础类型上调用对象的方法。

类型转换

装箱转换:把基本类型转换为对应的对象。

Symbol

function newObject() {
  return this;
}
cont symbolA = Symbol('a');
const symbolAObject = newObject.call(symbolA); // 利用 call 强迫产生装箱
console.log(typeof symbolA); // "symbol"
console.log(typeof symbolAObject); // "object"

使用 Object 函数可以显示调用装箱能力。

const symbolObj = Object(Symbol('a')); // Symbol {Symbol(a)}

装箱对象私有的 class 属性。使用 Object.prototype.toString 方法获取。

Object.prototype.toString.call(Object({})); // "[object Object]"
Object.prototype.toString.call(Object(null)); // "[object Object]"
Object.prototype.toString.call(Object(undefined)); // "[object Object]"
Object.prototype.toString.call(Object(true)); // "[object Boolean]"
Object.prototype.toString.call(Object(1)); // "[object Number]"
Object.prototype.toString.call(Object('')); // "[object String]"

cont symbolA = Symbol('a');
const symbolAObject = newObject.call(symbolA);
Object.prototype.toString.call(Object(symbolObj)); // "[object Symbol]"

call 本身会产生装箱操作,所以需要配合 typeof 来区分基本类型还是对象类型。

Object.prototype.toString.call(''); // "[object String]"
typeof ''; // "string"
typeof Object(''); // "object"

拆箱转换

对象类型转为基本类型。

略...

Last Updated: 6/19/2019, 10:26:22 PM