持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
1、判断是不是Object
通过如下代码能否准确判断一个数据是否为Object呢?
function isObject(obj) {
if (typeof obj === "object") {
return true;
}
return false;
}
由于typeof null的结果也是"object",所以以上代码不能够准确判断出一个数据是否为object
那么typeof null为什么为"object"呢?
这个问题要追溯到JavaScript的第一个版本:
- 在这个版本中,单个值在栈中占有32位的存储单元,其分为两部分,标记位与数据部分,此版本中只有5种数据类型
// 类型标记位
// 000: object
// 001: integer
// 010: double
// 100: string
// 110: boolean
null是个特别的存在,在机器码中null的标记位与数据部分全是0,也就是32个0,所以typeof 在判断null时会返回object
那么为什么不修复这个问题呢?
考虑到有很多兼容性问题,如果修复了这个历史的问题会导致后续有很多兼容性问题产生,不得不做妥协
2、使用一元运算符+转为数字
const print = console.log;
function toNumber(val) {
const result = +val;
print(result);
}
toNumber(null); // 0
toNumber(undefined); // NaN
toNumber(1); // 1
toNumber("123aa"); // NaN
toNumber({}); // NaN
toNumber(true); // 1
当使用+操作null、undefined、number、string、object、boolean时是没有问题的
但如果使用+操作bigint类型数字或者symbol时会报错:
toNumber(10n);
toNumber(Symbol.for("a"));
均会报如下错误:
此问题产生的原因也是兼容性问题,在ES5的数据类型中使用此方法转换为数字是没有问题的,但在ES6+的新数据类型中要注意此问题的产生。
3、字符串数组批量转为整数
var results = ["1", "2", "3"].map(parseInt);
console.log(results); // [ 1, NaN, NaN ]
以上代码执行完毕的结果为[1, NaN, NaN],这是为什么呢?
我们将此代码拆解开来:
["1", "2", "3"].map((val,index)=> parseInt(val,index))
// parseInt("1",0)
// parseInt("2",1)
// parseInt("3",2)
所以代码执行过程中相当于依次执行parseInt("1", 0)、parseInt("2", 1)、parseInt("3", 2)
parseInt可以接收第二个参数,用于指定低数(进制数)
- parseInt("1", 0),第二个参数为0,默认是不生效的,所以会当成10进制,最终结果为1
- parseInt("2", 1),第二个参数为1,1进制中是不可能出现2的,所以将字符串2转换为1进制时会变为NaN
- parseInt("3", 2),同理,2进制中是不可能出现3的,所以结果也会是NaN
4、if条件判断
比如,想判断obj上是否有name属性,如果有name属性则将obj的name属性值设置给result的name属性
const result = {};
// name存在
if(obj.name){
result.name = obj.name;
}
return result;
由于if 中的条件会进行布尔值转换,一旦obj的name属性值为0、null则均会判断为false,此时if条件内的代码将不会执行
会转换为false的值有:0、+0、-0、null、NaN、false、''(空字符串)、undefined
所以如果真想判断一个对象上是否存在某个属性,要使用Object.hasOwnProperty
5、宽松比较
console.log(null == 0); // false
console.log("0" == false); // true
宽松比较规律如下
- NaN:NaN与任何类型的值均不相等,包括其本身
- bigInt、Symbol:首先会比较是不是同类型,不是同类型直接不相等,然后再比较值是否相等
- null、undefined:null只会与null或者undefined相等;undefined只会与undefined与null相等
- 布尔类型和其他类型做相等比较时:布尔值会转换成数字再与其他类型值做比较
- 数字类型和字符串类型做相等比较时:字符串会转成数字然后做比较
- 对象类型和原始类型做相等比较时:对象类型会转成原始类型然后做比较
基于以上几点规律,来看上段代码:
- 由于在宽松比较中null只与null或undefined相等,所以会输出false
- 布尔类型在于其他类型值比较时会转为数字,所以false会转为0,然后相当于"0" == 0,数字与字符串比较时,字符串会转为数字,所以 0 ==0会输出true
Tip: 需要注意的是,以上几点规律适用于宽松比较,比如console.log(null == 0)会输出false,但console.log(null >= 0)会输出true
- 这是因为在
相等操作符中null与undefined不会转换为数字,所以null == 0为false - 而在
关系运算符中null、undefined会被Number()转换为数字,其中Number(null)为0、Number(undefined)为NaN,所以这也就是为什么null >= 0为true,undefined >=0 为false