判断是否是object
代码:
function isObject(obj){
if(typeof obj=='object'){
return true;
}
return false;
}
console.log(isObject(null));
- 第一个问题: 上面的方法有什么问题?
obj为null时,typeof obj=='object'返回true.
- 第二个问题:为什么
typeof null返回的值是object?
简单来说,typeof null的结果为Object的原因是一个bug。在 javascript 的最初版本中,使用的 32位系统,js为了性能优化,使用低位来存储变量的类型信息。
在判断数据类型时,是根据机器码低位标识来判断的,而null的机器码标识为全0,而对象的机器码低位标识为000。所以typeof null的结果被误判为Object。
- 第三个问题: 为什么不修复这个问题?
为了兼容以前的代码。
一元运算符+转为数字
function toNumber(val) {
const result = +val;
return result
}
// 传统数据类型
toNumber(null) // NaN
toNumber(undefined) // NaN
toNumber(1) // 1
toNumber("123cc") // NaN
toNumber("123") // 123
toNumber({}) // NaN
toNumber({a:2}) // NaN
toNumber(true) // 1
// ES6的 bigInt和Symbol
toNumber(10n) //throw error :`Cannot convert a BigInt value to a number`
toNumber(Symbol.for("a")) //throw error:' Cannot convert a Symbol value to a number'
为什么会造成这样的现象?
兼容问题,es6之前的数据类型适用,es6中新添加的数据类型不适用。
位移转为数字
code:
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
可以看出当数超大时,带符号位位移和不带符号位位移得到的结果不一样。
为什么会造成这样的结果呢?
这是因为带符号位和不带符号位的二进制的处理不一样。
使用>>(带符号位位移)和 >>>(不带符号位位移)时:
- 先将十整数转为二进制数,
- 取二进制的前32位
- 无符号位(>>>):将二进制转为十进制; 有符号位(>>):分正负情况。正:直接转为十进制;负:先减一再取反再转为十进制。
所以造成该问题的本质原因是:32位的有符号位移和无符号位移.
字符串批量转换为整数
var results = ["1", "2", "3"].map(parseInt);
console.log(results); //[ 1, NaN, NaN ]
- 为什么结果不是[1,2,3]呢? 实际上进行了下面的操作。
["1", "2", "3"].map((val,index)=> parseInt(val,index))
// parseInt("1",0)
// parseInt("2",1)
// parseInt("3",2)
- parseInt第二个参数的取值范围?
2~36
parseInt(string, radix):其中,string 是要解析的字符串,radix 是一个可选参数,表示解析时使用的基数(即进制)。
如果 radix 参数未指定或为 0,则 parseInt() 会尝试根据 string 的前缀自动判断基数。如果 string 以 "0x" 或 "0X" 开头,则基数为 16(十六进制);如果 string 以 "0" 开头,则基数为 8(八进制);否则基数为 10(十进制)。
如果指定了 radix 参数,则 parseInt() 会将 string 解析为指定进制的整数。radix 的取值范围是 2 到 36。如果 string 不能被解析为指定进制的整数,则 parseInt() 返回 NaN。
if条件判断
const result = {};
// name存在
if(obj.name){
result.name = obj.name;
}
return result;
- 本质
是将obj.name转为boolean.
- 哪些值转为布尔值为false
false0和-00n和-0n(BigInt 类型的零)""(空字符串)nullundefinedNaN
宽松比较
console.log(null == 0)
console.log('0' == false)
console.log(null == null)
- 本质
隐式转换
- 宽松比较的规律
typeof 性能比 instanceof 性能高20倍?
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()));
在百万级时,是高2倍,所以可以放心使用instanceof.
null和undefined实现的机制完全不一样
// null和undefined
var print = console.log;
print(Object.getOwnPropertyDescriptor(global, 'null'))
print(Object.getOwnPropertyDescriptor(global, 'undefined'))
- getOwnPropertyDescriptor方法
Object.getOwnPropertyDescriptor(obj, prop)其中,obj 表示包含属性的对象,prop 表示要获取描述符的属性名。
Object.getOwnPropertyDescriptor() 是 JavaScript 内置函数之一,它用于获取对象上指定属性的描述符。描述符包含属性的值、是否可写、是否可枚举以及是否可配置等信息。
Object.getOwnPropertyDescriptor() 的语法如下:
javascriptCopy code
Object.getOwnPropertyDescriptor(obj, prop)
其中,obj 表示包含属性的对象,prop 表示要获取描述符的属性名。
存在,函数返回一个包含以下属性的对象:
value:属性的值,如果属性存在的话。writable:一个布尔值,表示属性是否可写。enumerable:一个布尔值,表示属性是否可枚举。configurable:一个布尔值,表示属性是否可配置。
如果属性不存在,函数返回 undefined。