一次比较运算符引发的 JavaScript 数据类型与类型转换的思考

  JavaScript编程中,比较运算、数据转换操作等是十分常见,不过,计算机是如何工作、如何判断的,可能大部分人都不了解,想要学好 JS 这门弱类型语言,搞懂其类型判断机制很有必要,这里将从一次比较运算说起。

你了解比较运算 x == y,Js 是如何去判断的吗?

11.9.3 规定的 abstract equality comparison 机制

几个简单例子,看有木有一个初步的了解。

Tips:粘贴到 chrome devtool 的 snippets 里,再 run 一下就知道结果了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
console.log('undefined == null', undefined == null);
console.log('null == null', null == null);
console.log('NaN == "NaN"', NaN == 'NaN');
console.log('2 == NaN', 2 == NaN);
console.log('3 == 3', 3 == 3);
console.log('+0 == -0', +0 == -0);
console.log('-0 == +0', -0 == +0);

console.log('----------------------------------');

console.log('4 == "a"', 4 == "a");
console.log('"a" == 1', "a" == 1);
console.log('"1" == 1', "1" == 1);
console.log('"4" == 4', "4" == 4);

console.log('----------------------------------');

console.log('true == 5', true == 5);
console.log('true == 1', true == 1);
console.log('"a" == true', 'a' == true);
console.log('"0" == false', '0' == false);

console.log('----------------------------------');

console.log('1 == {A: 0}', 1 == {A: 0});
console.log('"{A: null}" == {A: null}', '{A: null}' == {A: null});
console.log('{A: 5} == 5', {A: 5} == 5);
console.log('{A: 0} == "1"', {A: 0} == '1');

基本数据类型(划重点了)

  • primitives 类型有 6 种:

    • boolean
    • number (Infinity, NaN)
    • string
    • null
    • undefined
    • symbol (ECMAScript 6 新增)
  • object 类型

目前,js只有以上7种类型,其中原始类型的值是 freezed 。即变量被赋予不同的原始值,只是将其指向了内存中的另外一个原始值,但原本的那个原始值在内存中并没有变化。 Object类型则不同,对象内部属性被赋予不同值后,在内存中表示该对象的一些字节确实被改变了。

装箱与拆箱

为了便于操作基本类型值,ECMAScript提供了3个特殊的引用类 Boolean, Number, String,每当读取一个基本类型值时,就会创建一个对应的基本包装类型对象,以便调用一些方法操作这些数据。

1
2
// 
var s = "stringtest";
1
2
// 当上方代码创建变量 s 后,后台会创建 String 类型的一个实例,将 s 包装成一个值为 "stringtest" 的 String 对象,这就是自动装箱操作。
var s = new String("stringtest");
1
2
// 在实例 s 调用 String 对象的方法后,后台会销毁这个实例,s 的值被指向基本数据类型 "test",这就是自动拆箱。
s.slice(6);
1
2
// 通过 typeof 查询基本数据类型
console.log(typeof s);

两个类型转换常用函数

  • valueOf() 返回这个对象逻辑上对应的原始类型的值。
    比如说,String 包装对象的 valueOf(),应该返回这个对象所包装的字符串。
  • toString() 返回这个对象的字符串表示。
    即用一个字符串来描述这个对象的内容。

valueOf() 和 toString() 是定义在 Object.prototype 上的方法,但是 js 的许多内置对象都重写了这两个函数,以符合自身需求。

JS 内部用于实现类型转换的4个函数

ToPrimitive ( input [ , PreferredType ] )

将input转化成一个原始类型的值。 PreferredType参数要么不传入,要么是 Number 或 String。

  • 如果 PreferredType 参数是 Number,ToPrimitive这样执行:

    1. 如果input本身就是原始类型,直接返回input。
    2. 调用input.valueOf(),如果结果是原始类型,则返回这个结果。
    3. 调用input.toString(),如果结果是原始类型,则返回这个结果。
    4. 抛出TypeError异常。
  • 以下是 PreferredType 不为 Number 时的执行顺序。

    1. 如果PreferredType参数是String,则交换第2和第3步的顺序,其他执行过程相同。
    2. 如果PreferredType参数没有传入
    3. 如果input是内置的Date类型,PreferredType 视为String
    4. 否则PreferredType 视为 Number

可以看出,ToPrimitive依赖于 valueOf 和 toString 的实现。

ToBoolean ( argument )

ToNumber ( argument )

ToString ( argument )

详细内容请参考