简体   繁体   English

在JavaScript中更改局部变量会影响具有不同名称的原始全局变量

[英]Changing local variable in JavaScript affects original global with different name

I have a global declared at top of script: 我在脚本顶部声明了一个全局变量:

var g_nutrition_summary = null;

When the user enters the page, I return network data and give this variable a value. 当用户进入页面时,我将返回网络数据并为该变量赋一个值。

g_nutrition_summary = json.data;

This line is the ONLY assignment of the variable and is never called again (tested with alerts). 该行是变量的唯一赋值,并且永远不会再次调用(经过警报测试)。

I later use that json.data variable to populate a Bar Chart with the plugin Chart.js . 稍后,我使用该json.data变量使用插件Chart.js填充条形图。 The global assignment is for later use. 全局分配供以后使用。

Underneath the chart, the user can filter certain types of data it displays with a series of checkboxes. 在图表下方,用户可以使用一系列复选框过滤显示的某些类型的数据。 So my goal is, to keep an original value of what comes in from the network, and then make a LOCAL COPY of it and alter the COPY (not the global original) and repopulate the chart. 因此,我的目标是,保留来自网络的内容的原始值,然后对其进行本地复制并更改COPY(而非全局原始值),然后重新填充图表。 Everytime the user checks/unchecks a checkbox, it will call this function and grab the ORIGINAL global ( g_nutrition_summary ) and re-filter that. 每次用户选中/取消选中复选框时,它将调用此函数并获取ORIGINAL全局( g_nutrition_summary )并对其进行重新过滤。

Here is how I do it: 这是我的方法:

function filter_nutrition_log()
{
    alert("1: " + JSON.stringify(g_nutrition_summary));

    // reassign object to tmp variable
    var tmp_object = g_nutrition_summary;

    var food_array = new Array("Grains", "Vegetables", "Fruits", "Oils");
    var checked_array = new Array();

    // Make an array of all choices that are checked
    $(".input-range-filter").each(function() 
    {        
        var type = $(this).val(); 
        if ($(this).is(':checked')) 
        {            
            checked_array.push(type);            
        }     
    });

    alert("2: " + JSON.stringify(g_nutrition_summary));

    // Loop thru all the 7 choices we chart
    $.each(food_array, function(i, val) 
    {
       // find out if choice is in array of selected checkboxes
       if ($.inArray(val, checked_array) === -1)
       {
            // it's not, so delete it from out tmp obj we 
            // will use to repopulate the chart with
            // (we do not want to overwrite the original array!)
            delete tmp_object["datasets"][val];
       }
    });

    // Resert graph
    alert("3: " + JSON.stringify(g_nutrition_summary));
    getNutritionChart(null, tmp_object, null, false);
}

Somehow, between alert "1" and alert "2". 以某种方式,在警报“ 1”和警报“ 2”之间。 The global gets changed. 全球变了。 Then when the user clicks a checkbox again and it calls this function, the very first alert shows that the original, global object contains the altered data to the tmp_object variable. 然后,当用户再次单击复选框并调用此函数时,第一个警报显示原始的全局对象包含对tmp_object变量进行更改的数据。

As you can see, I call a third party function I have created when this happens originally. 如您所见,当发生这种情况时,我将调用我创建的第三方函数。 Doing a search for the global there is absolutely nowhere else it is used in the instances described above. 搜索全局在上述实例中绝对没有其他地方可以使用。

Am I not understanding something about JavaScript variable scope? 我是否不了解JavaScript变量范围?

Both objects and arrays in javascript are treated as references, so when trying to pass them to functions or to "copy" them, you are just cloning the reference javascript中的对象和数组都被视为引用,因此当尝试将它们传递给函数或“复制”它们时,您只是在克隆引用

To have a "real copy", you would need to traverse the object and copy its content to another object. 要获得“真实副本”,您需要遍历对象并将其内容复制到另一个对象。 This can be done recursively, but fortunately jquery already comes with a function that does this: $.extend 可以递归地完成此操作,但幸运的是jquery已经带有执行此操作的函数: $.extend

So the solution would be: 因此解决方案将是:

var tmp_object = $.extend({},g_nutrition_summary);

If you have a nested object, you need to set an extra parameter: 如果您有嵌套的对象,则需要设置一个额外的参数:

var tmp_object = $.extend(true,{},g_nutrition_summary); // now it will do it recursively

For arrays, an easy way to make a "real copy" is, as @Branden Keck pointed out, 对于数组,如@Branden Keck所指出的,制作“真实副本”的一种简单方法是,

var arrCopy = arrOriginal.slice(0)

More on jquery extend: https://api.jquery.com/jquery.extend/ 有关jquery扩展的更多信息: https : //api.jquery.com/jquery.extend/

Going along with juvian's comment. 跟随juvian的评论。 To create the new array as somewhat of a "copy" and not just a reference, use: 要将新数组创建为某种“拷贝”而不仅仅是引用,请使用:

var tmp_object= g_nutrition_summary.slice(0);

However, .slice() is only works for arrays and will not work on JSON, so to used this method you would have to create an array from the JSON 但是,.slice()仅适用于数组,不适用于JSON,因此,要使用此方法,您必须从JSON创建数组

Another method that I found (although not the cleanest) suggested creating a string from the JSON and re-parsing it: 我发现的另一种方法(尽管不是最干净的)建议从JSON创建一个字符串并重新解析它:

var tmp_object= JSON.parse(JSON.stringify(g_nutrition_summary));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM