深拷贝:
将一个对象从内存中完整地拷贝出来一份给目标对象,并从堆内存中开辟一个全新的空间存放新对象,且新对象的修改并不会改变原对象,二者实现真正的分离。
实现深拷贝的方式:
①JSON.stringify()
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
缺点:
①会忽略 undefined | ②会忽略 symbol | ③不能序列化函数 |
---|---|---|
④无法拷贝不可枚举的属性 | ⑤无法拷贝对象的原型链 | ⑥拷贝 RegExp 引用类型会变成空对象 |
⑦拷贝 Date 引用类型会变成字符串 | ⑧对象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的结果会变成 null | ⑨不能解决循环引用的对象,即对象成环 obj[key] = obj) |
②手写实现
function deepClone(obj, Map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
if (Map.has(obj)) return Map.get(obj)
let copyObj = new obj.constructor()
Map.set(obj, copyObj) //放入缓存中
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copyObj[key] = deepClone(obj[key], Map)
}
}
return copyObj
}
二、数据类型的判断
①typeof
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object []数组的数据类型在 typeof 中被解释为 object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object null 的数据类型被 typeof 解释为 object
优缺点
优点 | 缺点 |
---|---|
①typeof 对于原始类型来说,除了 null 都可以显示正确的类型 | ①typeof 对于对象来说,除了函数都会显示 object |
②instanceof
原理:因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
缺点 | ①可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型 |
---|
③constructor
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
缺点 | ①创建一个对象,更改它的原型,constructor就会变得不可靠了 |
---|
④Object.prototype.toString.call()
原理:toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息。
Object.prototype.toString({}) // "[object Object]"
Object.prototype.toString.call({}) // 同上结果,加上call也ok
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('1') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([]) //"[object Array]"
Object.prototype.toString.call(document) //"[object HTMLDocument]"
Object.prototype.toString.call(window) //"[object Window]"
**总结:**判断数据类型通用方法:
function getType(obj){
let type = typeof obj;
if (type !== "object") {
return type;
}
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1'); // 注意正则中间有个空格
}
getType([]) // "Array" typeof []是object,因此toString返回
getType('123') // "string" typeof 直接返回
getType(window) // "Window" toString返回
getType(null) // "Null"首字母大写,typeof null是object,需toString来判断
getType(undefined) // "undefined" typeof 直接返回
getType() // "undefined" typeof 直接返回
getType(function(){}) // "function" typeof能判断,因此首字母小写
getType(/123/g) //"RegExp" toString返回