最近一直在看《你不知道的 JS》,轻总结下,转换类型。
强制转换分为隐式和显式转化,虽然名声不好,但还是有必要知道转换的规则是啥。
显式的强制转换,通过减少困惑,增强了代码的可读性和可维护性。
隐式的强制转换,有其的“隐藏的”副作用,但有些也是为了增强代码的可读性。
TL;DR
- ToString:基本类型和函数就是原地加上引号。但对象、数组转化就麻烦点。
- JSON.stringify:不识别
undefined
和函数,对于对象可以跳过部分值。可以有第二个和第三个参数。 - ToNumber:一句话难概括。。。
- ToBoolean:只有特定的值是可以转化为
false
,其他都是true
- parseInt:是从字符串里解析数字,遇到非数字就停止。要始终传字符串类型,且加上进制参数
- 隐式转化:各种条件表达式、加减乘除、><、==。
><
尽量转化为数字之后在使用。尽量用===
替换==
ToString()
一般用xx.toString(xx)或者String(xx)
显示转化。
基本类型有自然的字符串化形式
String(null); // 'null'
String(undefined); // 'undefined'
String(true); // 'true'
String(1); // '1'
String(1000000000000000000000.1); // "1e+21", 稍微注意的是,如果数很大或者很小,会变成指数的
- 普通对象,会调用默认的
toString()
,会返回内部的[[ Class ]]
- 函数,会返回函数的字符串形式
- 数组,会将数组每个都字符串化,然后用 **","**拼接每个字符串
String({}); // "[object Object]"(
String(function () {}); // "function(){}"
String([1, 2, {}]); // "1,2,[object Object]"
JSON.stringify(xx)
string
、number
、boolean
、和 null
值在 JSON
字符串化时,和xx.toString()
的值基本是相同的。
JSON.stringify(null); // 'null'
JSON.stringify(true); // 'true'
JSON.stringify(1); // '1',
JSON.stringify(1000000000000000000000.1); // "1e+21",稍微注意的是,如果数很大或者很小,会变成指数的
但是,其他类型的都不一样了!!!
- 遇到
undefined
、function
、和symbol
时将会自动地忽略它们,返回undefined
- 遇到
array
的时候,如果某项是上面的值,会替换成null
- 遇到对象的时候,如果对象有**
toJSON
**的方法,会将其返回值字符串化。没有的话,直接转化,会跳过值是undefined
、function
、和symbol
。
JSON.stringify(undefined); // undefined
JSON.stringify(function () {}); // undefined
JSON.stringify([1, 2, undefined, function () {}]); // "[1,2,null,null]"
JSON.stringify({ a: 1, b: 2, c: undefined, hello() {} }); // "{\"a\":1,\"b\":2}"
JSON.stringify({
a: 1,
b: 2,
toJSON() {
return { a: this.a };
},
}); // "{\"a\":1}"
JSON.stringify 可以不止一个参数
第二个参数和第三个参数都是可选的。
第二个参数的作用类似toJSON
,可以指定特定的key
字符串化,可以是数组,也可以是函数。
第三个参数的作用,就是每级缩进,个人觉得这个,作用不大,知道就行。
var a = { b: 1, c: 2 };
JSON.stringify(a, ['b']); // "{\"b\":1}"
JSON.stringify(a, function (k, v) {
if (k === 'b') return v;
}); // "{\"b\":1}"
JSON.stringify(a, ['c'], '--'); // "{\n--\"c\": 2\n}"
ToNumber
一般用Number(xx)
显示转化。
undefined
的话,变成NaN
null
的话,变成0
Boolean
的话true
变成1
,false
变成0
- 字符串的话,只含整数或者小数都可以变成正常数字,其他都是
NaN
Number(undefined); // NaN
Number(null); // 0
Number(true); // 1
Number(false); // 0
Number('1.2'); // 1.2
Number('1.2d'); // NaN
对象以及数组,会先转换成基本类型值的等价物,然后根据上面的规则继续转化。
转换成等价物说白了,就是先调用xx.valueOf()
没有这个方法的话,就调用xx.toString()
,如果这两方法返回基本类型值的话,则Number(返回值)
,没返回基本值的话就报错
var a = {
valueOf() {
return '1';
},
toString() {
return '2';
},
};
Number(a); // 1
var b = { c: 1 };
Number(b); // NaN
var c = {
c: 1,
toString() {
return {};
},
};
Number(c); // 报错
ToBoolean
一般用Boolean(xx)
显示转化。
将其他类型的值转化为 Boolean 类型的值,其实只要记住哪些转化为false
即可,其他的都是true
。
undefined
null
false
+0
,-0
,NaN
""
特别注意:
- 空对象、空函数、空数组转换成 Boolean 的话都是
true
- 用 new 创建基本类型的时候,此时转化成 Boolean 的话也是
true
Boolean({} && [] && function () {}); // true
Boolean(new String('') && new Number(0) && new Boolean(false)); // true
其他的显式转换
上面的String(x)/Number(x)/Boolean(x)
都是显式转化。
还有一些其他公认的显式转换:
// number => string
1 + '' === String(1);
// string => number
+'1' === Number('1');
// date => number 获取当前时间戳 等同于 Date.now() 或 new Date().getTime()
+new Date() === Number(new Date());
// 任意类型 => Boolean
!!1;
~x 等同于 -(x+1)
有时候,还会看到~
。
在 JS 里,常和indexOf
结合使用。
-1
也是另一种哨兵值,C 语言里-1
表示失败。
而 JS 里的indexOf
返回值为-1 的话,也表示没找到。
const isInclude = 'abc'.indexOf('d') !== -1;
if (isInclude) {
// ...
}
这种写法没毛病,但如果用~
更简洁,这时候用在 if 里,相当于转换成 Boolean
const isInclude = ~('abc').indexOf('d')
if (isInclude).indexOf('d')) {
// ...
}
解析数字字符串:和强制转换不一样
解析数字字符串:从一个字符串中解析出一个数字是 容忍 非数字字符的 —— 从左到右,如果遇到非数字字符就停止解析 。 强制转换是 不容忍 并且会失败而得出值 NaN。
var a = '42';
var b = '42px';
Number(a); // 42
parseInt(a); // 42
Number(b); // NaN
parseInt(b); // 42
parseInt 是工作在string值上的,所以永远不要传入非 string,不然会强制转换成 string。
parseInt 还有第二个可选参数,表示将字符串翻译成几进制(2-35),默认是 10 进制,总是在第二个参数值上传递进制,注意,最终返回的结果是 10 进制。
parseInt('0x16', 10); // 0
parseInt('0x16', 16); // 22
parseInt('15', 10); // 15
// 15作为16进制的翻译,转化为10进制就是21
parseInt('15', 16); // 21
参数是非字符串的话,会有各种奇怪的现象,所以永远不要传入非 string
parseInt(1 / 0, 19); // 18 ("I" from "Infinity")
parseInt(0.000008); // 0 ("0" from "0.000008")
parseInt(0.0000008); // 8 ("8" from "8e-7")
parseInt(false, 16); // 250 ("fa" from "false")
parseInt(parseInt, 16); // 15 ("f" from "function..")
parseInt('0x10'); // 16
parseInt('103', 2); // 2
其他的隐式转换
- 、* 、/ 运算符会将两边隐式变成 number 类型
这个还好,也容易理解。
'1' - '2' === -1;
+ 运算符
使用加号运算符要小心,加到字符串类型的时候,另一边会强制转化成字符串类型。
2 + 1 + '1' === '31';
> 和 <
这种也会发生类型转换,为了消除歧义,最好转化为数字类型之后在使用。
var a = [42];
var b = '043';
a < b; // false -- 字符串比较!
Number(a) < Number(b); // true -- 数字比较!
'1' - '2';
* -> Boolean
哪个种类的表达式操作(隐含地)要求/强制一个 boolean 转换呢?
- 在一个
if (..)
语句中的测试表达式。 - 在一个
for ( .. ; .. ; .. )
头部的测试表达式(第二个子句)。 - 在
while (..)
和do..while(..)
循环中的测试表达式。 - 在
? :
三元表达式中的测试表达式(第一个子句)。 ||
(“逻辑或”)和&&
(“逻辑与”)操作符左手边的操作数(它用作测试表达式 —— 见下面的讨论!)
特别注意:一个&&或||操作符产生的值不见得是 Boolean 类型。这个产生的值将总是两个操作数表达式其中之一的值!
var a = 42;
var b = 'abc';
var c = null;
a || b; // 42
a && b; // "abc"
c || b; // "abc"
c && b; // null
// 经常可能会写这样的代码
var a = 42;
var b = null;
var c = 'foo';
// 其实这里相当于 if("foo") 因为是if表达式,所以隐式转化为 if(true)
if (a && (b || c)) {
console.log('yep');
}
== 和 ===
==
两边的转换规则,可能超乎你的想象,所以,最好直接使用===
。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!