We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
基本类型数据保存在在栈内存中 引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中。
为什么基本数据类型存在栈内存,引用数据类型存在堆内存?
基本类型赋值,系统会为新的变量在栈内存中分配一个新值,这个很好理解。 引用类型赋值,系统会为新的变量在栈内存中分配一个值,这个值仅仅是指向同一个对象的引用,和原对象指向的都是堆内存中的同一个对象。
var obj1 = new Object(); var obj2 = obj1; obj1.name = 'lucyStar'; console.log(obj2.name); // lucyStar
我们可以看到,obj1保存了一个对象的实例,这个值被赋值到 Obj2中。赋值操作完成后,两个变量实际引用的是同一个对象,改变了其中一个,会影响另外一个值。
什么是浅拷贝? 如果是对象类型,则只拷贝一层,如果对象的属性又是一个对象,那么此时拷贝的就是此属性的引用。
简单实现一个浅拷贝
function shadowCopy(obj) { const newObj = {}; for(let prop in obj) { if(obj.hasOwnProperty(prop)){ newObj[prop] = obj[prop]; } } return newObj; } const obj1 = { name: 'litterStar', a: { b: '1' } }; const obj2 = shadowCopy(obj1); obj2.name = 'lucyStar'; obj2.a.b = '2'; console.log(obj1); // { name: 'litterStar', a: { b: '2' } } console.log(obj2); // { name: 'lucyStar', a: { b: '2' } }
可以看到修改obj2的name 属性不会影响 obj1,但是修改 obj2的 a属性(是个对象)的 b,就会影响 obj1.a.b
obj2
name
obj1
使用下面这些函数得到的都是浅拷贝:
Object.assign
Array.prototype.slice()
Array.prototype.concat()
什么是深拷贝? 浅拷贝是只拷贝一层,深拷贝会拷贝所有的属性。深拷贝前后两个对象互不影响。
深拷贝的实现
JSON.parse(JSON.stringify())
JSON.parse(JSON.stringify())有存在以下问题:
let obj = { fun: function(){}, syb: Symbol('foo'), a: undefined, b: NaN, c: Infinity, reg : /^abc$/, date: new Date(), set: new Set([1, 2, 3, 4, 4]), map: new Map([ ['name', '张三'], ['title', 'Author'] ]), text:'aaa', } let cloneObj = JSON.parse(JSON.stringify(obj)); console.log(cloneObj); // 结果如下 { reg: {}, b: null, c: null, date: '2020-05-05T09:32:52.533Z', set: {}, map: {}, text: 'aaa' } console.log(typeof obj.date); // object console.log(typeof cloneObj.date); // string
可以看到
TypeError: Converting circular structure to JSON
const obj = { a: '111', } obj.b = obj; let cloneObj = JSON.parse(JSON.stringify(obj)); console.log(cloneObj); // TypeError: Converting circular structure to JSON
尝试自己写一个深拷贝,需要考虑下面这几种情况
obj.prop1 = obj
function deepCopy(originObj, map = new WeakMap()) { // 判断是否为基本数据类型 if(typeof originObj === 'object') { // 判断是都否为数组 const cloneObj = Array.isArray(originObj) ? [] : {}; // 判断是否为循环引用 if(map.get(originObj)) { return map.get(originObj); } map.set(originObj, cloneObj); for(const prop in originObj) { cloneObj[prop] = deepCopy(originObj[prop], map); } return cloneObj; } else { return originObj; } } const obj1 = { a: '111', } obj1.obj2 = obj1; const aa = deepCopy(obj1); console.log(aa); // { a: '111', obj2: [Circular] }
上面的实现存在一些问题
下面这一版本
function deepCopy(originObj, map = new WeakMap()) { // 判断是否为基本数据类型 if(isObject(originObj)) { // 判断是否为循环引用 if(map.get(originObj)) { return map.get(originObj); } // 判断是否为几种特殊需要处理的类型 let type = [Date, RegExp, Set, Map, WeakMap, WeakSet]; if(type.includes(originObj.constructor)) { return new originObj.constructor(originObj); } // 其他类型 let allDesc = Object.getOwnPropertyDescriptors(originObj); let cloneObj = Object.create(Object.getPrototypeOf(originObj), allDesc); // Reflect.ownKeys方法用于返回对象的所有属性,基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。 for(const prop of Reflect.ownKeys(originObj)) { cloneObj[prop] = isObject(originObj[prop]) && typeof originObj[prop] !== 'function' ? deepCopy(originObj[prop], map) : originObj[prop]; } return cloneObj; } else { return originObj; } } // 是否为引用类型 function isObject(obj) { return typeof obj === 'object' || typeof obj === 'function' && obj !== null; } let obj = { fun: function(){}, syb: Symbol('foo'), a: undefined, b: NaN, c: Infinity, reg : /^abc$/, date: new Date(), set: new Set([1, 2, 3, 4, 4]), map: new Map([ ['name', '张三'], ['title', 'Author'] ]), text:'aaa', } let cloneObj = deepCopy(obj); console.log(cloneObj);
打印的结果如下
{ fun: [Function: fun], syb: Symbol(foo), a: undefined, b: NaN, c: Infinity, reg: /^abc$/, date: 2020-05-05T13:57:14.904Z, set: Set { 1, 2, 3, 4 }, map: Map { 'name' => '张三', 'title' => 'Author' }, text: 'aaa' }
更多细节的实现可以参考 lodash 中的 cloneDeep方法。
备注:markdown 表格在 https://tableconvert.com/ 该网站生成,很方便。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
数据类型存储
基本类型数据保存在在栈内存中
引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中。
为什么基本数据类型存在栈内存,引用数据类型存在堆内存?
浅拷贝和赋值(=)的区别
基本类型赋值,系统会为新的变量在栈内存中分配一个新值,这个很好理解。
引用类型赋值,系统会为新的变量在栈内存中分配一个值,这个值仅仅是指向同一个对象的引用,和原对象指向的都是堆内存中的同一个对象。
我们可以看到,obj1保存了一个对象的实例,这个值被赋值到 Obj2中。赋值操作完成后,两个变量实际引用的是同一个对象,改变了其中一个,会影响另外一个值。
什么是浅拷贝?
如果是对象类型,则只拷贝一层,如果对象的属性又是一个对象,那么此时拷贝的就是此属性的引用。
简单实现一个浅拷贝
可以看到修改
obj2
的name
属性不会影响obj1
,但是修改obj2
的 a属性(是个对象)的 b,就会影响 obj1.a.b使用下面这些函数得到的都是浅拷贝:
Object.assign
Array.prototype.slice()
,Array.prototype.concat()
深拷贝
什么是深拷贝?
浅拷贝是只拷贝一层,深拷贝会拷贝所有的属性。深拷贝前后两个对象互不影响。
深拷贝的实现
JSON.parse(JSON.stringify())
JSON.parse(JSON.stringify())
有存在以下问题:可以看到
TypeError: Converting circular structure to JSON
尝试自己写一个深拷贝,需要考虑下面这几种情况
obj.prop1 = obj
上面的实现存在一些问题
下面这一版本
打印的结果如下
更多细节的实现可以参考 lodash 中的 cloneDeep方法。
总结
参考
The text was updated successfully, but these errors were encountered: