简单类型 ( 值类型 ) 和复杂类型( 引用类型 )
简单类型又叫做基本数据类型或者值类型,名值存储于栈内存中,String、Number、Boolean、null、undefined、Symbol、BigInt(ES10)
复杂类型又叫做引用类型,( 名在栈内存中,值存在于堆内存中 ),在存储时变量中的存储仅仅是地址( 引用 ),通过 new 关键字创建的对象 ( 系统对象、 自定义对象 ),如Object、Function、 Array 、Date 等
堆和栈( JS 中没有堆栈概念 )
堆栈空间分配区别:
1.栈 ( 操作系统 ):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;简单数据类型存放到栈里面。
2.堆 ( 操作系统 ):存储复杂类型,一般由程序员负责分配释放,若程序猿不释放,由垃圾回收机制回收;复杂数据类型存放到堆里面
深拷贝和前拷贝 (面试题)
// 相对完美的本递归实现深拷贝
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null)
const deepClone = function (obj, hash = new WeakMap()) {
if (obj.constructor === Date)
return new Date(obj) // 日期对象直接返回一个新的日期对象
if (obj.constructor === RegExp)
return new RegExp(obj) //正则对象直接返回一个新的正则对象
//如果循环引用了就用 weakMap 来解决
if (hash.has(obj)) return hash.get(obj)
let allDesc = Object.getOwnPropertyDescriptors(obj)
//遍历传入参数所有键的特性
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
//继承原型链
hash.set(obj, cloneObj)
for (let key of Reflect.ownKeys(obj)) {
cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
}
return cloneObj
}
// 下面是验证代码
let obj = {
num: 0,
str: '',
boolean: true,
unf: undefined,
nul: null,
obj: { name: '我是一个对象', id: 1 },
arr: [0, 1, 2],
func: function () { console.log('我是一个函数') },
date: new Date(0),
reg: new RegExp('/我是一个正则/ig'),
[Symbol('1')]: 1,
};
//设置 "不可枚举属性"
Object.defineProperty(obj, 'innumerable', {
enumerable: false, value: '不可枚举属性'
}
);
obj = Object.create(obj, Object.getOwnPropertyDescriptors(obj))
// 设置loop成循环引用的属性
obj.loop = obj
let cloneObj = deepClone(obj)
cloneObj.arr.push(4)
console.log('obj', obj)
console.log('cloneObj', cloneObj)