JS数据类型有哪些
必要性:
这块知识很杂,但是又特别重要,我们拿到数据经常要做一些判断。而且在手写一些基本方法的时候必定会用到,比如数组常用方法,柯里化、深浅拷贝,call,apply,bind。因为别人在使用你的方法的时候会传入让你意想不到的数据类型,比如用数组调用call方法,所以在我们需要在这些方法针对不同的数据类型做判断。
JS数据类型
基本(原始)数据类型:Number String Boolean Undefined Null Bigint(ES6新加) Symbol(ES6新加)
引用数据类型:object(Function Array Object)
数据类型判断方法
1.typeof
除了Object,Array,Null会被判断为object,其他都正确,NaN会被判断为Number
2.instanceof
只能判断引用类型,基本类型判断不了!
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
console.log(function () {} instanceof Function); // true
console.log({} instanceof Object); // true
原理是顺着原型链查找,代码如下
function myInstanceOf(left, right) {
let proto1 = right.prototype;
let proto2 = Object.getPrototypeOf(left); //建议不要用__proto__
while (proto2) {
if (proto1 === proto2) {
return true;
}
proto2 = Object.getPrototypeOf(proto2);
}
return false;
}
let arr = [1, 2, 3];
let str = "123";
console.log(myInstanceOf(arr, Array));
console.log(myInstanceOf(str, Array));
console.log(myInstanceOf(str, Object));
console.log(myInstanceOf(arr, Object));`
3.constructor
利用隐式原型上的constructor属性,查找到它的构造函数,做判断。
`console.log((2).constructor === Number);`
存在的问题
构造函数的显式原型被重写,导致判断错误。
解释
constructor是构造函数原型对象上的属性,所以实例对象用这个属性的时候没有,就顺着原型链找,找到它的隐式原型上的constructor属性,从而指向它的构造函数。但是如果把构造函数的的prototype指向另外一个obj了,那么你实例对象的constrctor就找到obj了,但是obj还是一个实例对象啊,比如[1,2,3],你new Array()创建出来的 ! 然后在顺着arr原型链查找,找到Array.prototype,然后发现有constructor,Array判断正确,但是它其实是Fn的实例对象,不是Array的。判读错误。
4.Object.prototype.toString.call()
终极大Boss,啥都能判断正确,但是判断出来结构是下面这样,需要slice截取
[object Number]
手写深拷贝
学习完数据类型的判断,来手写一个完善的深拷贝吧!只能拷贝自身可枚举属性。
代码如下:
function deepClone(obj) {
if (obj === null) return obj;
if (typeof obj !== "object") return obj; //不是数组或对象也不是null
//数组或对象
let res = obj instanceof Array ? [] : {};
//不要用传统的for循环,对象没有length!,也不能用for-of,对象没有iterator
for (let item in obj) {
//item拿到索引
if (obj.hasOwnProperty(item)) {
if (typeof obj[item] !== "object" && obj[item] !== null) {
//如果里面不是对象和数组
res[item] = obj[item];
} else {
res[item] = deepClone(obj[item]); //递归考虑里面的嵌套数组
}
}
}
return res;
}
let arr = [1, 2, [2, 3, [4, 5, 6]]];
let obj1 = {
a: 1,
b: 2,
c: { d: 3 },
};
console.log(deepClone(arr));
console.log(deepClone(obj1));
console.log(deepClone(obj1) === obj1);
console.log(deepClone(arr) === arr);
补充:
其他深拷贝方法1:
JSON.parse(JSON.stringify(obj))
存在问题:函数,undefined,symbol会消失。
其他深拷贝方法2:
lodash库