V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
yuan321
V2EX  ›  JavaScript

js 有什么优雅的方法可以在处理 json 数组的时候只改变其中一个键值对的值并且自动保留其他的键值对不变吗

  •  
  •   yuan321 · 2022-05-12 09:42:53 +08:00 · 3357 次点击
    这是一个创建于 686 天前的主题,其中的信息可能已经有所发展或是发生改变。
    let test=[
      {
        "id": 28620,
        "name": "茌平粉煤灰[Ⅱ级]",
        "dn": "掺合料"
      },
      {
        "id": 5941,
        "name": "粉煤灰[Ⅰ 级]",
        "dn": "掺合料"
      },
      {
        "id": 5226,
        "name": "粉煤灰[Ⅱ级]",
        "dn": "掺合料"
      }]
      //需求是只改变 dn 为其他
      //改变后值为
      test=[
      {
        "id": 28620,
        "name": "茌平粉煤灰[Ⅱ级]",
        "dn": "其他"
      },
      {
        "id": 5941,
        "name": "粉煤灰[Ⅰ 级]",
        "dn": "其他"
      },
      {
        "id": 5226,
        "name": "粉煤灰[Ⅱ级]",
        "dn": "其他"
      }]
     // 这是我用到的方法
      test=test.map((item)=>({
        'id':item.id,
        'name':item.name,
        'dn':'其他'
      }))
      //这种方法是可行但是不优雅,因为就为了改变一个值还要把其他的也写上,有什么更好的方法实现吗?
    28 条回复    2022-06-07 11:20:12 +08:00
    akaxiaok339
        1
    akaxiaok339  
       2022-05-12 09:46:47 +08:00
    解构呀
    actar
        3
    actar  
       2022-05-12 09:48:13 +08:00
    test = test.map((item) => ({
    ...item,
    'dn': '其他'
    }))
    cjd6568358
        4
    cjd6568358  
       2022-05-12 09:49:27 +08:00
    test=test.forEach((item)=>item.dn='其他')
    --------------------------
    JSON.parse(JSON.stringfy(test).replace('dn:xxx','dn:qita'))
    alanhe421
        5
    alanhe421  
       2022-05-12 09:51:12 +08:00
    跟 json 啥关系?单单数组,做法就是这样,如楼上,缺的是个解构

    但假如本身只是个大的字符串,除了 JSON.parse 转为数组,进行处理之外,本身也可以直接 replace 正则。只是不差这点性能了。
    yuan321
        6
    yuan321  
    OP
       2022-05-12 10:00:22 +08:00
    谢谢,这三种方法都很好
    yaphets666
        7
    yaphets666  
       2022-05-12 10:10:24 +08:00
    test.forEach(item => item.dn = '其他') 就行了。这里边其实挺有玄机的,值传递~内存,指针~
    akatquas
        8
    akatquas  
       2022-05-12 10:22:42 +08:00   ❤️ 2
    纯纯提问,使用高级语法糖,就是优雅的意思吗?
    learningman
        9
    learningman  
       2022-05-12 10:25:04 +08:00 via Android
    @akatquas 函数式编程就是优雅的意思
    yuan321
        10
    yuan321  
    OP
       2022-05-12 10:27:10 +08:00
    @yaphets666 感觉这种写法确实有点匪夷所思
    libook
        11
    libook  
       2022-05-12 10:34:46 +08:00
    只改值不改字段,直接循环改值应该是最方便的,如用 forEach 方法或者干脆 for 循环。

    涉及到改字段名的话,也可以用循环,然后在每个对象里加个新字段,再 delete 旧字段;或者就用解构。

    另外要考虑下文是否还会用到修改之前的数组,如果用到的话也可以在这边新建数组修改,保留原数组的形态。
    reiji
        12
    reiji  
       2022-05-12 10:39:03 +08:00
    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#%E4%BD%BF%E7%94%A8_reviver_%E5%87%BD%E6%95%B0
    如果数据是从服务器拉过来的,可以直接在解析 json 的时候使用 reviver 函数处理
    libook
        13
    libook  
       2022-05-12 10:40:42 +08:00
    @yuan321 #10 JS 里面赋值有两种情况,一种是 string 、number 、bool 等简单类型的值复制,即 a=1;b=a ,那么 a 和 b 的值都是 1 ,但修改 a 不会导致 b 的值变化;另一种是对象、数组等的引用,即 a=[1];b=a;当给 a push 新元素之后,b 也随之改变。这个是 JS 最常用的基本的原理之一,用熟练了就不会觉得奇怪了。
    foolnius
        14
    foolnius  
       2022-05-12 10:51:05 +08:00
    @yuan321 #10
    值传递和引用传递的特性,不是 JavaScript 独有的
    forbreak
        15
    forbreak  
       2022-05-12 11:00:03 +08:00
    有个 json path 的包,可以用 set('*.dn','其他') 这种方式修改值。但是你这个单层也没必要。 多层 json 的话挺好用。
    brader
        16
    brader  
       2022-05-12 11:27:28 +08:00
    ```
    $test = '[{"id":28620,"name":"茌平粉煤灰[Ⅱ级]","dn":"掺合料"},{"id":5941,"name":"粉煤灰[Ⅰ 级]","dn":"掺合料"},{"id":5226,"name":"粉煤灰[Ⅱ级]","dn":"掺合料"}]';
    $test = json_decode($test);
    foreach ($test as $item) {
    $item->dn = '其他';
    }
    ```

    用 PHP 吧,少年,哈哈哈
    KousukeSakurako
        17
    KousukeSakurako  
       2022-05-12 12:26:40 +08:00
    写个 for 循环很麻烦吗
    wangtian2020
        18
    wangtian2020  
       2022-05-12 13:12:40 +08:00
    3 楼 4 楼都是标准答案,应该没有其他不引包的好办法了
    我倾向于使用 Array 的 map 或者 forEach
    jifengg
        19
    jifengg  
       2022-05-12 13:35:05 +08:00
    用 map 和解构,生生的多出一个数组的内存占用和解构耗时,并且 test 的引用也变了。
    forEach 或者 for 才是正解。楼主自己也说了,只是改一个字段的值,为什么要把其他字段也写上呢。

    自己简单测试一下,仅仅楼主的三个字段的 obj ,map 耗时是 for[Each]的 10 倍多。
    huai
        20
    huai  
       2022-05-12 13:43:38 +08:00
    test.forEach(i => i.dn = '其他')

    test.map(i => i.dn = '其他') // 只执行,不要考虑返回



    原来的值 不在意的话,两种方法没啥区别。
    rehoni
        21
    rehoni  
       2022-05-12 13:59:24 +08:00
    楼主写的有点啰嗦,map 和 forEach 是可以简写的,楼上已经有很多例子了。。而且我感觉会用 map 应该就会用 foreach 才对啊。。
    Envov
        22
    Envov  
       2022-05-12 14:06:31 +08:00
    @yaphets666 这个代码其实性能蛮好,但是搞习惯了 immutable 看这个真的难受
    yuan321
        23
    yuan321  
    OP
       2022-05-12 14:17:38 +08:00
    @huai 居然还可以这样子用 map 。。。
    yuan321
        24
    yuan321  
    OP
       2022-05-12 14:18:18 +08:00
    @huai 完全没有理解到 map 的精髓
    yaphets666
        25
    yaphets666  
       2022-05-12 14:33:36 +08:00
    @Envov 其实注意到这种事情就 ok
    mybyons
        26
    mybyons  
       2022-05-12 17:55:21 +08:00   ❤️ 2
    看到了我的家乡 茌平 估计 99% 不知道这个地方 也不知道怎么念这个名字
    galikeoy
        27
    galikeoy  
       2022-05-12 18:09:19 +08:00
    @yuan321 #23 你可以在 js 所有循环方法更改元素属性,find,filter,some,map,every, 他们的区别只是返回值和执行顺序而已,从性能上考虑,自然是 test.forEach(i => i.dn = '其他')最好,map 还要返回
    LLaMA2
        28
    LLaMA2  
       2022-06-07 11:20:12 +08:00
    歪一下,map 的话入参变成 async 然后 Promise.all 可以并发的跑,量大的话还是能快过 forEach
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1053 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 19:10 · PVG 03:10 · LAX 12:10 · JFK 15:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.