【笔记】js中的类型转换(ES6)
Aug 3, 2019笔记jsesjs中的类型转换(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  | // Q2  | 
更多问题可见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、-0或NaN返回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
3StrWhiteSpace(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的任何字符串值。
细节点还是很多的。
Author
My name is Micheal Wayne and this is my blog.
I am a front-end software engineer.
Contact: michealwayne@163.com