JavaScript:对象克隆的若干种方法

99 阅读2分钟

方法一:JSON

1、实现

let user = {
  name: 'Jerry',
  age: 30,
}
let newUser = JSON.parse(JSON.stringify(user))
console.log('user: ', user)
console.log('newUser: ', newUser)

image.png

2、优点

(1)简单粗暴:深拷贝

3、缺点

(1)忽略不可枚举的属性

let user = {
  name: 'Jerry',
  age: 30,
}
Object.defineProperty(user, 'name', {
  writable: true,
  enumerable: false,
  configurable: true,
})
let newUser = JSON.parse(JSON.stringify(user))
console.log('user: ', user)
console.log('newUser: ', newUser)

image.png (2)忽略symbol类型的属性

let user = {
  name: 'Jerry',
  age: 30,
  [Symbol('desc')]: '666'
}
let newUser = JSON.parse(JSON.stringify(user))
console.log('user: ', user)
console.log('newUser: ', newUser)

image.png (3)无法克隆原型

let person = {
  say() {}
}
let user = {
  name: 'Jerry',
  age: 30,
  __proto__: person
}
let newUser = JSON.parse(JSON.stringify(user))
console.log('user: ', user)
console.log('newUser: ', newUser)

image.png

方法二:for..in

1、实现

for (let key in user) { 
    clone[key] = user[key]
}

2、缺点

(1)不能复制属性的不可配置标志符

let user = {
  name: 'Jerry',
  age: 30
}
Object.defineProperty(user, 'name', {
  configurable: false
})

let newUser = {}
for (let key in user) {
  newUser[key] = user[key]
}

console.log('user: ', Object.getOwnPropertyDescriptors(user))
console.log('newUser: ', Object.getOwnPropertyDescriptors(newUser))

image.png

(2)忽略不可枚举的属性

let user = {
  name: 'Jerry',
  age: 30
}

Object.defineProperty(user, 'name', {
  enumerable: false,
})

let newUser = {}
for (let key in user) {
  newUser[key] = user[key]
}

console.log('user: ', Object.getOwnPropertyDescriptors(user))
console.log('newUser: ', Object.getOwnPropertyDescriptors(newUser))

image.png

(3)忽略symbol类型的属性

let user = {
  name: 'Jerry',
  age: 30,
  [Symbol('11')]: '666'
}

let newUser = {}
for (let key in user) {
  newUser[key] = user[key]
}

console.log('user: ', Object.getOwnPropertyDescriptors(user))
console.log('newUser: ', Object.getOwnPropertyDescriptors(newUser))

image.png

(4)浅拷贝

方法三:Object.assign

Object.assign() 方法将所有可枚举(Object.propertyIsEnumerable() 返回 true)的自有(Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。

1、实现

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source, {d: 5})
console.log(target); // {a: 1, b: 4, c: 5, d: 5}
console.log(returnedTarget); // {a: 1, b: 4, c: 5, d: 5}

2、缺点

(1)忽略不可枚举的属性

(2)忽略symbol类型的属性

(3)浅拷贝

方法四:Object.defineProperties和Object.getOwnPropertyDescriptors

1、实现

let user = {
  name: 'Jerry',
  age: 30,
  [Symbol('11')]: '666'
}

Object.defineProperties(user, {
  'name': {
    enumerable: false,
  },
  'age': {
    configurable: false
  }
})

const newUser = Object.defineProperties({}, Object.getOwnPropertyDescriptors(user))
console.log('user: ', Object.getOwnPropertyDescriptors(user))
console.log('newUser: ', Object.getOwnPropertyDescriptors(newUser))

image.png

2、优点

(1)能复制属性的不可配置标志符

(2)可复制不可枚举的属性

(3)可复制symbol类型的属性

3、缺点

(1)无法克隆原型

let user = {
  name: 'Jerry',
  age: 30,
}
let person = {
  say() {}
}
Object.setPrototypeOf(user, person)

const newUser = Object.defineProperties({}, Object.getOwnPropertyDescriptors(user))
console.log('user: ', user)
console.log('newUser: ', newUser)

image.png

(2)浅拷贝

方法五:Object.create

1、实现

let person = {
  say() {}
}
let user = {
  name: 'Jerry',
  age: 30,
  __proto__: person
}

const cloneUser = Object.create(Object.getPrototypeOf(user), Object.getOwnPropertyDescriptors(user))
console.log('user: ', user)
console.log('cloneUser: ', cloneUser)

image.png

2、优点

(1)能复制属性的不可配置标志符

(2)可复制不可枚举的属性

(3)可复制symbol类型的属性

(4)可复制原型对象

3、缺点

(1)浅拷贝

总结:此调用可以对 obj 进行真正准确地拷贝,包括所有的属性:可枚举和不可枚举的,数据属性和 setters/getters —— 包括所有内容,并带有正确的 [[Prototype]]。