◆
JavaScript 类型转换:显式与隐式转换规则详解
显式转换
- 通过手动进行类型转换,Javascript 提供了以下转型函数:
- 转换为数值类型:
Number(mix)、parseInt(string,radix)、parseFloat(string) - 转换为字符串类型:
toString(radix)、String(mix) - 转换为布尔类型:
Boolean(mix)
- 转换为数值类型:
String(mix)
将任何类型的值转换为字符串,其规则为:
- 如果有
toString()方法,则调用该方法(不传递radix参数)并返回结果 - 如果是
null,返回"null" - 如果是
undefined,返回"undefined" String方法的参数如果是对象,返回一个类型字符串;如果是数组,返回该数组的字符串形式。- 先调用对象自身的
toString方法。如果返回原始类型的值,则对该值使用String函数,不再进行以下步骤。 - 如果
toString方法返回的是对象,再调用原对象的valueOf方法。如果valueOf方法返回原始类型的值,则对该值使用String函数,不再进行以下步骤。 - 如果
valueOf方法返回的是对象
- 先调用对象自身的
boolean
- 是一个布尔值的对象包装器。
- 第一个参数传递的值将转换为布尔值。如果省略或值
0,-0,0n,-0n,null,false,NaN,undefined,或空字符串("" || `` || ''),该对象具有的初始值false。 - 所有其他值,包括任何对象,空数组([])或字符串"
false",都会创建一个初始值为true的对象。 - 不要将基本类型中的布尔值
true和false与值为true和false的Boolean对象弄混了。 - 其值不是
undefined或null的任何对象(包括其值为false的布尔对象)在传递给条件语句时都将计算为true。 例如,以下if语句中的条件评估为true:
var x = new Boolean(false); // 一个值为 false 的 Boolean 对象
// object
console.log(typeof x);
if (x) {
console.log('这里的代码会被执行');
}
// ===
var x = Boolean(false);
// boolean
console.log(typeof x);
if (x) {
console.log('这里的代码不会被执行');
}
Number
Number(mix)函数,可以将任意类型的参数mix转换为数值类型。其规则为:- (1) 如果是布尔值,
true和false分别被转换为1和0 - (2) 如果是数字值,返回本身。
- (3) 如果是
null,返回0. - (4) 如果是
undefined,返回NaN。 - (5) 如果是字符串,遵循以下规则:
- 1、如果字符串中只包含数字,则将其转换为十进制(忽略前导
0) - 2、如果字符串中包含有效的浮点格式,将其转换为浮点数值(忽略前导
0) - 3、如果是空字符串,将其转换为
0 - 4、如果字符串中包含非以上格式,则将其转换为
NaN
- 1、如果字符串中只包含数字,则将其转换为十进制(忽略前导
- (6) 如果是对象
- 调用对象自身的
valueOf方法。如果返回原始类型的值,则直接对该值使用Number函数,不再进行后续步骤。 - 第二步,如果
valueOf方法返回的还是对象,则改为调用对象自身的toString方法。如果toString方法返回原始类型的值,则对该值使用Number函数,不再进行后续步骤。 - 第三步,如果
toString方法返回的是对象,就报错。
- 调用对象自身的
- (1) 如果是布尔值,
console.log(Number(false)); // 0
console.log(Number(-0)); // -0
console.log(Number(Infinity)); // Infinity
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(Number(0x11)); // 17
console.log(Number('03 ')); // 3
console.log(Number(' 03x')); // NaN
console.log(Number('0x03')); // 3
console.log(Number(' +0 ')); // 0
console.log(Number('0 5')); // NaN
console.log(Number('0a3')); // NaN
console.log(Number(' 0.3')); // 0.3
console.log(Number('0.3.2 ')); // NaN
console.log(Number('null')); // NaN
console.log(Number('')); // 0
console.log(Number(new Number(3))); // 3
console.log(Number(new String('null'))); // NaN
console.log(Number({ a: 3 })); // NaN
console.log(Number({})); // NaN
console.log(Number([3, 4])); // NaN
console.log(Number([])); // 0
console.log(Number([1])); // 1
console.log(Number(['333'])); // 333
隐式转换
逻辑运算符
- 逻辑与,AND(&&)
expr1&&expr2若expr1可转换为true,则返回expr2;否则,返回expr1。 - 逻辑或,OR(||)
expr1||expr2若expr1可转换为true,则返回expr1;否则,返回expr2。 - 逻辑非,NOT(!)
!expr若expr可转换为true,则返回false;否则,返回true。
false && true; // 返回 false
'Cat' && 'Dog'; // 返回 "Dog"
false && 'Cat'; // 返回 false
'Cat' && false; // 返回 false
'' && false; // 返回 ""
false && ''; // 返回 false
NaN && ''; // 返回 NaN
'' || false; // 返回 false
false || ''; // 返回 ""
关系操作符(<, >, <=, >=)
关系操作符的操作值也可以是任意类型的,所以使用非数值类型参与比较时也需要系统进行隐式类型转换:
- 如果两个操作值都是数值,则进行数值比较
- 如果两个操作值都是字符串,则比较字符串对应的字符编码值
- 如果只有一个操作值是数值,则将另一个操作值转换为数值,进行数值比较
- 如果一个操作数是对象,则调用
valueOf()方法(如果对象没有valueOf()方法则调用toString()方法),得到的结果按照前面的规则执行比较 - 如果一个操作值是布尔值,则将其转换为数值,再进行比较 注:
NaN是非常特殊的值,它不和任何类型的值相等,包括它自己,同时它与任何类型的值比较大小时都返回false。
一元加/减值符(+/-)
一元运算符, 如果操作数在之前不是 number,试图将其转换为 number
console.log(+[]); // 0
console.log(+[1, 2]); // NaN
console.log(+true); // 1
加法运算操作符
- 如果两个操作值都是数值,其规则为:
- 如果一个操作数为 NaN,则结果为
NaN - 如果是
Infinity+Infinity,结果是Infinity - 如果是
-Infinity+(-Infinity),结果是-Infinity - 如果是
Infinity+(-Infinity),结果是NaN - 如果是
+0+(+0),结果为+0 - 如果是
(-0)+(-0),结果为-0 - 如果是
(+0)+(-0),结果为+0 - 如果两个操作值都是字符串,则将它们拼接起来
- 如果只有一个操作值为字符串,则将另外操作值转换为字符串,然后拼接起来
- 如果一个操作数是对象、数值或者布尔值,则调用
toString()方法取得字符串值,然后再应用前面的字符串规则。对于undefined和null,分别调用String()显式转换为字符串。 - 可以看出,加法运算中,如果有一个操作值为字符串类型,则将另一个操作值转换为字符串,最后连接起来。
console.log(1 + 'str'); // '1str'
console.log(1 + 3); // 4
console.log(1 + '3'); // '13'
console.log('1' + '3'); // '13'
console.log(1 + []); // '1'
console.log(1 + {}); // '1[object Object]'
console.log(1 + function test() {}); // '1function test(){}'
console.log([] + {}); // '[object Object]'
console.log([1] + {}); // '1[object Object]'
console.log([1] + [2]); // '12'
console.log(['3'] + {}); // '3[object Object]'
console.log(['4', '5'] + {}); // '4,5[object Object]'
console.log(['4', '5'] + 1); // '4,51'
console.log(['4', '5'] + '1'); // '4,51'
乘除、减号运算符、取余运算符
这些操作符针对的是运算,所以他们具有共同性:如果操作值之一不是数值,则被隐式调用 Number() 函数进行转换。
相等操作符 == or !=
- ==,转化成同一类型后的值,看“值”是否相等。
- ===,如果类型不同,其结果就是不等。
- 相等操作符(
== or !=)会对操作值进行隐式转换后进行比较: - 布尔类型与其它任何类型进行比较,布尔类型将会转换为
number类型,如果为true,那么会转换为1,如果为false,会转换为整数0,即0。 - 如果一个操作值为字符串,另一个操作值为数值,则通过
Number()函数将字符串转换为数值 - 如果一个对象与数字或字符串相比较,
JavaScript会尝试返回对象的默认值。操作符会尝试通过方法valueOf和toString将对象转换为其原始值(一个字符串或数字类型的值)。如果尝试转换失败,会产生一个运行时错误。 null与undefined是相等的- 如果一个操作值为
NaN,则相等比较返回false - 如果两个操作值都是对象,则比较它们是不是指向同一个对象
number类型或string类型与object类型进行比较,number或者string类型都会转换为object类型
// true
console.log(null == undefined);
// false
console.log(NaN == NaN);
// false
console.log(null === undefined);
// true
console.log(0 === -0);
// false
console.log({ a: 1 } == { a: 1 });
// true
console.log({ a: 1 } == '[object Object]');
other
空值合并运算符
当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。
const foo = null ?? 'default string';
// default string
console.log(foo);
const baz = 0 ?? 42;
// 0
console.log(baz);
- 以前,如果想为一个变量赋默认值,通常的做法是使用逻辑或操作符(
||): - 然而,由于
||是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。任何假值 (0, '', NaN, null, undefined)都不会被返回。这导致如果你使用0,''或NaN作为有效值,就会出现不可预料的后果。
let foo;
let someDummyText = foo || 'Hello!';
let count = 0;
let text = '';
let qty = count || 42;
let message = text || 'hi!';
console.log(qty); // 42,而不是 0
console.log(message); // "hi!",而不是 ""
let myText = '';
let notFalsyText = myText || 'Hello world';
console.log(notFalsyText); // Hello world
let preservingFalsy = myText ?? 'Hi neighborhood';
console.log(preservingFalsy); // ''
- 不能与 AND 或 OR 操作符共用
null || undefined ?? "foo"; // 抛出 SyntaxError
true || undefined ?? "foo"; // 抛出 SyntaxError
// 用括号包裹
(null || undefined) ?? "foo"; // 返回 "foo"
可选链操作符
- 可选链操作符(
?.)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。 ?.操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空(null或者undefined) 的情况下不会引起错误,该表达式短路返回值是undefined。- 与函数调用一起使用时,如果给定的函数不存在,则返回
undefined。 - 当使用方括号与属性名的形式来访问属性时,你也可以使用可选链操作符:
let nestedProp = obj?.['prop' + 'Name'];
- 可选链不能用于赋值
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
- 可选链访问数组元素
let arrayItem = arr?.[42];
- 使用空值合并操作符
let customer = {
name: 'Carl',
details: { age: 82 },
};
let customerCity = customer?.city ?? '暗之城';
console.log(customerCity); // “暗之城”
Object.js
- 不和 == 一样,它不会进行隐式类型转换
- 与
===的区别如下
Object.is(0, -0); // false
Object.is(+0, -0); // false
Object.is(0, +0); // true
Object.is(-0, -0); // true
Object.is(NaN, 0 / 0); // true
模板字符串
- 如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的 toString 方法。
var obj = {};
// [object Object]
console.log(`${obj}`);
// true
console.log(obj.toString() === `${obj}`);
对象转原始类型
对象转原始类型,会调用内置的 [ToPrimitive] 函数,对于该函数而言,其逻辑如下:
- 如果有
Symbol.toPrimitive()方法,优先调用再返回 - 调用
valueOf(),如果转换为原始类型,则返回 - 调用
toString(),如果转换为原始类型,则返回 - 如果都没有返回原始类型,会报错
var obj = {
value: 3,
valueOf() {
return 4;
},
toString() {
return '5';
},
[Symbol.toPrimitive]() {
return 6;
},
};
console.log(obj + 1); // 输出7
// ===
var obj = {
value: 3,
valueOf() {
return 4;
},
toString() {
return '5';
},
};
console.log(obj + 1); // 输出5
// ===
var obj = {
value: 3,
toString() {
return '5';
},
};
console.log(obj + 1); // 输出51 注意 toString 返回的是一个字符串5
// ===
var obj = {
value: 3,
};
// obj.toString == [object Object] ==> [object Object]1
console.log(obj + 1);
Symbol.toPrimitive
- 一个内置的
Symbol值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。 - 在
Symbol.toPrimitive属性(用作函数值)的帮助下,一个对象可被转换为原始值。 - 该函数被调用时,会被传递一个字符串参数
hint,表示要转换到的原始值的预期类型。 hint参数的取值是number、string和default中的任意一个。
// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果
var obj1 = {};
console.log(+obj1); // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ''); // "[object Object]"
// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果
var obj2 = {
[Symbol.toPrimitive](hint) {
if (hint == 'number') {
return 10;
}
if (hint == 'string') {
return 'hello';
}
return true;
},
};
console.log(+obj2); // 10 -- hint 参数值是 "number"
console.log(`${obj2}`); // "hello" -- hint 参数值是 "string"
console.log(obj2 + ''); // "true" -- hint 参数值是 "default"
如何让 if(a == 1 && a == 2) 条件成立?
var a = {
value: 0,
valueOf: function () {
this.value++;
return this.value;
},
};
// true
console.log(a == 1 && a == 2);
[] == ![]结果是什么?为什么?
- 首先可以看成是 对象(
[])和布尔值(![])的比较 ==中,布尔值先转换成数字 ![] 转换为0- 变成对象(
[])和数值(0)的比较 - 应用对象的 toString 方法将
[]转换为"" - 变成字符串(
"")和数值(0)的比较 - 将字符串(
"")转换为数值0 0 == 0结果为true

还没有留言,来发表第一条吧~