这个问题来自于在对koa源码的解析之中被再次提起。 源码的位置github.com/koajs/koa/b…
程序中需要从context,request,response模板中复制三个对象,并将其互相挂载起来。这里面用到了Object.create方法。
首先我们先盘一盘如果想达到对象复制都有哪几种办法
为什么我们要复制对象
首先我们看看为什么要复制变量,假设我们用字面量定义一个模板对象, 如果不复制,两个对象其实是引用的同一个对象实例。
const template = { data: 1, } const objectA = template template.data = 8 const objectB = template template.data = 9 console.log('objectA:',objectA) console.log('objectB:',objectB) // 运行结果 // objectA: { data: 9 } // objectB: { data: 9 } `121
方法一: 解构赋值
解构赋值其实就是利用解构的浅拷贝效应从而达到变量赋值的目的。当然既然是浅拷贝,深层就不行了。
const template = { data: 1, info: { b: 1 } } const objectA = {...template} objectA.data = 2 objectA.info.b = 8 const objectB = {...template} objectB.data = 3 objectB.info.b = 9 console.log('objectA:',objectA) console.log('objectB:',objectB) // 运行结果 // ============ // objectA: { data: 2, info: { b: 9 } } // objectB: { data: 3, info: { b: 9 } }
方法二: JSON.stringify & parse
为了解决深层拷贝问题我们可以考虑将源对象转换为字符串,再转换为新对象。
const template = { data: 1, info: { b: 1 } } const objectA = JSON.parse(JSON.stringify(template)) objectA.data = 2 objectA.info.b = 8 const objectB = JSON.parse(JSON.stringify(template)) objectB.data = 3 objectB.info.b = 9 console.log('objectA:',objectA) console.log('objectB:',objectB) // 运行结果 // ============ // objectA: { data: 2, info: { b: 8 } } // objectB: { data: 3, info: { b: 9 } }
方法三:Object.create
看似问题解决了 但是如果我们如果使用了getter和setter方法的话,而且里面又有一个字面量中没有描述的对象,问题就出现了,由于上面两种复制方式都会调用到变量的getter方法,这个时候就会报错。
const template = { data: 1, info: { b: 1 }, get c() { return this.xxx.data } }
实际上Object.create是做了以对象为原型进行了继承操作 getter/setter方法可以继承过来 但是并不能完成深层copy
const template = { data: 1, info: { b: 1 }, get c() { return this.xxx.data } } const objectA = Object.create(template) objectA.data = 2 objectA.info.b = 8 const objectB = Object.create(template) objectB.data = 3 objectB.info.b = 9 console.log('objectA:',objectA.__proto__) console.log('objectA的原型:',objectA.__proto__) console.log('objectA.data:',objectA.data) console.log('objectA.info.b:',objectA.info.b) console.log('objectB的原型:',objectB.__proto__) console.log('objectB.data:',objectB.data) console.log('objectB.info.b:',objectB.info.b) // 运行结果 // ============ // objectA: { data: 1, info: { b: 9 }, c: [Getter] } // objectA的原型: { data: 1, info: { b: 9 }, c: [Getter] } // objectA.data: 2 // objectA.info.b: 9 // objectB的原型: { data: 1, info: { b: 9 }, c: [Getter] } // objectB.data: 3 // objectB.info.b: 9 // 并没有深拷贝
归纳总结
赋值 | 浅拷贝 | 深拷贝 | getter/setter |
解构赋值 | √ | ||
JSON.stringify | √ | √ | |
Object.create | √ | √ |
最后我们就知道了在koa源码里面 主要就是要继承原型中的getter/setter所以选择了Object.create方法