js中的类型转换(ES6)

我们一直知道js是一种动态类型的语言,也正因为这种特性,我们使用的时候既觉得灵活有时候也会觉得坑。以下整理了ES6涉及到的转换操作。

ECMAScript会根据需要隐式执行自动类型转换。为了明确某些构造的语义,定义一组转换抽象操作是很有用的。转换抽象操作是多态的;它们可以接受任何ECMAScript语言类型或完成记录值的值。但是这些操作没有使用其他规范类型。

1 ToPrimitive(input[, PreferredType])转换原始类型。

抽象操作ToPrimitive接受input参数和可选参数preferredType。抽象操作ToPrimitive将其输入参数转换为非对象类型。如果一个对象能够转换为多种原始类型,那么它可以使用可选的参数PreferredType来支持该类型转换。根据下表:

输入类型 输出结果
Completion Record 如果输入参数input是一个中断完成(break这种),返回input;否则返回ToPrimitive(input.[[value]])并且传入可选的提示PreferredType。
Undefined 返回Undefined
Null 返回Null
Boolean 返回Boolean input
Number 返回Number input
String 返回String input
Symbol 返回Symbol input
Object 根据下列1.1流程:

(其中Completion Record:完成类型是一个记录,用于解释值和控制流的运行时传播,例如执行非本地控制传输的语句,如break、continue、return和throw的行为。)

1.1 Object转为原始类型

  • 1.如果PreferredType没有赋值,hint为"default"(hint为转换示意);
  • 2.如果PreferredType是String的示意,hint为"string"
  • 3.如果PreferredType是Number的示意,hint为"number"
  • 4.设置抽象值exoticToPrim为抽象函数GetMethod(input, @@toPrimitive)的返回结果(GetMethod用于获取对象的特定属性的值,此处即获取input的转原始类型方法);
  • (中断判断exoticToPrim);
  • 6.如果exoticToPrim是undefined,那么
    • 设置result等于Call(exoticToPrim, input, « hint »),即执行exoticToPrim(hint);
    • (中断判断result);
    • 如果result是原始数据类型,返回result;
    • 抛出一个TypeError异常;
  • 如果hint是"default",使hint为"number"
  • 返回下列OrdinaryToPrimitive(input, hint)的值。

OrdinaryToPrimitive(input, hint)

  • input:Object,数据类型
  • hint:String,转换示意,’string’或’number’

执行步骤:

  • 1.判断input是不是对象;
  • 2.判断hint是不是’string’或’number’;
  • 3.如果hint是"string",设置methodNames等于« "toString", "valueOf" »
  • 4.如果hint是"number"(记住不是’string’就是’number’),设置methodNames等于« "valueOf", "toString" »
  • 5.对刚设置的变量methodNames的每一项进行迭代并执行:
    • 获取对象的执行方式,如input.toString
    • (中断判断method);
    • 如果是可执行的,那么
      • 设置result为执行调用结果
      • 如果result的类型不是Object,返回result
  • 抛出一个TypeError异常;

toPrimitive是可以定义修改的。Symbol.toPrimitive

来猜测一下以下执行的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Q1
var obj1 = {
[Symbol.toPrimitive] (hint) {
if (hint === 'number') {
return 123456
} else {
return '陈冠希'
}
}
};

String(obj1);
Number(obj1);

1
2
3
4
5
6
7
8
9
10
11
12
// Q2
var obj2 = {
valueOf () {
return [1,2]
},
toString () {
return [3,4]
}
};

String(obj2);
Number(obj2);

更多问题可见https://github.com/MichealWayne/study-js-from-questions

2.ToBoolean ( argument )转换布尔值

抽象操作ToBoolean将参数argument转为一个布尔值。根据下表:

输入类型 输出结果
Completion Record 如果输入参数input是一个中断完成(break这种),返回input;否则返回ToPrimitive(input.[[value]])并且传入可选的提示PreferredType。
Undefined 返回false
Null 返回false
Boolean 返回Boolean argument
Number 如果argument是+0-0NaN返回false,否则返回true
String 如果是空字符串(’’/“”)返回false,否则返回true
Symbol 返回true
Object 返回true

3.ToNumber ( argument )转换为数字

抽象操作ToNumber将参数argument转为一个数字值。根据下表:

输入类型 输出结果
Completion Record 如果输入参数input是一个中断完成(break这种),返回input;否则返回ToPrimitive(input.[[value]])并且传入可选的提示PreferredType。
Undefined 返回NaN
Null 返回+0
Boolean 如果是true返回1,如果是false返回+0
Number 返回Number argument
String 见下面3.1
Symbol 抛出一个TypeError异常
Object 第一步转为原始类型获得变量primValue,hint为’number’(ToPrimitive(argument, hint Number)),第二步调用数字转换ToNumber(primValue).

