通过闭包复制对象

时间:2017-12-27 22:09:34

标签: javascript

我正在尝试获取这样一个对象的副本:

graphs = (function () {
    var trends = {
        pointSize: 10,
    };

    // Object Oriented JavaScript - pp 109
    var lockVariable = function(x) {
        return function() {
            return x;
        }
    };

    var getTrendsConfig = function() {
        return lockVariable(trends)();
    };
    return {
        getTrendsConfig : getTrendsConfig
    };
}());

c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())

我原本打算打印一个“{pointSize:10}”

因为 getTrendsConfig 函数会将trend对象传递给 lockVariable 函数,该函数将返回本地值对象:“{pointSize:10}”,而不是我得到的“{pointSize:11}”。

我从“面向对象的JavaScript”一书的一个例子中得到了这一点,第108-109页:

enter image description here

如何获得预期结果?可能吗?为什么这不起作用?

2 个答案:

答案 0 :(得分:1)

graphs = (function () {
    var trends = {
        pointSize: 10,
    };

    // Object Oriented JavaScript - pp 109
    var lockVariable = function(x) {
        return function() {
            return x;
        }
    };

    var getTrendsConfig = function() {
        return lockVariable(trends)();
    };
    return {
        getTrendsConfig : getTrendsConfig
    };
}());

c = Object.assign({}, graphs.getTrendsConfig()); // same as ...graphs.getTrendsConfig() in ES6 spread syntax

c.pointSize = 11;

console.log(graphs.getTrendsConfig());
console.log("c =", c);

由于您已将c.pointSize重新分配给11,因此您未获得预期结果,这就是您获得11的原因;

在JavaScript中,将对象分配给变量是通过引用而不是通过值完成的。这意味着您只是复制对象在内存中的位置,导致任何修改都会影响原始值。

在您分配c = graphs.getTrendsConfig();的示例中,c现在将指向同一对象的位置/地址。
当您执行此c.pointSize = 11时,您修改了相同的(原始)对象而不是副本。

<强>解决方案: 另外,为了制作graphs.getTrendsConfig()的副本,您可以使用Object.assign()或新的ES6差异语法...。通过制作副本,您不会修改原始对象的pointSize变量。

答案 1 :(得分:1)

JavaScript中的原始值(如数字)是不可变的。您可以将x复制到i(根据本书),更改x并保持trends不变。

对象不是不可变的,只能通过引用来解决。当您返回c = graphs.getTrendsConfig();c)的值时,您将返回对该对象的引用(因此trendstrends都包含对同一对象的引用)。修改它时,您修改该对象。获取graphs = (function() { var lockVariable = function(x) { return function() { return x; } }; var getTrendsConfig = function() { var trends = { pointSize: 10, }; return lockVariable(trends)(); }; return { getTrendsConfig: getTrendsConfig }; }()); c = graphs.getTrendsConfig(); c.pointSize = 11; console.log(graphs.getTrendsConfig())的另一个副本会为您提供另一个参考副本...仍然指向同一个对象。

处理这个问题的简单方法是在被调用的函数内移动创建对象的逻辑。

&#13;
&#13;
graphs = (function() {
  var getTrendsConfig = function() {
    return {
      pointSize: 10,
    };
  };
  return {
    getTrendsConfig: getTrendsConfig
  };
}());

c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
&#13;
&#13;
&#13;

虽然您可以将其简化为

&#13;
&#13;
graphs = (function() {
  var trends = {
    pointSize: 10,
  };

  // Object Oriented JavaScript - pp 109
  var lockVariable = function(x) {
    return Object.assign({}, x);
  };

  var getTrendsConfig = function() {
    return lockVariable(trends);
  };
  return {
    getTrendsConfig: getTrendsConfig
  };
}());

c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
&#13;
&#13;
&#13;

要使用接近原始代码尝试实现的内容,您可以使用Object.assign()

返回对象的显式副本

&#13;
&#13;
import pandas as pd
import numpy as np

headers = lista.pop(0)

df = pd.DataFrame(lista, columns = headers)

martin = df[df['"Cliente"'] == 'Martin']
tom = df[df['"Cliente"'] == 'Tom']

merge = pd.merge(martin, tom, on = '"Fecha"')

stats = headers[2:]
compare = ['"Fecha"']

for index, row in merge.iterrows():
    for x in stats:
        merge[x+'_compare'] = np.where(row[x+'_x'] > row[x+'_y'], 'Martin', 'Tom')
        if x+'_compare' not in compare:
            compare.append(x+'_compare')

print(merge[compare])

#output
"Fecha" "Subastas"_compare  "Impresiones_exchange"_compare  "Fill_rate"_compare "Importe_a_pagar_a_medio"_compare   "ECPM_medio"_compare
20/12/2017  Tom Martin  Martin  Martin  Tom
21/12/2017  Tom Martin  Martin  Martin  Tom
22/12/2017  Tom Martin  Martin  Martin  Tom
&#13;
&#13;
&#13;