番茄妹 發表於 2019-9-28 04:27:00

JavaScript 复制变量的三种方法

<p>参考:Copying Objects in JavaScript&nbsp;-&nbsp;Orinami Olatunji(@orinamio_) October 23, 2017</p>
<div data-article-type="post" data-article-id="23306" data-article-title="Copying Objects in JavaScript">&nbsp;</div>
<div id="react-bookmark" data-article-type="post" data-article-id="23306" data-article-title="Copying Objects in JavaScript">&nbsp;直接将一个变量赋给另一个变量时,系统并不会创造一个新的变量,而是将原变量的地址赋给了新变量名。举个栗子:</div>
<div data-article-type="post" data-article-id="23306" data-article-title="Copying Objects in JavaScript">
<div class="cnblogs_code">
<pre>let obj =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>1<span style="color: rgba(0, 0, 0, 1)">,
b: </span>2<span style="color: rgba(0, 0, 0, 1)">,
};
let copy </span>=<span style="color: rgba(0, 0, 0, 1)"> obj;

obj.a </span>= 5<span style="color: rgba(0, 0, 0, 1)">;
console.log(copy.a);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Result </span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> a = 5; // 更改obj的值,copy变量的值也会改变</span></pre>
</div>
<p>文章中提到了很多种办法,本文只选择了三种普遍的用法并分析了各自的优缺点,以及什么情况下使用哪种是最好的。</p>
</div>
<h1>1. 原生方法解决</h1>
<p>最简单的办法就是一个一个循环复制给新的变量。举栗:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> copy(mainObj) {
let objCopy </span>= {}; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> objCopy will store a copy of the mainObj</span>
<span style="color: rgba(0, 0, 0, 1)">let key;

</span><span style="color: rgba(0, 0, 255, 1)">for</span> (key <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> mainObj) {
    objCopy </span>= mainObj; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> copies each property to the objCopy object</span>
<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> objCopy;
}

const mainObj </span>=<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>2<span style="color: rgba(0, 0, 0, 1)">,
b: </span>5<span style="color: rgba(0, 0, 0, 1)">,
c: {
    x: </span>7<span style="color: rgba(0, 0, 0, 1)">,
    y: </span>4<span style="color: rgba(0, 0, 0, 1)">,
},
}

console.log(copy(mainObj));</span></pre>
</div>
<p>缺点:</p>
<p>1. objCopy 的Object.prototype 方法与mainObj 会不一样,通常情况下我们需要完全一样的副本时,这个办法并不适用。</p>
<p>2. 麻烦而且费时费事,代码无法重用。</p>
<p>3. 如果原来的变量中包含Object类型,复制时还是会把这个子变量的索引交给新的变量,并不是创建了新的副本。</p>
<h1>2. 深度复制</h1>
<p>利用JSON转换来复制变量。先将原先的变量转换为String然后再重新组装成JSON,这样会产生一个不一样的副本。</p>
<div class="cnblogs_code">
<pre>let obj =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>1<span style="color: rgba(0, 0, 0, 1)">,
b: {
    c: </span>2<span style="color: rgba(0, 0, 0, 1)">,
},
}

let newObj </span>=<span style="color: rgba(0, 0, 0, 1)"> JSON.parse(JSON.stringify(obj));

obj.b.c </span>= 20<span style="color: rgba(0, 0, 0, 1)">;
console.log(obj); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 1, b: { c: 20 } }</span>
console.log(newObj); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 1, b: { c: 2 } } (New Object Intact!)</span></pre>
</div>
<p>缺点:</p>
<p>1. 变量很多的时候非常耗时耗内存。</p>
<h1>3. 使用Object.assign()</h1>
<p>使用举例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> circular object</span>
let obj =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>'a'<span style="color: rgba(0, 0, 0, 1)">,
b: {
    c: </span>'c'<span style="color: rgba(0, 0, 0, 1)">,
    d: </span>'d'<span style="color: rgba(0, 0, 0, 1)">,
},
}

obj.c </span>=<span style="color: rgba(0, 0, 0, 1)"> obj.b;
obj.e </span>=<span style="color: rgba(0, 0, 0, 1)"> obj.a;
obj.b.c </span>=<span style="color: rgba(0, 0, 0, 1)"> obj.c;
obj.b.d </span>=<span style="color: rgba(0, 0, 0, 1)"> obj.b;
obj.b.e </span>=<span style="color: rgba(0, 0, 0, 1)"> obj.b.c;

let newObj2 </span>=<span style="color: rgba(0, 0, 0, 1)"> Object.assign({}, obj);

console.log(newObj2);</span></pre>
</div>
<p>可以把它封装成一个方法:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">// 封装成方法<br>//</span><span style="color: rgba(0, 128, 0, 1)"> 返回一个新的变量副本</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> get a copy of an object</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getNewObjectOf(src) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Object.assign({}, src);
}</span></pre>
</div>
<p>缺点:</p>
<p>1. 这个也是浅复制(仅复制顶层的属性,底层属性并不复制)。深层属性会同样返回索引,与原变量分享一个地址。(看下面栗子)</p>
<div class="cnblogs_code">
<pre>let obj =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>1<span style="color: rgba(0, 0, 0, 1)">,
b: {
    c: </span>2<span style="color: rgba(0, 0, 0, 1)">,
},
}
let newObj </span>=<span style="color: rgba(0, 0, 0, 1)"> Object.assign({}, obj);
console.log(newObj); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 1, b: { c: 2} }</span>
<span style="color: rgba(0, 0, 0, 1)">
obj.a </span>= 10<span style="color: rgba(0, 0, 0, 1)">;
console.log(obj); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 10, b: { c: 2} }</span>
console.log(newObj); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 1, b: { c: 2} }</span>
<span style="color: rgba(0, 0, 0, 1)">
newObj.a </span>= 20<span style="color: rgba(0, 0, 0, 1)">;
console.log(obj); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 10, b: { c: 2} }</span>
console.log(newObj); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 20, b: { c: 2} }</span>
<span style="color: rgba(0, 0, 0, 1)">
newObj.b.c </span>= 30<span style="color: rgba(0, 0, 0, 1)">;
console.log(obj); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 10, b: { c: 30} }</span>
console.log(newObj); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: 20, b: { c: 30} }</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 注意: 所有变量 的 *。b.c 都等于30; 原因看上面解释。</span></pre>
</div>
<p>&nbsp;</p>
<hr>
<p>&nbsp;</p>
<h1>结论:</h1>
<p><strong>原文中还有很多其他的办法,但此文仅摘抄出最有用的几个。一般不会用到第一种办法,如需要复制的变量有很多层的话,需要用第二种办法来复制,如果变量仅仅包含一层(如json格式的配置信息变量),第三种是最高效的。</strong></p>
<p>&nbsp;</p>
<p><span style="color: rgba(255, 0, 0, 1)">再次给出封装好的方法:</span></p>
<div class="cnblogs_code">
<pre>// 封装成方法<br>// 返回一个新的变量副本
// get a copy of an object
function<span> getNewObjectOf(src) {
return<span> Object.assign({}, src);
}</span></span></pre>
</div>
<p>&nbsp;</p>
<p><span class="hotness" style="box-sizing: inherit; margin-right: 20px; color: rgba(74, 74, 74, 1); font-family: Nunito, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-size: 15px; text-align: center">&nbsp;</span></p><br><br>
来源:https://www.cnblogs.com/AndrewXu/p/11601285.html
頁: [1]
查看完整版本: JavaScript 复制变量的三种方法