- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在JavaScript中存在两大数据类型:基本类型、引用类型.
基本数据类型存放在栈中,是一段简单的数据段, 数据大小确定,内存空间大小可以分配 ,是直接按值存放的,可以 按值访问 .
引用数据类型存放在堆中,变量在栈中保存的是 指向堆内存的地址值 ,这个地址值指向对应的对象类型,访问堆内存中的对象是 通过地址值访问 的.
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝.
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址.
即浅拷贝是拷贝一层.
下面简单实现一个浅拷贝:
function shallowClone (obj) {
const newObj = {}
for (let prop in obj) {
if (obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop]
}
}
return newObj
}
在JavaScript中, 存在浅拷贝的现象 有:
Object.assign()
Array.prototype.slice()
Array.prototype.concat()
使用扩展运算符实现的复制
Object.assign() 。
var obj = {
age: 18,
nature: ['smart', 'good'],
names: {
name1: 'fx',
name2: 'xka'
},
love: function () {
console.log('fx is a great girl')
}
}
var newObj = Object.assign({}, fxObj)
slice() 。
const fxArr = ['One', 'Two', 'Three']
const fxArrs = fxArr.slice(0)
fxArrs[1] = 'love'
consloe.log(fxArr) // ['One', 'Two', 'Three']
consloe.log(fxArrs) // ['One', 'love', 'Three']
concat() 。
const fxArr = ['One', 'Two', 'Three']
const fxArrs = fxArr.concat()
fxArrs[1] = 'love'
consloe.log(fxArr) // ['One', 'Two', 'Three']
consloe.log(fxArrs) // ['One', 'love', 'Three']
扩展运算符 。
const fxArr = ['One', 'Two', 'Three']
const fxArrs = [...fxArr]
fxArrs[1] = 'love'
consloe.log(fxArr) // ['One', 'Two', 'Three']
consloe.log(fxArrs) // ['One', 'love', 'Three']
深拷贝开辟一个新的栈,两个对象相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性.
常见的深拷贝方式 有:
_.cloneDeep()
jQuery.extend()
JSON.stringify()
循环递归
_.cloneDeep() 。
const _ = require('lodash')
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: { 1, 2, 3 }
}
const obj2 = _.cloneDeep(obj1)
console.log(obj1.b.f === obj2.b.f) // false
jQuery.extend() 。
const $ = require('jquery')
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: { 1, 2, 3 }
}
const obj2 = $.extend(true, {}, obj1)
console.log(obj1.b.f === obj2.b.f) // false
JSON.stringify() 。
const obj = {
name: 'A',
name1: 'undefined',
name2: function () {},
name3: Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj1)) // 会忽略undefined、Symbol、函数
console.log(obj2) // { name: 'A' }
循环递归 。
function deepClone (obj, hash = new WeakMap()) {
if (obj === null) return obj // 如果是null或者undefined,就不进行拷贝操作
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// 可能是对象或者普通的值,如果是函数的话不需要深拷贝
if (typeof obj !== 'Object') return obj
// 如果是对象,就进行深拷贝
if (hash.get(obj)) return hash.get(obj)
let cloneObj = new obj.constructor()
// 找到的是所属类型原型上的constructor,而原型上的constructor指向的是当前类本身
hash.set(obj, cloneObj)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash)
}
}
return cloneObj
}
浅拷贝只复制内存地址,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象.
// 浅拷贝
const obj1 = {
name: 'init',
arr: [1, [2, 3], 4]
}
const obj3 = shallowClone(obj1) // 一个浅拷贝方法
obj3.name = 'update‘
obj3.arr[1] = [5, 6, 7] // 新旧对象还是共享同一块内存
console.log('obj1', obj1) // obj1 { name: 'init', arr: [1, [5, 6, 7], 4] }
console.log('obj3', obj3) // obj3 { name: 'update', arr: [1, [5, 6, 7], 4] }
深拷贝会另外创造一个一模一样的对象,新对象与原对象不共享内存,修改新对象不会改到原对象.
// 深拷贝
const obj1 = {
name: 'init',
arr: [1, [2, 3], 4]
}
const obj4 = deepClone(obj1) // 一个深拷贝方法
obj4.name = 'update‘
obj4.arr[1] = [5, 6, 7] // 新对象与原对象不共享内存
console.log('obj1', obj1) // obj1 { name: 'init', arr: [1, [2, 3], 4] }
console.log('obj4', obj4) // obj4 { name: 'update', arr: [1, [5, 6, 7], 4] }
当拷贝类型为引用类型时:
最后此篇关于浅拷贝与深拷贝的文章就讲到这里了,如果你想了解更多关于浅拷贝与深拷贝的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有一个基类和两个派生类,我需要将一个指向派生类对象的指针复制到另一个类中,就像示例一样。 class Base { public: Base(const Base& other); } cl
考虑 Container 类,它主要存储 Box 对象的 unique_ptr vector ,并可以对它们执行一些计算。 class Container { private: std::
引用是指保存的值为对象的地址。在 Python 语言中,一个变量保存的值除了基本类型保存的是值外,其它都是引用,因此对于它们的使用就需要小心一些。下面举个例子: 问题描述:已知一个列表,求生成一个
我正在尝试实现 Bron-Kerbosch 算法,这是一种用于查找派系的递归算法。我设法达到了一个点,它返回了正确数量的派系,但是当我打印它们时,它们不正确 - 添加了额外的节点。我在这里遗漏了什么明
在评估中,我选择了选项LINE I 上的运行时错误。没有未定义行为这样的选项,尽管我认为这是正确的选择。 我不确定,但我认为评估有误。我编译并运行了该程序,它确实打印了 3, 9, 0, 2, 1,
在函数签名中通过 const 值传递参数是否有任何好处(或相反,成本)? 所以: void foo( size_t nValue ) { // ... 对比 void foo( const s
我为 answer to another question 写了一个 OutputIterator .在这里: #include using namespace std; template clas
我有一个由第三方生成的 dll,它具有某种内部数据结构,将其大小限制为 X 个元素。 所以基本上,它有一个以 X 为限制的队列。 据我所知,DLL 是每个进程的,但是是否可以多次加载 DLL?也许每个
假设我有以下两个数据结构: std::vector all_items; std::set bad_items; all_items vector 包含所有已知项和 bad_items vector
如何在不渲染 CGImage 的情况下从另一个 CIImage 复制一个 CIImage 最佳答案 CIImage *copiedImage = [originalImage copy]; 正如您在
我有一个名为 UINode 的 GUI,我想创建一个拷贝并只更改一些内容。该项目由 3 个基本线程组成。 PingThread、RosThread 和 GuiThread。我试图复制粘贴项目文件夹并将
Qt 新手。如果这个问题太幼稚,请多多包涵。在 Windows 操作系统环境中,我有 Qt 对话框框架应用程序,它具有“重复”- 按钮。在同一目录中,有 Qt 应用程序 - (一个带有关闭按钮的对话框
我正在尝试创建一个函数来复制我的卡片结构。我只需复制 cvalue 即可轻松开始。然而,我的 cvalue 没有复制,当应该读取 1000 时它仍然读取 5。 #include #include
string str1("someString"); string str2 = string(str1);//how many copies are made here //copy2 =
我希望了解 boost::bind 执行何种函数对象的内部拷贝。由于这些对象的构造函数似乎没有被调用,我推测这是一种“非常浅的复制”,所以我引入了动态内存分配来产生一些错误。但是,下面代码的运行时输出
我正在查看 http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c22-make-default-operations-consis
下面的类方法Augmented3dPoint::getWorldPoint()返回对其成员的引用 cv::Point3f world_point; class Augmented3dPoint { p
我需要通过 MyClass2 将用户定义的 lambda 传递给 MyClass1。我想确保只有一步,没有拷贝。下面的代码实现了吗?有没有更好的方法来做到这一点(比如使用编译器完成的隐式移动)? 注意
在我的数据库访问代码中,我想写一个方法: variant_t GetQueryRows (...) 我想这样调用它: const variant_t result = GetQueryRows (..
我有一个包含引用的类,例如: class A { A(B &b) : b(b) {} // constructor B &b; } 有时b必须是只读的,有时是可写的。当我创建一个 const A
我是一名优秀的程序员,十分优秀!