3.1 ToNumber(String)

先判断是否合规

首先ToNumber的字符串String的应用于解释为UTF-16编码代码点序列的输入字符串。如果语法无法将字符串解释为StringNumericLiteral的扩展,即如果字符串包含任何补充代码点或任何不成对的代理代码点的UTF-16编码,则ToNumber的结果是NaN。

语法

1
2
3
StrWhiteSpace(opt)

StrWhiteSpace(opt) StrNumericLiteral StrWhiteSpace(opt)

其中

  • StrWhiteSpace:空格、行终止
  • StrNumericLiteral:
    • StrDecimalLiteral:十进制字符
    • BinaryIntegerLiteral:二进制字符
    • OctalIntegerLiteral:八进制字符
    • HexIntegerLiteral:十六进制字符

详细的不多说,基本要在以下字符中找:

1
+ - e E 0 1 2 3 4 5 6 7 8 9 Infinity

所以像以下这种字符都不行(NaN)

1
2
3
'1 1'
'1a'
'infinity'

以下这种倒又是可以的

1
2
3
4
'\n1'
' 1'
'-1E2'
' Infinity '

再进行转换:mv

将字符串转换为数字值的整个过程与确定数字文本的数字值类似,但有些细节不同。该值分两步确定:
-
第一步,从字符串数字文本派生一个数学值(mv);
第二步,如下文所述对该数学值进行四舍五入。

具体细节在这就不记录了。

4.ToInteger ( argument )转换为整数

抽象操作ToInteger将参数argument转为一个整数数字值。根据以下流程:

  • 1.设置number为ToNumber(argument)
  • (中断判断number);
  • 2.如果number是NaN,返回+0;
  • 3.如果number是+0、-0、+∞或-∞,返回number;
  • 4.返回符号sign和floor(abs(number))向下取正取整。

5.ToInt32 ( argument )转为32位整数(有符号)

抽象操作ToInt32将参数argument转为-2^31 ~ 2^31-1范围内的一个整数数值。根据以下流程:

  • 1.设置number为ToNumber(argument)
  • (中断判断number);
  • 2.如果number是NaN、+0、-0、+∞或-∞,返回+0;
  • 3.设置int为返回符号sign和floor(abs(number))向下取正取整;
  • 4.设置int32bit按2^32取模计算;
  • 5.如果int32bit大于2^31,返回int32bit-2^32,否则返回int32bit。

6.ToUint32 ( argument )转为无符号32位整数

抽象操作ToUint32将参数argument转为0 ~ 2^32-1范围内的一个整数数值。根据以下流程:

  • 1.设置number为ToNumber(argument)
  • (中断判断number);
  • 2.如果number是NaN、+0、-0、+∞或-∞,返回+0;
  • 3.设置int为返回符号sign和floor(abs(number))向下取正取整;
  • 4.设置int32bit按2^32取模计算;
  • 5.返回int32bit

7.ToInt16 ( argument )转为16位整数(有符号)

类似于ToInt32,范围是 −32768~32767

8.ToUint16 ( argument )转为无符号16位整数

类似于ToUint32,范围是0 ~ 2^16−1

9.ToInt8 ( argument )转为8位整数(有符号)

类似于ToInt32,范围是 −128~127

10.ToUint8 ( argument )转为无符号8位整数

类似于ToUint32,范围是0 ~ 255

11.ToUint8Clamp ( argument )

与ToUint8类似,但执行步骤有所不同

  • 1.设置number为ToNumber(argument)
  • (中断判断number);
  • 2.如果number是NaN,返回+0;
  • 3.如果number小于等于0,返回+0;
  • 4.如果number大于等于255,返回255;
  • 5.设置f为number向下取整(floor(number));
  • 6.如果f+0.5 < number,返回f + 1;
  • 7.如果number < f+0.5,返回f;
  • 8.如果f是奇数,返回f+1;
  • 9.返回f。

12.ToString ( argument )转为字符串

抽象操作ToString将参数argument转为一个字符串,根据下表:

输入类型 输出结果
Completion Record 如果输入参数input是一个中断完成(break这种),返回input;否则返回ToPrimitive(input.[[value]])并且传入可选的提示PreferredType。
Undefined 返回字符串”undefined”
Null 返回字符串”null”
Boolean argument为true则返回字符串”true”,否则返回字符串”false”
Number 见下面12.1
String 返回String argument
Symbol 抛出一个TypeError异常
Object 第一步转为原始类型获得变量primValue,hint为”string”,,第二步调用字符串转换ToString(primValue).

