【JavaScript】类型转换

转 number 类型

Number 方法

  1. 对于 string

(1)空字符串 ''0
(2)纯数字的字符串 → 数字 (可识别指数字符串)
(3)非纯数字的字符串 → 转不了,返回 NaN

console.log(Number('')); // 0

console.log(Number('123')); // 123 - 整数
console.log(Number('123.123')); // 123.123 - 浮点数
console.log(Number('1.5e5')); // 150000 - 指数

console.log(Number('123a')); // NaN

不仅可以转换 10 进制的数字字符串,还能转换 2 进制、8 进制、16 进制的数字字符串。

注意:8 进制的数字字符串必须是 0o / 0O 开头,0 开头会被认为是 10 进制的数字字符串

// 2 进制
console.log(0b1010); // 10
console.log(Number('0b1010')); // 10

// 8 进制 - 0o 开头
console.log(0o12); // 10
console.log(Number('0o12')); // 10

// 8 进制 - 0 开头
console.log(012); // 10
console.log(Number('012')); // 12

// 16 进制
console.log(0xa); // 10
console.log(Number('0xa')); // 10

  1. 对于 booleantrue1false0
console.log(Number(true)); // 1
console.log(Number(false)); // 0

  1. 对于 null:返回 0
console.log(Number(null)); // 0

  1. 对于 undefined:返回 NaN
console.log(Number(undefined)); // NaN

  1. 对于对象:会先检查该值是否有 valueOf() 方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString() 的返回值来进行强制类型转换。如果 valueOf()toString() 均不返回基本类型值,会产生 TypeError 错误。
var a = {
    valueOf: function () {
        return '42';
    },
};
Number(a); // 42

var b = {
    toString: function () {
        return '42';
    },
};
Number(b); // 42

var c = [4, 2];
c.toString = function () {
    return this.join(''); // "42"
};
Number(c); // 42

Number([]); // 0
Number([1]); // 1
Number([1, 2]); // NaN
Number(['abc']); // NaN
const date = new Date();
console.log(Number(date)); // 1408369986000
console.log(date.valueOf()); // 1408369986000

不建议对日期类型使用强制类型转换,应该使用 Date.now() 来获得当前的时间戳,使用 new Date(..).getTime() 来获得指定时间的时间戳。

注意:使用 Object.create(null) 创建的对象 [[Prototype]] 属性为 null,并且没有 valueOf()toString() 方法,因此无法进行强制类型转换。


综上,在基本类型数据中:

  • Number(xxx) 返回 0 的值有:nullfalse''
  • Number(xxx) 返回 NaN 的值有:非纯数字的字符串undefined

正负号

本质上还是调用 Number(),只是多了正负号。

console.log(-'123'); // -123
console.log(+''); // 0
console.log(-true); // -1
console.log(+'123.6a745'); // NaN

数学运算

var a = '3.14';
var b = a - 0;

b; // 3.14

- 是数字减法运算符,因此 a - 0 会将 a 强制类型转换为数字。也可以使用 a * 1a / 1,因为这两个运算符也只适用于数字,只不过这样的用法不太常见。


对象的 - 操作与 + 类似:

var a = [3];
var b = [1];

a - b; // 2

为了执行减法运算,a 和 b 都需要被转换为数字,它们首先被转换为字符串(通过 toString()),然后再转换为数字。



转 string 类型

toString 方法

  1. 对于 numberboolean
const num = 123;
console.log(num.toString()); // "123"

const bool = true;
console.log(bool.toString()); // "true"

对于 number,toString 能传入 1 个参数 x (默认为 10),表示返回 x 进制的数字字符串:

const num = 10;
console.log(num.toString(2)); // "1010" —— 2 进制
console.log(num.toString(8)); // "12" —— 8 进制
console.log(num.toString(10)); // "10" —— 10 进制
console.log(num.toString(16)); // "a" —— 16 进制

对于极大/极小的 number,toString 会使用指数表示法:

const num = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
console.log(num.toString()); // "1.07e+21"

  1. 对于 nullundefined,没有包装类,不能调用 toString 方法,会报错:
const val = null;
console.log(val.toString()); // TypeError: Cannot read properties of null
const val = undefined;
console.log(val.toString()); // TypeError: Cannot read properties of undefined

  1. 对于普通对象,会调用 Object.prototype.toString(),返回内部属性 [[Class]] 的值 [object Object]
const obj = {};
console.log(obj.toString()); // "[object Object]"

如果对象有自己的 toString 方法,字符串化时就会调用该方法并使用其返回值:

const obj = {
    toString() {
        return '123';
    },
};
console.log(obj.toString()); // "123"

将对象强制类型转换为 string 是通过 ToPrimitive 抽象操作来完成的


  1. 对于数组,因为重新定义了 toString 方法,所以会调用 Array.prototype.toString(),返回数组元素组成的字符串,元素之间用 , 分隔:
const arr = [1, 2, 3];
console.log(arr.toString()); // "1,2,3"

