一、类型转换先说类型
类型转换指将一种类型转换为另一种类型,那我们首先来说说JavaScript中的类型。
1.1原始(Primitive)数据类型
Null
Undefined
Boolean
String
Number
Symbol
BigInt
BigInt是一种新的数据类型,用于当整数值大于Number数据类型支持的范围时。这种数据类型允许我们安全地对大整数执行算术操作,表示高分辨率的时间戳,使用大整数id,等等,而不需要使用库。重要的是要记住,不能使用Number和BigInt操作数的混合执行算术运算,需要通过显式转换其中的一种类型。此外,出于兼容性原因,不允许在BigInt上使用一元加号(+)运算符。
1.2引用(Object)数据类型
javaScript中内置了很多对象。
Array
Array
ArrayBuffer
AsyncFunction
Atomics
BigInt
BigInt64Array
BigUint64Array
Boolean
DataView
Date
Error
EvalError
Float32Array
Float64Array
Function
Generator
GeneratorFunction
Infinity
Int16Array
Int32Array
Int8Array
InternalError
Intl
Intl.Collator
Intl.DateTimeFormat
Intl.ListFormat
Intl.Locale
Intl.NumberFormat
Intl.PluralRules
Intl.RelativeTimeFormat
JSON
Map
Math
NaN
Number
Object
Promise
Proxy
RangeError
ReferenceError
Reflect
RegExp
Set
SharedArrayBuffer
String
Symbol
SyntaxError
TypeError
TypedArray
URIError
Uint16Array
Uint32Array
Uint8Array
Uint8ClampedArray
WeakMap
WeakSet
WebAssembly
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
globalThis
isFinite()
isNaN()
null
parseFloat
parseInt
undefined
unescape()
uneval()
详情请参考MDN,
大家不要看javaScript的内置对象这么多,转换时只需要把这么统统当做一个类型引用类型进行转换就行,在javaScript内部中转换也不会考虑这么多。
二、自动装箱
为了方便操作基本数据类型, ECMAScript还提供了三个特殊的引用类型,基本包装类型,String、Boolean、Number。有了这三个类型,在需要的时候,原始类型会自动转换成相应的包装对象(这个过程叫自动装箱)。自动装箱就是临时创建一个包装对象,将原始类型的值封装起来,以便调用包装对象的函数。但是原来那个变量的值不会有任何变化!
var s1 = "some text";
var s2 = s1.substring(2);
字符串是基本数据类型,为撒能调用方法了,这其实在后台进行了一系列的操作
创建String类型的一个实例
在实例上调用指定的方法。
销毁这个实例。
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
当然,你可以将Boolean 、Number 、String 这三个函数当作构造函数来使用,通过手动new包装类来装箱(得到包装对象):
// 手动装箱
var s1 = new String("some text");
s1.toUpperCase();
typeof s1;
// "object"
三、类型转换的规则
四、内部用于实现类型转换的4个函数
4.1 ToPrimitive ( input [ , PreferredType ] )
// ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
// (1) for number hint, and (2) for string hint.
function ToPrimitive(x, hint) {
// Fast case check.
if (IS_STRING(x)) return x;
// Normal behavior.
if (!IS_SPEC_OBJECT(x)) return x;
if (IS_SYMBOL_WRAPPER(x)) throw MakeTypeError(kSymbolToPrimitive);
if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
return (hint == NUMBER_HINT) ? DefaultNumber(x) : DefaultString(x);
}
// ECMA-262, section 8.6.2.6, page 28.
function DefaultNumber(x) {
if (!IS_SYMBOL_WRAPPER(x)) {
var valueOf = x.valueOf;
if (IS_SPEC_FUNCTION(valueOf)) {
var v = % _CallFunction(x, valueOf);
if (IsPrimitive(v)) return v;
}
var toString = x.toString;
if (IS_SPEC_FUNCTION(toString)) {
var s = % _CallFunction(x, toString);
if (IsPrimitive(s)) return s;
}
}
throw MakeTypeError(kCannotConvertToPrimitive);
}
// ECMA-262, section 8.6.2.6, page 28.
function DefaultString(x) {
if (!IS_SYMBOL_WRAPPER(x)) {
var toString = x.toString;
if (IS_SPEC_FUNCTION(toString)) {
var s = % _CallFunction(x, toString);
if (IsPrimitive(s)) return s;
}
var valueOf = x.valueOf;
if (IS_SPEC_FUNCTION(valueOf)) {
var v = % _CallFunction(x, valueOf);
if (IsPrimitive(v)) return v;
}
}
throw MakeTypeError(kCannotConvertToPrimitive);
}
ToPrimitive将input装换为基本数据类型,PreferredType要么不传,要么是number、string。
4.1.1 PreferredType为number
如果input本身就是原始类型,直接返回input。
调用input.valueOf(),如果结果是原始类型,则返回这个结果。
调用input.toString(),如果结果是原始类型,则返回这个结果。
抛出TypeError异常。
4.1.2 PreferredType为string
如果input本身就是原始类型,直接返回input。
调用input.toString(),如果结果是原始类型,则返回这个结果。
调用input.valueOf(),如果结果是原始类型,则返回这个结果。
抛出TypeError异常。
4.1.3 PreferredType不传入
如果input是内置的Date类型,PreferredType 视为String
否则PreferredType 视为 Number。
来看看这道网上的面试题
({}) + 1
+号操作符,只有当左右两边的类型相同(都为string或者number)是才进行操作。所以会经历如下步骤:
{}和1都会调用ToPrimitive,1原始类型直接返回。
{}内部调用DefaultNumber,使用valueOf方法,返回object。
在调用toString方法,返回[object, object]。
所以最后的结果就是[object, object]1。
这一类转换换汤不换药,转换规则都是这样的。
4.2 ToBoolean ( argument )
4.3 ToNumber( argument )
4.4 ToString( argument )
来源:ECMA-262草案/ 2019年11月7日 ECMAScript®2020语言规范
五、隐式类型装换
在执行过程中当js内部期望得到某种类型的值,而实际在那里的值是其他的类型,就会发生隐式类型转换。系统内部会自动调用我们前面说ToBoolean ( argument )、ToNumber ( argument )、ToString ( argument ),尝试转换成期望的数据类型。
5.1 期望得到boolean的值
if ( !undefined && !null && !0 && !NaN && !'') {
// xxxx
}
因为在if的括号中,js期望得到boolean的值,所以对括号中每一个值都使用ToBoolean ( argument ),将它们转化成boolean。
5.2 期望得到number的值
3 * { valueOf: function () { return 5 } };
因为在乘号的两端,js期望得到number类型的值,所以对右边的那个对象使用ToNumber ( argument ),得到结果5,再与乘号左边的3相乘。
5.3 加号有别于其他运算符
如果有一边是字符串,就把另外一边也转换为字符串
如果一方不是字符串或者数据,就转换为数据或者字符串
处了加号运算符,其他运算符,只要其中一方数据,那么另一方就被转换为数字
六、显示类型装换
手动调用Boolean(value)、Number(value)、String(value)完成的类型转换。
Boolean('some text'); // true
Number("2019"); // 2019
String({a: 1}); // "[object Object]"
前面两个类型转换没有什么好解释的,我们看看最后一个String({a: 1});在内部发生的时候
执行转换String({a: 1})。
执行内部的ToString({a: 1})。
{a: 1}不是原始类型,执行ToPrimitive({a: 1}, hint string)。
调用toString方法,返回"[object, object]"。
执行ToString("[object, object]"),返回"[object, object]"。
参考文章:
tc39.es/ecma262/#se…
www.cxymsg.com/guide/jsBas…
源自:https://juejin.im/post/5dc431a0e51d4504be09ca8c
声明:文章著作权归作者所有,如有侵权,请联系小编删除。
本文分享自微信公众号 - web前端学习圈(web-xxq)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/3979844/blog/4924544