精华内容
下载资源
问答
  • JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型。基本数据类型包括Number、Boolean、String、Null、String、Symbol(ES6 新增),而复杂数据类型包括Object,而所有其他引用类型(Array、...
  • js中如何复制一个对象,例如如下一个js对象。 如果知道这个对象的所有属性自然就可以重新new一个,然后对每个属性赋值,就可以做到,但如果不知道呢?如何创建一个内容相同 的对象呢? 代码如下: var obj={ colkey...
  • oldObj是一个对象,而不是值 例如var newObj=oldObj; 如果想oldObj改变的时候不影响到newObj; 可以这样写一个函数 代码如下: function clone(myObj){ if(typeof(myObj) != ‘object’) return myObj; if(myObj == ...
  • JS复制对象

    万次阅读 2019-01-16 16:53:24
    在这篇文章中,我将会讲到几种在JS复制对象的方式,我们将会关注到浅复制和深复制。 在开始之前,值得一提的是一些基础知识:JS中的对象只是对内存中某个位置的引用。这些引用是可以更改的。即...

    原文地址:Copying objects in Javascript, 原文作者:Victor Parmar
    渣翻译,有英文阅读能力的可以去原网址阅读,正文部分的括号内是译者的尝试补充说明
    自豪地采用谷歌翻译

    在这篇文章中,我将会讲到几种在JS中复制对象的方式,我们将会关注到浅复制和深复制。
    在开始之前,值得一提的是一些基础知识:JS中的对象只是对内存中某个位置的引用。这些引用是可以更改的。即他们可以被重新分配。从而,简单的复制引用的操作在结果上仅仅是将两个引用指向了内存中的同一位置。

    var foo = {
      a: 'abc'
    }
    console.log(foo.a) // abc
    
    var bar = foo
    console.log(bar.a) // abc
    
    foo.a = 'yo foo'
    console.log(foo.a) // yo foo
    console.log(bar.a) // yo foo
    
    bar.a = 'whatup bar?'
    console.log(foo.a) // whatup bar?
    console.log(bar.a) // whatup bar?
    

    正如你从上面例子中看到的,foo和bar都反映了同一个对象的变化。从而,在JS中复制对象需要小心,具体取决于您的用例。

    浅复制

    如果你的对象的属性的类型仅仅只是值类型(译者注:基本类型)的。你可以使用扩展运算符语法或者Object.assign(...)

    var obj = { foo: 'foo', bar: 'bar' }
    var copy = { ...obj } // Object { foo: 'foo', bar: 'bar' }
    
    var obj = { foo: 'foo', bar: 'bar' }
    var copy = Object.assign({}, obj) // Object { foo: 'foo', bar: 'bar' }
    

    请注意,上述两种方法都可用于将属性值从多个源对象复制到目标对象:

    var obj1 = { foo: 'foo' }
    var obj2 = { bar: 'bar' }
    
    var copySpread = { ...obj1, ...obj2 } // Object { foo: 'foo', bar: 'bar' }
    var copyAssign = Object.assign({}, obj1, obj2) // Object { foo: 'foo', bar: 'bar' }
    

    事实上,上述方法的问题在于对象的属性如果是一个对象,则只会复制该属性对象在内存中的引用。即它相当于var bar = foo,如同第一个代码例子:

    var foo = { a: 0, b: { c: 0 } }
    var copy = { ...foo }
    
    copy.a = 1
    copyb.c. = 2
    
    console.dir(foo) // { a: 0, b: { c: 2 } }
    console.dir(copy) // { a: 0, b: { c: 2 } }
    

    深复制(有缺陷)

    为了对对象进行深复制操作,一个潜在的解决方案是序列化对象为一个字符串,然后反序列化,生成一个新对象:

    var obj = { a: 0, b: { c: 0 } }
    var copy = JSON.parse(JSON.stringify(obj))
    

    不幸的是,这个方法仅仅适用于当源对象包含可序列化的值类型并且没有循环引用的情况。不能序列化的值的类型,比如Date对象,即使它在字符串化上以ISO格式打印。JSON.parse仅仅会将它解释为一个字符串,而不是Date对象。

    深复制(更少的缺陷)

    对于更复杂的对象,可以使用更新的HTML5structured clone克隆算法。不幸的是,在撰写本文时,它仍局限于某些内置类型,但它支持的内容类型比JSON.parse更多。比如:DateRegExpMapSetBlobFileListImageData、稀疏和类型化数组。它还在克隆对象中保留了引用关系。允许它支持不适用于上述序列化方法的循环和递归结构。

    当前还没有直接调用结构化克隆算法的方法,但一些新的浏览器特性可以被用来间接使用这个方法。从而,我们会得到一些可能用于深度复制对象的变通方法

    使用 MessageChannel:这背后的想法是利用MessageChannel通信功能使用的序列化算法。这个功能是基于事件的,因此获取克隆结果是一个异步的操作。

    class StructruedCloner {
      constructor() {
        this.pendingClones_ = new Map()
        this.nextKey_ = 0
        
        const channel = new MessageChannel()
        this.inPort_ = channle.port1
        this.outPort_ = channel.port2
        
        this.outPort_.onmessage = ({data: {key, value}}) => {
          const resolve = this.pendingClones_.get(key)
          resolve(value)
          this.pendingClones_.delete(key)
        }
        this.outPort_.start()
      }
      
      cloneAsync(value) {
        return new Promise(resolve => {
          const key = this.nextKey_++
          this.pendingClones_.set(key, resolve)
          this.inPort_.postMessage({key, value})
        })
      }
    }
    
    const structuredCloneAsync = window.structuredCloneAsync = 
          StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner)
    
    const main = async () => {
      const original = { date: new Date(), number: Math.random() } // 译者注释:添加一些JSON方法不能解释的对象
      original.self = original // 译者注释:添加循环引用
      
      const clone = await structuredCloneAsync(original)
      
      // 不同的对象
      console.assert(original !== clone)
      console.assert(original.date !== clone.date)
      
      // 循环
      console.assert(original.self === original)
      console.assert(clone.self === clone)
      
      // 等价值
      console.assert(original.number === clone.number)
      console.assert(Number(original.date) === Number(clone.date))
      
      console.log('Assertions complete.')
    }
    
    main()
    

    使用historyAPIhistory.pushState()history.replaceState()两个方法会创建它们第一个参数的结构化对象。注意这个方法是同步的,操纵浏览器历史记录不是一个快速的操作并且反复调用此方法可能导致浏览器无响应。

    const structureClone = obj => {
      const oldState = history.state
      history.replaceState(obj.null)
      const clonedObj = history.state
      history.replaceState(oldState, null)
      return clonedObj
    }
    

    使用notificationAPI:当创建一个新的提醒(译者注:notification),构造函数会从它所关联的数据中创建一份结构化的克隆副本。注意,这么做浏览器会尝试将提醒显示给用户。但是这将会静默失败。除非应用已经请求到显示提醒的权限。万一权限存在,提醒会立即关闭。

    const structuredClone = obj => {
      const n = new Notification('', {data: obj, silent: true})
      n.onshow = n.close.bind(n)
      return n.data
    }
    

    在NodeJS中进行深复制

    在NodeJS的8.0.0版本中,它提供了一个序列化的API,它是兼容结构化克隆的。注意:这个API在本文撰写时(译者注:原文发表于2018.11.1)还是标记为实验性的:

    const v8 = require('v8')
    const buf = v8.serialize({a: 'foo', b: new Date()})
    const cloned = v8.deserialize(buf)
    cloned.b.getMonth()
    

    对于版本低于8.0.0或者更稳定的实现,一种方法是:可以使用lodashcloneDeep方法。该方法也基于结构化克隆算法

    结论

    总而言之,在JS中复制对象最佳的算法是严重依赖于你所复制对象的上下文和类型的。而lodash是通用深复制函数最安全的选择。也许你会给出更高效的实现呢。下面是一个对Date对象也起效的深复制的函数:

    function deepClone(obj) {
      var copy
      
      // 处理3种基础类型,和null、undefined
      if (obj === null || typeof obj !== 'object') return obj
      
      // 处理日期
      if (obj instanceof Date) {
        copy = new Date()
        copy.setTime(obj.getTime())
        return copy
      }
      
      // 处理数组
      if (Array instanceof Array) {
        copy = []
        for (var i = 0, len = obj.length; i < len; i++) {
          copy[i] = deepClone(obj[i])
        }
        return copy
      }
      
      // 处理函数
      if (obj instanceof Function) {
        copy = function() {
          return obj.apply(this, arguemnts)
        }
        return copy
      }
      
      // 处理对象
      if (obj instance Object) {
        copy = {}
        for (var attr in obj) {
          if (obj.hasOwnProperty(attr)) copy[attr] = deepClone(obj[attr])
        }
        return copy
      }
      
      throw new Error("Unable to copy obj as type isn't suported" + obj.constructor.name)
    }
    

    就个人而言,我期待能够在任何地方使用结构化克隆,最后让这个问题得到休息,快乐的克隆:)

    展开全文
  • JavaScript复制对象,不影响原对象

    千次阅读 2016-07-27 09:12:55
    //深度克隆 function deepClone(obj){ var result,oClass=isClass(obj); //确定result的类型 if(oClass==="Object"){ result={}; }else if(oClass==="Array"){ result=[]; }else{
    展开全文
  • js复制对象的属性值给新的对象

    万次阅读 2019-07-05 17:10:32
    我们有一个对象,且包含很多属性值和方法,但是我们想把它的内部属性复制给一个新的对象时,我们如何去做呢? 你可能会说直接 a = b就可以了。 no no no,这样两个对象其实指针指向的还是一个内存中的对象,当一个...

    我们有一个对象,且包含很多属性值和方法,但是我们想把它的内部属性复制给一个新的对象时,我们如何去做呢?

    你可能会说直接 a = b就可以了。

    no no no,这样两个对象其实指针指向的还是一个内存中的对象,当一个发生变化的时候,另一个也是变化的,这并不是我们想要的结果。

    那么,以三种方法来看看具体实现过程吧。

    如下,有一个circle对象,其中包括一个属性值,一个属性方法

    const circle = {
        radius: 1,
        draw() {
            console.log('draw');
        }
    };

    方法一:for in枚举对象

    通过循环初始对象,得到每一个key以及所对应的值,然后把它赋值给新的对象

    const newObj = {};
    
    for(let key in circle) {
        newObj[key] = circle[key];
    }

    方法二:对象合并方法:

    通过一个空对象和初始对象进行合并,赋值给新的对象

    const newObj = Object.assign({}, circle);

    方法三:es6扩展操作符

    通过扩展操作符,找到circle的每一个属性然后赋值给新的对象

    const newObj = { ...circle };

    结果:

    console.log(newObj)

    这样就完成了复制对象的值的操作。

    如有问题,请指出,接受批评。

    个人微信公众号:

    展开全文
  • Js复制对象/克隆对象 Js浅拷贝与深拷贝 浅拷贝和深拷贝的实现方法 前言 学习Js克隆一个对象,作为准备工作,需要理解Js中的数据类型和按值传递:Js中的数据类型和按值传递 浅拷贝最后两种方法不理解的话,可以读es5...

    Js复制对象/克隆对象 Js浅拷贝与深拷贝 浅拷贝和深拷贝的实现方法

    前言

    学习Js克隆一个对象,作为准备工作,需要理解Js中的数据类型和按值传递:Js中的数据类型和按值传递

    浅拷贝最后两种方法涉及到了继承和es5新特性中的call方法,可以读es5替换函数中的this的方法
    Js中的prototype、__proto__和constructor

    1. 浅拷贝

    1.1. 赋值和浅拷贝

    概念:

    浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是原始类型,拷贝的就是原始类型的值;如果属性是引用类型,拷贝的就是内存地址 。

    代码示例:

    var student={
        name:"Lily",
        age:15,
        sex:"女",
        friends:["Jack","Rose","Ben"]
    }
    var obj1=student;
    function clone(obj){
        var newObj={};
        for(var key in obj){
            newObj[key]=obj[key]
        }
        return newObj;
    }
    var obj2=clone(student)
    obj1.name="Tom";
    obj2.sex="男";
    obj2.friends[0]="Lilei";
    console.log(student.name) //Tom 
    console.log(student.age) //15
    console.log(student.friends) //["Lilei", "Rose", "Ben"]
    
    

    解析:

    i. 赋值:

    上面一段代码,student变量中保存着所创建对象的地址,obj1由赋值得到,根据按值传递,我们知道,obj1变量中保存的是student所存地址的副本,这两个地址指向同一个实例化对象,无论哪个对象发生改变,都会改变这个实例化对象,两个对象是联动的。

    ii. 浅拷贝:

    a. 重新创建一个新对象,逐个拷贝源对象的属性;

    b. 如果属性值是原始类型数据,拷贝的是原始类型的值的副本,原始类型的属性在新对象和源对象之间互不影响

    c. 如果属性值是引用类型数据,拷贝的是地址,如果其中一个的地址发生改变,就会影响到另外一个对象

    1.2. 浅拷贝的方法

    1.2.1. Object.assign()

    Object.assign()方法可以将源对象自身的可枚举属性(任意多个)拷贝给目标对象,然后返回目标对象

    var student={
        name:"Lily",
        age:15,
        sex:"女",
        friends:["Jack","Rose","Ben"]
    }
    var obj3=Object.assign({},student)
    console.log(obj3.name) //LilY
    
    1.2.2. 展开运算符…(Es6新特性)
    var student={
        name:"Lily",
        age:15,
        sex:"女",
        friends:["Jack","Rose","Ben"]
    }
    var obj4={...student}
    console.log(obj4.name) //LilY
    
    1.2.3. 强行调用数组的concat方法
    var student={
        name:"Lily",
        age:15,
        sex:"女",
        friends:["Jack","Rose","Ben"]
    }
    var obj5=Array.prototype.concat.call({},student)
    console.log(obj5) //{name: "Lily", age: 15, sex: "女", friends: Array(3)}  
    
    1.2.4. 强行调用数组的slice方法
    var student={
        name:"Lily",
        age:15,
        sex:"女",
        friends:["Jack","Rose","Ben"]
    }
    var obj6=Array.prototype.slice.call({},student)
    console.log(obj6) //{name: "Lily", age: 15, sex: "女", friends: Array(3)}   
    

    2.深拷贝

    概念

    深拷贝是将一个对象从内存中完整的拷贝出一份,从内存中开辟出一个新的区域来存放新对象,新对象跟原对象不共享内存,修改新对象不会影响原对象。

    2.1. 深拷贝与浅拷贝对比

    浅拷贝与深拷贝对比

    2.2. 深拷贝的实现方式

    2.2.1. JSON.parce(JSON.stringify())
    var student={
        name:"Lily",
        age:15,
        sex:"女",
        friends:["Jack","Rose","Ben"]
    }
    var obj7=JSON.parse(JSON.stringify(student))
    console.log(obj7) //{name: "Lily", age: 15, sex: "女", friends: Array(3)}
    obj7.friends[0]="Alice"
    console.log(student.friends[0]) //Jack 未影响源对象
    

    利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的内存空间,实现深拷贝。

    这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,JSON.stringify()方法在处理undefined、任意的函数以及 symbol 值时,作为非数组对象的属性值时会被忽略,作为数组对象中的属性值时,会被转换成 null。函数、undefined 被单独转换时,会返回 undefined。

    使用JSON.parce(JSON.stringify())克隆非数组对象,源对象中的方法被忽略
    var student={
        name:"Lily",
        age:15,
        sex:"女",
        friends:["Jack","Rose","Ben"],
        say:function(){
            console.log("hello")
        }
    }
    var obj7=JSON.parse(JSON.stringify(student))
    console.log(obj7) //{name: "Lily", age: 15, sex: "女", friends: Array(3)} say方法被忽略
    
    使用JSON.parce(JSON.stringify())克隆数组对象,源对象中的方法被转换成null
    var arr= [1,2,3,function say(){console.log("hello")}];
    var obj=JSON.parse(JSON.stringify(arr));
    console.log(arr,obj)
    

    数组中的函数会被转换为null
    这里列举了一些最常用情况下的弊端,其他方面的弊端可参考JSON.stringify()

    2.2.2.手写递归

    递归方法实现深度克隆原理:遍历对象直到最内层都是原始数据类型,然后再去复制,就是深度拷贝
    有种特殊情况需注意就是对象存在循环引用的情况,即对象的属性直接的引用了自身的情况,解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝。

    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;
    }
    let obj = { name: 1, address: { x: 100 } };
    obj.o = obj; // 对象存在循环引用的情况
    let d = deepClone(obj);
    obj.address.x = 200;
    console.log(d);
    
    解析:

    WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
    方法:

    WeakMap.prototype.delete(key)
    移除key的关联对象。执行后 WeakMap.prototype.has(key)返回false。
    WeakMap.prototype.get(key)
    返回key关联对象, 或者 undefined(没有key关联对象时)。
    WeakMap.prototype.has(key)
    根据是否有key关联对象返回一个Boolean值。
    WeakMap.prototype.set(key, value)
    在WeakMap中设置一组key关联对象,返回这个 WeakMap对象
    

    参考文章:
    如何写出一个惊艳面试官的深拷贝?(找不到文章的网址,只能贴个题目)
    一文读懂 javascript 深拷贝与浅拷贝(公众号推文,找不到文章的网址,只能贴个题目)
    WeakMap 对象

    展开全文
  • js复制 json对象

    2020-05-25 11:38:56
    3.对于json 复制, 要进行深复制,避免假复制(就是只是将地址指向同一对对象) 最好使用 JSON.parse(JSON.stringify(cloneData)) 4.lodash官网 npmi--savelodash main.js import_from"lodash"; 使用: letdata= _....
  • 对象和数组在赋值的时候都是引用传递,赋值的时候只是传递一个指针。
  • javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法前言在js中,数组和对象的复制如果使用=号来进行复制,那只是浅拷贝。如下图演示: 如上,arr的修改,会影响arr2的值,这显然在绝大多数情况下,并...
  • 下面小编就为大家带来一篇深入理解JavaScript中的对象复制(Object Clone)。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • JS对象分为两类,一类为基础类型对象,包括字符串(String),数值(Number),布尔值(Boolean),null(空),undefined(未定义)。另一类为合成对象,又叫做引用类型对象,包括数组(Array),对象(Object),函数(Function)...
  • js 复制数组以及对象

    千次阅读 2018-07-25 16:47:59
    先简单的说一下,关于我们的 = 号复制只是简单的浅拷贝。只是这样我在处理数组的时候,往往会影响原数组的值,这样就违背了我们的初始本意。 复制数组 1. for循环 var arr = [1,2,3,4,5]; var arr2 = copyArr(arr...
  • js对象连续结构复制

    2021-01-21 20:48:21
    Document
  • javaScript 复制对象

    千次阅读 2017-07-20 09:59:07
    对于javascript,相信大家都知道复制对象的方法,现在先贴出javascript的深拷贝 function deepCopy(p, c) { var c = c || {}; for (var i in p) { if(! p.hasOwnProperty(i)){ continue; }
  • js 对象复制

    万次阅读 2019-06-28 22:48:28
    //复制对象,复制是切断了引用关系 // var div=document.createElement("div"); //创建DOM元素 // Object.assign(div.style,{ //object样式的复制,把后面复制到前面 // }) var obj={ a:1, b:2, c:[1,2,3,4] ...
  • 现在要实现的是:原生js实现复制对象,扩展对象,类似jq中的extend()方法,具体实例如下: 现有3个对象字面量: var o1={hello:1,old:555}, o2 = { abc: 55555555, hello: 2, fun: function() { alert(111)...
  • js复制一个对象方法(克隆对象): 平时我们针对对象,还有其他基本类型常常使用复制,对于{}这种对象复制之后的只是多了一个引用,实际上还是指向原对象。 1.使用将转化为json字符串,然后再转回去。存在的...
  • js对象的拷贝(复制

    万次阅读 2016-12-21 16:04:53
    一、场景除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝将一个对象赋值给另外一个对象。var a = [1,2,3]; var b = a; b.push(4); // b中添加了一个4 alert(a); // a变成了[1,2,3...
  • function util(){ //复制 var clone = function (sObj) { if (typeof (sObj) != "object") { return sObj; } ...
  • https://www.cnblogs.com/showcase/p/10489636.html
  • 复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的constructor属性,是否对每一种数据类型(JavaScript常见的数据类型有String,Number,Boolean,Data,RegExp,Array,Funtion,Object)都实现正确的...
  • js如何复制一个对象

    万次阅读 2016-08-13 10:51:34
    js如何复制一个对象
  • https://blog.csdn.net/JaRiS_jade/article/details/83303363
  • VUE js复制对象 JSON

    千次阅读 2019-09-26 18:00:52
    let obj1 = '1'; let obj2 = ''; obj2 复制 obj1 的数据 Object.assign(obj2,obj1) 优点: obj1 与 obj2都是独立的对象,对obj2对象操作,对obj1没有影响
  • JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型。基本数据类型包括Number、Boolean、String、Null、String、Symbol(ES6 新增),而复杂数据类型包括Object,而所有其他引用类型(Array、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 190,792
精华内容 76,316
关键字:

js复制对象