课程名称: 破解JavaScript高级玩法,成为精通 JS 的原生专家
课程章节: 2-1 数据类型的陷阱,从表象看本质!
课程讲师: Cloud
课程内容:
判断是不是Object
function isObject(obj) { if(typeof obj === 'object') { return true; } return true }
第一个问题: 上面的方法有什么问题?
typeof null 也是 ‘object’
第二个问题:为什么 typeof null 返回的值是 “object” ?
追溯 javascript 第一个版本,这个版本中单个值在栈中占用32个位的存储单元,又分为两个部分,一个标记位,一个表示其它的数据,这个时候它有只有5中数据类型:
// 类型标记位 // 000: object // 001: integer // 010: double // 100: string // 110: boolean而 null 在机器码中的指针从0~31 位全都是0,自然标记为也是 0,而标记为是0,typeof 返回的也是0了。
当然现在的v8引擎不是这样判断数据的,它是一个历史包袱
第三个问题: 为什么不修复这个问题?
因为兼容性的问题,如果一改很多程序就运行不起来了,所以不得不做妥协
一元运算符+转为数字
function toNumber(val) { return +val; }
上面的代码在 es5中是完全没有问题的,但在 es6 引入的新的数据类型中是会出错,如下:
const print = console.log; function toNumber(val) { const result = +val; print(result); return result; } // 传统数据类型 toNumber(null); // 0 toNumber(undefined); // NaN toNumber(1); // 1 toNumber("123aa"); // NaN toNumber({}); // NaN toNumber(true); // 1 // ES6的 bigInt和Symbol // toNumber(10n) // 错误 // toNumber(Symbol.for("a")) // 错误
所以我们代码要考虑向后兼容
位移转为数字
// 有符号位移 function toNumber(val) { return val >> 0 } // 无符号位移 function toNumber2(val) { return val >>> 0 }
代码有什么问题?
上面代码问题为 数值较大是 会出现莫名的数字
本质是 32位的有符号位移和无符号位移
解析:
const print = console.log; function toNumber(val) { const result = val >> 0; print(result); return result; } function toNumber2(val) { const result = val >>> 0; print(result); return result; } // toNumber(null); // 0 // toNumber({}); // 0 // toNumber("10x"); // 0 // toNumber("10"); // 10 // 超大的数 toNumber(Number.MAX_SAFE_INTEGER); // -1 toNumber2(Number.MAX_SAFE_INTEGER); // 4294967295 // toNumber2(Number.MAX_SAFE_INTEGER) => 4294967295 var val = Number.MAX_SAFE_INTEGER.toString(2); // 11111111111111111111111111111111111111111111111111111 var val1 = val.substring(0, 32); // 11111111111111111111111111111111 var num = parseInt(val1, 2); // 4294967295 // console.log(num) // toNumber(Number.MAX_SAFE_INTEGER) => -1 // 有符号数字,最高位为符号位。 // 十进制变二进制:原码 => 反码 加一(补码) // 二进制变十进制:减一 =>反码 = 原码。 var val = Number.MAX_SAFE_INTEGER.toString(2); // 11111111111111111111111111111111111111111111111111111 var val1 = val.substring(0, 32) - // 11111111111111111111111111111111 // 减1 // 11111111111111111111111111111110 // 取反, // 00000000000000000000000000000001 = 1 // 因为其最高位1是负数 1;
字符串批量转换为整数
const arr = ["1","2","3"] arr.map(parseInt)
问题1:结果是多少?
结果为 [ 1, NaN, NaN ]
上面代码翻译如下:
["1", "2", "3"].map((val, index) => parseInt(val, index)); // parseInt("1",0) // 这个0是没有生效的所以默认为 10进制 // parseInt("2",1) // 这个是1进制,但结果是为 2,1进制是不能出现2的,所以返回 NaN // parseInt("3",2) // 这个是2进制,但结果是为 3,2进制是不能出现3的,所以返回 NaN
问题2:parseInt第二个参数的取值范围
范围为 2~36 的整数
if条件判断
const result = {} //name存在 if(result.name) { result.name = obj.name } return result;
上面的代码是否能进入if
不能 因为对象上没有name,返回 undefined,undefined在if条件中会转为boolean值,undefined转boolean为false
这里推荐使用 Object.hasOwnProperty() 进行判断对象上是否存在某个属性
问题:那些值转为布尔值为false
null、undefined、’’、false、(±)0、NaN
宽松比较
null == 0 // false '0' == false // true
本质:隐式转换
隐式转换七大法则(规律)
NaN
它和任何人都不能包括,包括它自己
bigInt,Symbol
首先比较是不是同类型,如果不是就不相等
null、undefined
null只会和null或undefined相等,undefined也是一样
布尔类型(boolean)和其它类型的相等比较
布尔类型(boolean)会转为数字
数字类型(Number)和 字符串类型(String)的相等比较
字符串(String)会转为数字
对象类型({})和 原始类型 的相等比较
对象会转为原始数据类型
对象和对象相等比较
比两个对象的引用是否同一个地址
其它
typeof 性能比 instanceof 性能高20倍?
千万级别的时候性能相差 1~2倍
// instanceOf 性能 var count = 10000000; var func = function () {}; var startTime = new Date(); console.log(typeof func === "function"); for (var j = 0; j < count; j++) { typeof func === "function"; } console.log( '[typeof func === "function"] ' + (new Date().getTime() - startTime.getTime()) ); /* ---------- */ startTime = new Date(); console.log(func instanceof Function); for (var k = 0; k < count; k++) { func instanceof Function; } console.log( "[func instanceof Function] " + (new Date().getTime() - startTime.getTime()) );
null 和 undefined实现机制完全不一样
null 是属于关键字
undefined 是属于一个词,变量
代码测试:
// null和undefined var print = console.log; print("null=》", Object.getOwnPropertyDescriptor(global, "null")); print("undefined=》", Object.getOwnPropertyDescriptor(global, "undefined"));上面代码运行后可以看见,null 是没有值的,undefined有描述信息。
由此可见 null 是关键字,undefined是一个值
判断是不是数字,NaN
课程收获:
对js数据类型有了深刻的理解