美文网首页
浅拷贝没那么简单

浅拷贝没那么简单

作者: 流光号船长 | 来源:发表于2018-04-24 19:03 被阅读0次

拷贝的分类

  1. 浅拷贝: 只能对基本类型的值拷贝,如果所要拷贝的对象的某个属性的值是对象的话,那么目标对象拷贝得到的是这个对象的引用。
  2. 深拷贝: 和原对象一样的属性和原型,相互之间互不影响(不一样的内存地址)

在写这篇博客之前,看了很多博客实现的浅拷贝,发现大家实现的方法或多或少都有些不足,今天就把这些坑说一说。

  • 我需不需要拷贝原对象的原型?
  • 对象中有以Symbol为属性名的属性我需不需要拷贝?
  • 对象中有不可遍历的属性,我要不要拷贝?

逐个属性遍历(ES6之前)

通过逐个遍历对象的属性并复制,来实现浅拷贝,但这种方法有两个弊端:

  • 不可遍历以symbol为属性名的属性
  • 不可遍历不可枚举属性

Symbol 作为属性名,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。

// 浅拷贝函数
function shallowClone(obj) {
    const newObj = {};
    for (let i in obj) {
        newObj[i] = obj[i];
    }
    return newObj;
}
// 被拷贝对象
const obj1 = {
    a: 1,
    b: 'hellow world',
    c: true,
    d: Symbol('symbol'),
    [Symbol('e')]: 'e',
}
Object.defineProperty(obj1, 'f', {
  value: 'f',
  enumerable: false,
}) // 添加不可枚举属性
const obj2 = shallowClone(obj1);

obj2 // {a: 1, b: "hellow world", c: true, d: Symbol(symbol)}

所拷贝的对象并没有以symbol为属性名的属性,也不能拷贝不可遍历的属性,所以这种方法并不是最佳实践。

ES6下的浅拷贝

ES6新增了许多操作对象或者遍历对象的API,下面分别测试下能不能实现完美的浅拷贝

Object.assign()

通过和空对象合并来实现浅拷贝:

const obj1 = {
    a: 1,
    b: 'hellow world',
    c: true,
    d: Symbol('symbol'),
    [Symbol('e')]: 'e',
}
const obj2 = Object.assign({},obj1) // ES6新扩展: Object.assign() 
obj2 // {a: 1, b: "hellow world", c: true, d: Symbol(symbol), Symbol(e): "e"}

发现可以实现对以symbol为属性名的属性的拷贝,但是对于不可枚举属性Object.assign()还是无能为力。
我们在MDN上发现Object.assign()不可以遍历出不可枚举属性:

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

解构赋值+rest

那我们看看更加优雅的解构赋值+rest能不能实现完美的浅克隆通过ES6的解构赋值可以更简单的实现浅拷贝:

const obj1 = {
    a: 1,
    b: 'hellow world',
    c: true,
    d: Symbol('symbol'),
    [Symbol('e')]: 'e',
}
Object.defineProperty(obj1, 'f', {
  value: 'f',
  enumerable: false,
});
let { ...obj2 } = obj1
obj2 // {a: 1, b: "hellow world", c: true, d: Symbol(symbol), Symbol(e): "e"}

发现依然不能解决不可遍历属性的问题。

ES7下的浅拷贝

Object.getOwnPropertyDescriptors

Object.getOwnPropertyDescriptor() 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

Object.getOwnPropertyDescriptors方法可以配合Object.create方法实现浅拷贝

const shallowClone = (obj) => Object.create(
    Object.getPrototypeOf(obj),
    Object.getOwnPropertyDescriptors(obj)
);
const obj1 = {
    a: 1,
    b: 'hellow world',
    c: true,
    d: Symbol('symbol'),
    [Symbol('e')]: 'e',
}
Object.defineProperty(obj1, 'f', {
    value: 'f',
    enumerable: false,
});
const obj2 = shallowClone(obj1);

obj2 //{a: 1, b: "hellow world", c: true, d: Symbol(symbol), f: "f"}

基本上完美实现了对所有类型属性的拷贝,可以看见即使是浅拷贝,要踩得坑还是很多的。

相关文章

  • 浅拷贝没那么简单

    拷贝的分类 浅拷贝: 只能对基本类型的值拷贝,如果所要拷贝的对象的某个属性的值是对象的话,那么目标对象拷贝得到的是...

  • js浅拷贝深拷贝

    js浅拷贝,深拷贝的简单实现 基础数据 浅拷贝 深拷贝

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • 深浅拷贝理解

    先看最简单的赋值 (a=b) 浅拷贝 补充说明浅拷贝 如图 深拷贝

  • 认识js下的浅拷贝与深拷贝

    浅拷贝与深拷贝 首先深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象的。简单来说,浅拷贝只拷贝一...

  • iOS - copy 与 mutableCopy

    一说到拷贝,就不得不提浅拷贝和深拷贝。 何谓浅拷贝?何谓深拷贝? 往简单的说: 浅拷贝:拷贝地址。 深拷贝:拷贝内...

  • JS深浅拷贝常用方法

    浅拷贝: 浅拷贝出现原因 上述代码中,如果我们希望a和b的属性是独立的,那么最后结果显然不符期望,简单来说发生原因...

  • js浅拷贝、深拷贝

    前言 本文主要简单讲一下什么是浅拷贝、什么是深拷贝、深拷贝与浅拷贝的区别,以及怎么进行深拷贝和怎么进行浅拷贝。 一...

  • java中的深拷贝和浅拷贝

    简单记录一下java中的深拷贝和浅拷贝,深拷贝和浅拷贝只是针对对象而言的. 1 深拷贝代码 2 浅拷贝代码 3 测...

  • iOS-NSString strong copy mutable

    聊一聊NSString的strong copy mutableCopy。 简单概括一下深拷贝和浅拷贝。 浅拷贝: ...

网友评论

      本文标题:浅拷贝没那么简单

      本文链接:https://www.haomeiwen.com/subject/bewnhftx.html