String 方法

  • 对于 numberboolean普通对象数组:其实就是调用 toString 方法。
  • 对于 nullundefined:相当于直接用引号包裹。
console.log(String(undefined)); // "undefined"
console.log(String(null)); // "null"

字符串拼接

任意类型的数据与字符串拼接,都会被隐式转换成 string。


用空字符串进行拼接,效果与 String() 一样,且写起来更方便(推荐):

console.log('' + 123); // "123"
console.log('' + true); // "true"
console.log(undefined + ''); // "undefined"
console.log(null + ''); // "null"

也可以使用模板字符串:

console.log(`${123}`); // "123"
console.log(`${true}`); // "true"
console.log(`${undefined}`); // "undefined"
console.log(`${null}`); // "null"

对于对象a + ""String(a) 之间有一个细微的差别需要注意。根据 ToPrimitive 抽象操作规则,a + "" 会尝试调用 a.valueOf(),然后再尝试调用 a.toString()。而 String(a) 则是直接调用 a.toString()

var a = [1, 2];
var b = [3, 4];

a + b; // "1,23,4"

因为数组的 valueOf() 操作无法得到简单基本类型值,于是它转而调用 toString()。因此上例中的两个数组变成了 "1,2""3,4"+ 将它们拼接后返回 "1,23,4"

var a = {
    valueOf: function () {
        return 42;
    },
    toString: function () {
        return 4;
    },
};

a + ''; // "42"
String(a); // "4"

在定制 valueOf()toString() 时需要特别小心,因为这会影响强制类型转换的结果。

有一个坑常常被提到,即 [] + {}{} + [],它们返回不同的结果,分别是 "[object Object]"0



转 boolean 类型

  • 6 个负性值±0NaN''undefinednullfalse
  • 除了负性值,其他值转成 boolean 都是 true

Boolean 方法

  1. 对于 number0 & NaNfalse;其他 → true
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false

console.log(Boolean(12)); // true
console.log(Boolean(Infinity)); // true

  1. 对于 string''false;其他 → true
console.log(Boolean('')); // false

console.log(Boolean('a123')); // true

  1. 对于 nullundefinednull & undefinedfalse
console.log(Boolean(undefined)); // false
console.log(Boolean(null)); // false

  1. 对于对象true
var a = []; // true
var b = {}; // true
var c = function () {}; // true

逻辑非

逻辑运算符 ! 会把操作的数据转换为布尔类型,然后再取反。那再使用一次 !,不就可以将当前数据转换为对应的布尔值了咯。

console.log(!!''); // false
console.log(!!'ok'); // true

隐式强制类型转换

下面的情况会发生布尔值隐式强制类型转换。

  1. if (..) 语句中的条件判断表达式。
  2. for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
  3. while (..)do..while(..) 循环中的条件判断表达式。
  4. ? : 中的条件判断表达式。
  5. 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。
var a = 42;
var b = 'abc';
var c;
var d = null;

if (a) {
    console.log('yep'); // yep
}

while (c) {
    console.log('nope, never runs');
}

c = d ? a : b;
c; // "abc"

if ((a && d) || c) {
    console.log('yep'); // yep
}

|| 和 &&

逻辑运算符 ||(或)和 &&(与)应该并不陌生。

我其实不太赞同将它们称为 “逻辑运算符”,因为这不太准确。称它们为 “选择器运算符”(selector operators)或者 “操作数选择器运算符”(operand selector operators)更恰当些。

为什么?因为和其他语言不同,在 JS 中它们返回的并不是布尔值。它们的返回值是两个操作数中的一个(且仅一个)。即选择两个操作数中的一个,然后返回它的值。

var a = 42;
var b = 'abc';
var c = null;

a || b; // 42
a && b; // "abc"

c || b; // "abc"
c && b; // null

||&& 首先会对第一个操作数(ac)执行条件判断,如果其不是布尔值就先进行 ToBoolean 强制类型转换,然后再执行条件判断。

对于 || 来说,如果条件判断结果为 true 就返回第一个操作数(ac)的值,如果为 false 就返回第二个操作数(b)的值。

&& 则相反,如果条件判断结果为 true 就返回第二个操作数(b)的值,如果为 false 就返回第一个操作数(ac)的值。

||&& 返回它们其中一个操作数的值,而非条件判断的结果。c && bc 为 null,是一个假值,因此 && 表达式的结果是 null(即 c 的值),而非条件判断的结果 false。

a || b;
// 大致相当于:
a ? a : b;

a && b;
// 大致相当于:
a ? b : a;

之所以说 a || b a ? a : b 大致相当,是因为它们返回结果虽然相同但是却有一个细微的差别。在 a ? a : b 中,如果 a 是一个复杂一些的表达式(比如有副作用的函数调用等),它有可能被执行两次(如果第一次结果为真)。而在 a || ba 只执行一次,其结果用于条件判断和返回结果(如果适用的话)。a && ba ? b : a 也是如此。

日常开发中经常会见到类似 a = b || "something"a && b() 这种 “短路” 机制。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JS.Huang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值