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

在 js 中为什么如下方式会找不到值?

  •  
  •   qq309187341 · 2023-01-04 10:38:41 +08:00 · 3761 次点击
    这是一个创建于 690 天前的主题,其中的信息可能已经有所发展或是发生改变。
    let a = {
    b: {
    c: {
    d: 1
    }
    }
    }

    let z = 'c.d'
    console.log(a.b[z]) // undefined
    为什么?
    如何才能正常找到
    35 条回复    2023-01-04 20:52:44 +08:00
    DingJZ
        1
    DingJZ  
       2023-01-04 10:40:59 +08:00
    js 本来就不支持这种玩法,可以用第三方的库,lodash 之类的
    qq309187341
        2
    qq309187341  
    OP
       2023-01-04 10:42:51 +08:00
    @DingJZ 不借用第三方,有什么别的写法,如果 z 只有一层 z='c'这样是能找到 c 的,但是再加一层就找不到了
    GressJoe
        3
    GressJoe  
       2023-01-04 10:43:20 +08:00
    eval ,不过容易 boom
    vagary
        4
    vagary  
       2023-01-04 10:46:24 +08:00   ❤️ 2
    哈哈哈哈哈
    a={b:{'c.d':1}}; z='c.d'; console.log(a.b[z])能找到
    DOLLOR
        5
    DOLLOR  
       2023-01-04 10:47:21 +08:00
    要么直接用 lodash ,要么自己参考 lodash 的源码自己实现一个 get 方法。
    我倒是好奇有什么编程语言能这样来的?
    thinkershare
        6
    thinkershare  
       2023-01-04 10:48:19 +08:00
    因为 c.d 是一个合法的属性,JS 的对象本质是个 string|symbol-> any 的字典映射。
    chenmobuys
        7
    chenmobuys  
       2023-01-04 10:49:41 +08:00
    啥语言能这样写,这估计是第三方库的处理吧
    wangtian2020
        8
    wangtian2020  
       2023-01-04 10:53:34 +08:00   ❤️ 1
    let a = {
    b: {
    c: {
    d: 1,
    },
    },
    }

    let z = 'c.d'
    console.log(eval(`a.b.${z}`)) // 1
    rongchuan
        9
    rongchuan  
       2023-01-04 10:53:51 +08:00   ❤️ 5
    @qq309187341
    你声明的'c.d'是一个 string 。a.b[z]是从 a 的 b 属性这个对象上,去找 key 值是 z 的 value ,也就是找 key 值是'c.d'的 value 。显然没有这个 value
    这跟第三方库没关系,你没有理解 key 的概念,.不是随便就能.的
    lower
        10
    lower  
       2023-01-04 10:54:56 +08:00
    a.b['c']['d'] 能找着🤣
    qq309187341
        11
    qq309187341  
    OP
       2023-01-04 10:55:36 +08:00
    @rongchuan 哦。我明白了,c.d 是一个整体,而不是 c 下的 d 。所以合在一起就成了 a.b.'c.d'是这样对吧。哈哈哈哈
    qq309187341
        12
    qq309187341  
    OP
       2023-01-04 10:56:42 +08:00
    @lower 哈哈哈,你这个也行。我理解错了。确实要用你这样的写法才可以
    heishu
        13
    heishu  
       2023-01-04 11:31:27 +08:00
    #8 和 #10 是两种可行的方法,一个是处理字符串,一个是对象依次找值
    pendulum
        14
    pendulum  
       2023-01-04 11:34:18 +08:00
    有点想当然了,JS 根本没有这种特性
    hervey0424
        15
    hervey0424  
       2023-01-04 11:38:37 +08:00
    let a = { 'b.c': 123, b: { c: 456 } };
    console.log(a.b.c); // 456
    console.log(a['b.c']); //123
    enchilada2020
        16
    enchilada2020  
       2023-01-04 11:41:19 +08:00 via Android
    我居然看了好久才明白你的代码意图是什么。。。。所以反过来我想问的是 哪个语言能支持你这样的写法取值?
    mynameislihua
        17
    mynameislihua  
       2023-01-04 11:44:09 +08:00
    lodash get
    webcape233
        18
    webcape233  
       2023-01-04 11:49:37 +08:00 via iPhone
    什么样的需求这是...
    zhouyg
        19
    zhouyg  
       2023-01-04 11:55:56 +08:00
    根本原因 js 不知道你传入的 c.d 是一个整体的字符串 key 还是可以分割的访问 key ,这里是有歧义的。支持这个特性也很简单,那就是在语言层面新增一个语法来消除这个歧义
    1t1y1ILnW0x5nt47
        20
    1t1y1ILnW0x5nt47  
       2023-01-04 11:57:02 +08:00
    可以用 Object.defineProperty 劫持它的 key,然后把 c.d 转化一下
    caocong
        21
    caocong  
       2023-01-04 12:06:32 +08:00   ❤️ 2
    z.split('.').reduce((res, val)=>res[val],a.b)
    venfiw
        22
    venfiw  
       2023-01-04 12:52:02 +08:00
    let a = {
    b: {
    c: { d: 1}
    }
    }

    let z = 'c.d';
    console.log(a.b[z]) // undefined
    console.log(Object.keys(a.b))

    你可以通过这个可以看到 a.b 里只有一个键值:'c' 并没有'c.d'
    如果你把 c 改为‘c.d' 那么 a.b[z]就可以正常输出
    777777
        23
    777777  
       2023-01-04 14:32:53 +08:00
    写 go 的,看见这种语法直接震惊
    aust
        24
    aust  
       2023-01-04 14:43:14 +08:00
    这种写法你要打印的写法等同于
    {
    "c.d": 1
    } 而不是 {
    c: {
    d: 1
    }
    }
    Arthit
        25
    Arthit  
       2023-01-04 16:12:20 +08:00
    console.log(a.b["c"]["d"]);
    libook
        26
    libook  
       2023-01-04 16:18:47 +08:00   ❤️ 1
    题主提供了一个典型的 bug 案例。因为实际工程上,更多的情况是我们会预期给 z 传入单个字段名,但意外传入路径就 bug 了。所以通常这样用需要小心,如果 z 是用户输入的要做好校验。
    weixiangzhe
        27
    weixiangzhe  
       2023-01-04 16:54:12 +08:00
    那就是手写个 get
    ```js
    function get(obj, path, def) {
    var fullPath = path
    .replace(/\[/g, '.')
    .replace(/]/g, '')
    .split('.')
    .filter(Boolean);

    return fullPath.every((step)=>{
    return !(step && (obj = obj[step]) === undefined);
    }) ? obj : def;
    }

    let a = {
    b: {
    c: {
    d: 1
    }
    }
    }

    let z = 'c.d'
    // console.log(a.b[z]) // undefined


    console.log(get(a,'b.c.d'))


    ```
    horseInBlack
        28
    horseInBlack  
       2023-01-04 17:06:32 +08:00
    const {
    b: {
    c: { d: z },
    },
    } = a;

    console.log(z);

    连续解构赋值
    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
    chenyu0532
        29
    chenyu0532  
       2023-01-04 18:07:58 +08:00
    连续解构赋值吧。
    你们玩的是真 high ,学习归学习,工作里我可不敢这么用,怕同事打我
    z782297190
        30
    z782297190  
       2023-01-04 18:19:48 +08:00
    字符串 . 和 属性访问器 . 是不同的,js 引擎不认字符串 .
    enchilada2020
        31
    enchilada2020  
       2023-01-04 18:29:18 +08:00 via Android
    @777777 小场面 莫慌莫慌 写 JS 的震惊。。
    mwjz
        32
    mwjz  
       2023-01-04 18:38:39 +08:00
    let a = {
    b: {
    c: {
    d: 1
    }
    }
    }

    let z = 'c.d'

    const c = z.split('.').reduce((pre, curr) => pre[curr], a.b);
    imingyu
        33
    imingyu  
       2023-01-04 18:42:57 +08:00
    为什么?
    因为你语法写错了!
    为什么语法是 a.b.c.d 而不是 a.b['c.d']?
    因为规定!
    lynan
        34
    lynan  
       2023-01-04 20:51:57 +08:00
    https://imgur.com/EHwVAgx.png
    这样写才可以取到值,因为在[]里是 key 名
    lynan
        35
    lynan  
       2023-01-04 20:52:44 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   926 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:48 · PVG 03:48 · LAX 11:48 · JFK 14:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.