10081677wc / blog

78 stars 6 forks source link

彻底理解 JavsScript 类型转换 #22

Open 10081677wc opened 6 years ago

10081677wc commented 6 years ago

彻底理解 JavsScript 类型转换

为什么 []==![] 是 true?

EqualityExpression

产生式 EqualityExpression:EqualityExpression == RelationalExpression 按照如下过程执行:

  1. 令 lref 为解释执行 EqualityExpression 的结果;
  2. 令 lval 为 GetValue(lref);
  3. 令 rref 为解释执行 RelationalExpression 的结果;
  4. 令 rval 为 GetValue(rref);
  5. 返回作用相等比较算法于 rval == lval 的结果。

UnaryExpression

产生式 UnaryExpression:!UnaryExpression 按照如下过程执行:

  1. 令 expr 为解释执行 UnaryExpression 的结果;
  2. 令 oldValue 为 ToBoolean(GetValue(expr));
  3. 如果 oldValue 为 true,返回 false;
  4. 返回 true。

相等比较算法

比较运算 x==y,其中 x 和 y 是值,产生 true 或者 false 的结果,按照如下过程执行:

  1. 若 Type(x) 与 Type(y) 相同则: 1.1. 若 Type(x) 为 Undefined,返回 true; 1.2. 若 Type(x) 为 Null,返回 true; 1.3. 若 Type(x) 为 Number 则: 1.3.1. 若 x 或 y 为 NaN,返回 false; 1.3.2. 若 x 与 y 为相等数值,返回 true; 1.3.3. 若 x 为 +0 且 y 为 -0,返回 true; 1.3.4. 若 x 为 -0 且 y 为 +0,返回 true; 1.3.5. 返回 false; 1.4. 若 Type(x) 为 String 则当 x 和 y 为完全相同的字符序列时返回 true,否则返回 false; 1.5. 若 Type(x) 为 Boolean 则当 x 和 y 同为 true 或者同为 false 时返回 true,否则返回 false;
  2. 若 x 为 null 且 y 为 undefined 返回 true;
  3. 若 x 为 undefined 且 y 为 null 返回 true;
  4. 若 Type(x) 为 Number 且 Type(y) 为 String 则返回比较运算 x==ToNumber(y) 的结果;
  5. 若 Type(x) 为 String 且 Type(y) 为 Number 则返回比较运算 ToNumber(x)==y 的结果;
  6. 若 Type(x) 为 Boolean 则返回比较运算 ToNumber(x)==y 的结果;
  7. 若 Type(y) 为 Boolean 则返回比较运算 x==ToNumber(y) 的结果;
  8. 若 Type(x) 为 String 或 Number 且 Type(y) 为 Object 则返回比较运算 x==ToPrimitive(y) 的结果;
  9. 若 Type(x) 为 Object 且 Type(y) 为 String 或 Number 则返回比较运算 ToPrimitive(x)==y 的结果;
  10. 返回 false;

ToBoolean

输入类型 结果
Undefined false
Null false
Boolean 结果等于输入的参数(不发生转换)
Number 如果参数是+0、-0或 NaN 则结果为 false,否则为 true
String 如果参数是空字符串则结果为 false,否则为 true
Object true

ToNumber

输入类型 结果
Undefined NaN
Null +0
Boolean 如果参数是 true 则结果为1,如果参数为 false 则结果为+0
Number 结果等于输入的参数(不发生转换)
String 参加下文的文法和注释
Object 设原始值的为 ToPrimitive(参数) 的结果并返回 ToNumber(原始值)

ToPrimitive

输入类型 结果
Undefined 结果等于输入的参数(不发生转换)
Null 结果等于输入的参数(不发生转换)
Boolean 结果等于输入的参数(不发生转换)
Number 结果等于输入的参数(不发生转换)
String 结果等于输入的参数(不发生转换)
Object 返回该对象的默认值,对象的默认值由把期望类型传入作为 hint 参数调用对象的内部方法 [[DefaultValue]] 得到

ToPrimitive(obj, preferredType) 第一个参数 obj 为被转换的对象,第二个参数 preferredType 为希望转换成的类型(默认为空,接受的值为 Number 或 String)。

在执行 ToPrimitive(obj, preferredType) 时,如果第二个参数为空并且 obj 为 Date 的实例时 preferredType 会 被设置为 String;其他情况下 preferredType 都会被设置为 Number,此时有执行过程如 下:

  1. 如果 obj 为原始值则直接返回;
  2. 否则调用 obj.valueOf(),如果执行结果是原始值则返回之;
  3. 否则调用 obj.toString(),如果执行结果是原始值则返回之;
  4. 否则抛异常。

如果 preferredType 为 String 则将上面的第2步和第3步调换即:

  1. 如果 obj 为原始值则直接返回;
  2. 否则调用 obj.toString(),如果执行结果是原始值则返回之;
  3. 否则调用 obj.valueOf(),如果执行结果是原始值则返回之;
  4. 否则抛异常。

toString 用来返回对象的字符串表示:

const o = {};
o.toString(); // "[object Object]"
const a = [];
a.toString(); // ""
const d = new Date();
d.toString(); // "Sat Feb 10 2018 16:41:20 GMT+0800 (CST)"

valueOf 方法返回对象的原始值,原始值指的是 ['Null', 'Undefined', 'String', 'Boolean', 'Number'] 五种基本数据类型之一:

const o = {a: 1};
o.valueOf(); // {a: 1}
const a = [1];
a.valueOf(); // [1]
const d = new Date();
d.valueOf(); // 1518252406357

http://es5.github.io/#x11.9.3