判断是否是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
false
0
和-0
0n
和-0n
(BigInt 类型的零)""
(空字符串)null
undefined
NaN
宽松比较
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
。