【问题标题】:javascript return reference to array itemjavascript 返回对数组项的引用
【发布时间】:2014-08-09 20:39:21
【问题描述】:

我有一个这样的数组:

users = [{id:1, name:'name1'},{id:2, name:'name2'}]

我如何获得对项目 {id:2, name:'name2'} 的引用,所以我可以将其更改为 name 属性,例如:

user = get_item(users, 'id', 2);
user.name = "user2 name changed";

console.log(users) 会有结果:

[{id:1, name:'name1'},{id:2, name:'user2 name changed'}]

我尝试使用 Array.filter() 函数,但它返回一个新数组而不是对原始数组的引用。我不能用它来改变原始数组。

有什么想法吗?

【问题讨论】:

    标签: javascript arrays pass-by-reference


    【解决方案1】:

    我尝试使用Array.filter() 函数,但它返回一个新数组而不是对原始数组的引用。我不能用它来改变原始数组。

    它返回一个新数组,但数组的 entries 仍然是对相同对象的引用。所以filter 就可以了。

    var filteredUsers = users.filter(function(entry) { return entry.id === 2; });
    var item = filteredUsers[0];
    item.name = "user2 name updated";
    console.log(users[1].name) // "user2 name updated"
    

    数组包含对象的引用,而不是对象的副本。当我们使用item = users[1] 或使用filter 来获取包含对象子集的新数组时,我们会得到对象引用的副本,因此该变量现在引用的是同一个对象,如下所示:

    +−−−−−−−−−−−+ 用户------------->| (数组) | +−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−+ | 0 |−−−−−−−−−−->| (对象) | | | +−−−−−−−−−−−−−−−−−+ | | |编号:1 | | | |名称:“名称1” | | | +−−−−−−−−−−−−−−−−−+ | 1 |−−+ | | | | | | +−−−−−−−−−−−−−−−−−+ | | +−−−+−+−>| (对象) | +−−−−−−−−−−−+ / / +−−−−−−−−−−−−−−−−−+ | | |编号:2 | +−−−−−−−−−−−+ | | |名称:“名称2” | 过滤用户-->| (数组) | | | +−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−+ | | | 0 |−−−−−−+ | +−−−−−−−−−−−+ | | 项目−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

    更改对象会更改对象,并且无论您使用哪个对对象的引用来查看其属性,这些更改都是可见的。

    现在,如果你有一个 原始数组

    var a = [1, 2, 3, 4, 5];
    

    ...那么当然,您不能使用上述方法,因为它们不是对象。在这种情况下,您可以使用indexOf 来查找索引:

    var index = a.indexOf(3); // Find the first entry === 3
    

    ...然后修改条目

    a[index] = 42;
    

    这也适用于字符串(前提是它们是很好的普通字符串原语,而不是您通过 new String() 创建的东西,几乎没有理由这样做)。

    【讨论】:

    • 这个问题是我不知道索引,只知道id属性值,这就是为什么我需要一个辅助函数来查找项目并引用它
    • @xiaopang:哦,我没听懂。我会修复答案。
    • @xiaopang:我再次编辑以解决您问题中的主要误解。
    • 今天学到了一些新东西...
    【解决方案2】:

    为了类似于接受的答案,但更简洁一点,让我们使用Array.find,如下所示:

    var item = users.find(u => u.id === 2)
    item.name = "user2 name updated"
    console.log(users[1].name) // "user2 name updated"
    

    解释与接受的答案中提供的非常相似。

    【讨论】:

    • 我相信这是正确的答案,简单明了:)
    • 这不起作用 a = [1,2,3]; -> (3) [1, 2, 3] b = a.find(i => i === 2); -> 2 b = 4; -> 4个; -> (3) [1, 2, 3]
    • Matt 它只适用于非原始值。 Javascript 通过引用返回非原语,如对象和数组。
    • 如果你知道该项目存在,你可以去:users.find(u => u.id === 2).name = "user2 name updated";
    • find 返回一个引用,我认为这是一个糟糕的设计模式,find 应该返回全新的对象以尊重可变性。
    【解决方案3】:

    您可以使用findIndex(),例如:

    var users = [{id:1, name:'name1'},{id:2, name:'name2'}]
    var idx = users.findIndex(item => item.id === 2);
    var u = users[idx]; // the reference of user2
    u.name = "name changed."; // same as `users[idx].name = "name changed.";`
    

    【讨论】:

    • 此方法在找到匹配的单个项目时停止搜索,这可能比使用始终处理整个数组的过滤器更有效。
    【解决方案4】:

    与@zing-lee 的回答类似,您可以使用find() 删除多行代码:

    var users = [{id:1, name:'name1'},{id:2, name:'name2'}]
    var user = users.find(item => item.id === 2)
    user.name = 'name change'
    

    来自文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

    返回值: 数组中第一个元素的值满足 提供测试功能

    因为它是一个 Objects(不是原语)数组,返回值将是对原始对象的 reference,因此修改返回对象的属性,将更新它所引用的对象的属性。

    这里有很好的文章解释 Javasript 中的值和引用:https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

    【讨论】:

    • 有趣的是,如果我用类似 let foundElement = collections.find(element => element.id === someId); foundElement = {..someData}; 的价差运算符覆盖fund 方法找到的对象,它将不起作用
    • 这是预期的行为。扩展运算符的工作方式类似于Object.assign()。它总是返回对象的浅拷贝。
    • 是的,我没有抱怨的意思,只是跟别人提了提
    【解决方案5】:

    要么

      users[1].name = "xx"
    

    或者如果您想像在问题中尝试那样按 id 搜索:

    for (i = 0; i < users.length; i++) {
      if (users[i].id == "2") {
        users[i].name = "xxx";
      }
    }
    

    edit您想要更高级的东西,使用 map 怎么样:(想法是您可以更改与查询匹配的元素并基于它创建一个新数组。您可以使用 filter过滤掉它们)

    [{a: 1, b: 2}, {a:3, b:2}].map(function (elm) {
    if (elm.b == 2) {
     elm.a += 5;
    }
    return elm;
    });
    

    返回:

    [{a: 6, b: 2}, {a:8, b:2}]
    

    【讨论】:

    【解决方案6】:

    检查以下功能是否能解决您的问题

    注意:自定义对象总是通过引用 JavaScript 函数来传递。因此自定义对象的数组是通过引用传递的。

    function updateUser(targetArray, keyField, targetField, key, new_val) {
    var result = -1;
    for (var i = 0; i < targetArray.length; i++) {
        if (targetArray[i][keyField] == key) {
            targetArray[i][targetField] = new_val;
            result = i;
            return result;
        }
    }
    return result;
    }
    

    Example

    【讨论】:

      【解决方案7】:

      这里的代码可以更好地解释这个场景。运行脚本就明白了。

      var arr = [
      	{"name": "James", "age": 34},
      	{"name": "Peter", "age": 67}
      ];
      
      var p1 = arr.filter(function(p){return p.name=="James"});
      p1[0] = {"name": "James", "age": 50};
      console.log(JSON.stringify(arr)); // Won't work
      
      var p2 = arr.filter(function(p){return p.name=="James"});
      p2[0].age = 50;
      console.log(JSON.stringify(arr)); // Voila... this works

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-16
        • 1970-01-01
        • 2014-05-23
        • 2012-06-28
        • 1970-01-01
        • 2021-09-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多