12.1 ToString(Number)

  • 1.如果argument是NaN,返回字符串”NaN”;
  • 2.如果argument是+0或-0,返回字符串”0”;
  • 3.如果argument小于0,返回字符串”-“和ToString(-argument)
  • 4.如果m是+∞,返回字符串”Infinity’;
  • 5.设置整数n, k, s,其中k >= 1, 10^(k-1) <= s < 10^k。argument = s * 10^(n - k),并且k尽可能小。注意,k是s的十进制表示中的位数,s不能被10整除并且s的最低有效位不一定由这些标准唯一确定。。
  • 6.如果k <= n <= 21,返回由s的十进制表示的k位数的代码单位组成的字符串(按顺序,不带前导零),然后是代码单位0x030(数字零)的n-k次出现。
  • 7.如果0 < n <= 21,则返回字符串,该字符串由S的十进制表示中最有效n位的代码单位组成,然后是代码单位0x002E(完全停止),然后是S的十进制表示中剩余k-n位的代码单位。
  • 8.如果−6 < n <= 0,则返回由代码单元0x030(数字零)组成的字符串,然后返回代码单元0x002E(完全停止),然后返回代码单元0x030(数字零)的−n次出现,最后返回十进制表示s的k位的代码单元。
  • 9.否则,如果k=1,返回根据n−1是正数还是负数,返回由s的单个数字的代码单位组成的字符串,后跟代码单位0x0065(拉丁文小写字母E),后跟代码单位0x002b(加号)或代码单位0x002d(连字符-减号),后跟代码单位整数abs(n-1)的十进制表示(不带前导零)。
  • 10.返回一个字符串,该字符串由s的小数表示形式中最有效位的代码单位组成,后跟代码单位0x002E(完全停止),然后是s的小数表示形式中剩余k−1位的代码单位,最后是代码单位0x0065(拉丁文小写字母E),然后是代码单元0x002B(加号)或代码单元0x002D(连字符-减号),根据n−1是正数还是负数,然后是整数abs(n−1)的十进制表示的代码单元(不带前导零)。

13.ToObject ( argument )转为对象

抽象操作ToObject将参数argument转为一个Object,根据下表:

输入类型 输出结果
Completion Record 如果输入参数input是一个中断完成(break这种),返回input;否则返回ToPrimitive(input.[[value]])并且传入可选的提示PreferredType。
Undefined 抛出一个TypeError异常
Null 抛出一个TypeError异常
Boolean 返回一个新的Boolean布尔对象,该对象的[[booleandata]]内部设置为参数值
Number 返回一个新的Number数字对象,该对象的 [[NumberData]] 内部设置为参数值
String 返回一个新的String字符对象,该对象的 [[StringData]] 内部设置为参数值
Symbol 返回一个新的Symbol对象,该对象的 [[SymbolData]] 内部设置为参数值
Object 返回Object argument

14 ToPropertyKey ( argument )转为属性键

抽象操作ToPropertyKey将参数argument转为一个能作为属性键(key)的值,流程如下:

  • 1.设置key为argument转换为原始类型的值(ToPrimitive(argument, hint String).
  • (中断判断);
  • 2.如果key的类型是Symbol,返回key
  • 3.将key转为字符串(ToString(key))后返回

15 ToLength ( argument )转为适合用作类数组对象长度的整数

抽象操作ToLength将参数argument转为一个适合用作类数组对象长度的整数,流程如下:

  • (中断判断argument);
  • 1.设置len为argument转为整数的值(ToInteger(argument));
  • (中断判断len);
  • 2.如果len <= +0,返回+0;
  • 3.如果len是+∞,返回2^53-1;
  • 返回len和2^53-1两者的较小值(min(len, 2^53 - 1))

16 CanonicalNumericIndexString ( argument )规范数字索引字符串

抽象操作CanonicalNumericIndexString将参数argument转为一个数值,如果该参数是ToString或字符串“-0”将生成的数字的字符串表示形式。否则,返回未定义。流程如下:

  • 1.确认argument是一个字符串
  • 2.如果argument是”-0”,返回-0;
  • 3.设置n为argument转为数字的值(ToNumber(argument));
  • 4.如果ToString(n)与argument不相同,返回Undefined
  • 5.返回数字n。

规范数字字符串是CanonicalNumericIndexString抽象操作后未返回Undefined的任何字符串值。


细节点还是很多的。