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

神奇的 Javascript,谁能告诉我为什么

  •  1
     
  •   zero3412 · 2021-05-05 14:08:42 +08:00 · 7070 次点击
    这是一个创建于 1333 天前的主题,其中的信息可能已经有所发展或是发生改变。
    let data = [
    {x:0, y:1},
    {x:2, y:3},
    ];

    let A = data[0];
    let B = data[1];

    A.x = B.x;
    A.y = B.y;

    console.log(data, A, B)

    为什么 data[0].x == 2 ???
    明明申请了变量 A,我只想改变变量 A,怎么连 data 的值都变了
    这是什么原理,搞 PHP 的搞不明白啊
    53 条回复    2021-05-06 17:54:43 +08:00
    across
        1
    across  
       2021-05-05 14:11:05 +08:00
    不懂 php 。
    {}是 object 类型,A 是做了 data[0]引用,改 A 就是改 data[0]
    zero3412
        2
    zero3412  
    OP
       2021-05-05 14:12:28 +08:00
    @across 至少在 PHP 里,A 变量就是个完全独立的值了,只是复制了一份 data[0],直接蒙逼了哇,这操作太神奇了。
    across
        3
    across  
       2021-05-05 14:13:59 +08:00
    @zero3412 php 不知道,但我接触的大语言,都是自定义类型按引用传递,基础类型按值传递的····
    dzdh
        4
    dzdh  
       2021-05-05 14:14:24 +08:00
    PHP 的话是这样的:

    ```
    php > $a = new StdClass();
    php > $a->a = new StdClass();
    php > $b = $a->a;
    php > $b->ee = 3;
    php > var_dump($a);
    object(stdClass)#1 (1) {
    ["a"]=>
    object(stdClass)#2 (1) {
    ["ee"]=>
    int(3)
    }
    }
    ```
    aijam
        5
    aijam  
       2021-05-05 14:15:37 +08:00
    搞清楚“对象”和“引用”的关系。列表和变量存的都是引用,而通过引用改变的都是同一个对象。
    ashong
        6
    ashong  
       2021-05-05 14:15:45 +08:00
    let A = Object.assign({}, data[0]);
    zero3412
        7
    zero3412  
    OP
       2021-05-05 14:23:02 +08:00   ❤️ 1
    @across @dzdh @aijam @ashong

    谢谢各位,找了一篇文章学习了一下 https://segmentfault.com/a/1190000014724227
    特别是 “列表和变量存的都是引用,而通过引用改变的都是同一个对象。” 精辟
    ericgui
        8
    ericgui  
       2021-05-05 14:23:23 +08:00
    JavaScript 是 pass by reference
    Jirajine
        9
    Jirajine  
       2021-05-05 14:39:50 +08:00 via Android
    @across 全部都是按引用传递,所谓“按值传递”是一种 inline 优化,对程序员是透明的,这些语言没有 deref 操作。
    JerryCha
        10
    JerryCha  
       2021-05-05 14:48:48 +08:00   ❤️ 2
    data[0]传递的实际是指针,小伙子 C 没学好吧
    Rocketer
        11
    Rocketer  
       2021-05-05 14:57:25 +08:00 via iPhone
    实际上传指针才是主流,PHP 那种默认传值,加了&才传指针的,属于少数派
    HashV2
        12
    HashV2  
       2021-05-05 15:08:24 +08:00
    很多语言都这样吧,引用
    godbasin
        13
    godbasin  
       2021-05-05 15:09:09 +08:00
    因为 A 拿到的是 data[0] 的引用
    ipwx
        14
    ipwx  
       2021-05-05 15:16:15 +08:00   ❤️ 4
    大部分语言,C#, Java, Javascript, Scala, Python 都是这个逻辑。PHP 是少数。

    C++ 程序员不会有这个疑问,因为他们天天和 T* T& T 打交道
    InternetExplorer
        15
    InternetExplorer  
       2021-05-05 15:19:47 +08:00   ❤️ 1
    php 的数组是值类型,而且是写是复制,大数组赋值起来很快,改到的时候才会真正复制值。
    js 的对象 { }(包括数组 [ ] ) 是引用类型,赋值就是传一下引用,都是指向同一个对象的。
    hejingyuan199
        16
    hejingyuan199  
       2021-05-05 15:29:05 +08:00
    我平时基本只用 php,但我感觉 JavaScript 这个才更符合编程本质吧。

    没深入研究过 php 这个问题。
    Justfakemoz
        17
    Justfakemoz  
       2021-05-05 15:31:32 +08:00
    。。。除了基础类型,赋值都是引用
    zjsxwc
        18
    zjsxwc  
       2021-05-05 15:38:08 +08:00
    感觉楼主在抹黑 php 。

    php 里你用对象照样也和 js 得到一样的结果。

    无非是 js 里面 {} 表示对象,php 里面 [] 表示数组不是对象。
    jeffwcx
        19
    jeffwcx  
       2021-05-05 16:04:17 +08:00
    看得我一脸懵逼,我还以为有啥问题呢
    jonsun30
        20
    jonsun30  
       2021-05-05 16:07:44 +08:00
    Everthing using a dot in JS is an object.

    When you store a non-primitive value some where or you pass it to a function, it is passed by reference, you are passing a pointer to it.
    ShuoHui
        21
    ShuoHui  
       2021-05-05 16:12:27 +08:00 via iPhone
    不懂 php,pythoner 感觉没毛病啊……
    Rache1
        22
    Rache1  
       2021-05-05 16:42:04 +08:00
    PHP 里面对象也是引用的,数组不是
    darknoll
        23
    darknoll  
       2021-05-05 16:47:45 +08:00
    这不是最基础的东西?
    charlie21
        24
    charlie21  
       2021-05-05 16:55:39 +08:00
    1

    JAVASCRIPT
    let arr1 = [1,2,3,4];
    let arr2 = arr1;
    arr2[0] = 99;
    console.log(arr2); // [99,2,3,4]
    console.log(arr1); // [99,2,3,4]

    JAVASCRIPT
    let arr1 = [1,2,3,4];
    let arr2 = [...arr1];
    arr2[0] = 99;
    console.log(arr2); // [99,2,3,4]
    console.log(arr1); // [1,2,3,4]

    JAVASCRIPT
    let d1 = { x: 1, y:2 };
    let d2 = d1;
    d2.x = 80;
    console.log(d2); // { x: 80, y: 2 }
    console.log(d1); // { x: 80, y: 2 }

    JAVASCRIPT
    let d1 = { x: 1, y:2 };
    let d2 = {...d1};
    d2.x = 80;
    console.log(d2); // { x: 80, y: 2 }
    console.log(d1); // { x: 1, y: 2 }

    关键词 js spread operator

    2

    PHP
    $arr1 = [1,2,3,4];
    $arr2 = $arr1;
    $arr2[0] = 99;
    var_export($arr2); // [99,2,3,4]
    var_export($arr1); // [1,2,3,4]

    PHP
    $arr1 = [1,2,3,4];
    $arr2 = &$arr1;
    $arr2[0] = 99;
    var_export($arr2); // [99,2,3,4]
    var_export($arr1); // [99,2,3,4]

    3

    C#
    int[] arr1 = new int[]{1,2,3,4};
    int[] arr2 = arr1;
    arr2[0] = 99;
    Console.WriteLine(String.Join(" ", arr2)); // 99 2 3 4
    Console.WriteLine(String.Join(" ", arr1)); // 99 2 3 4

    C#
    using System.Collections.Generic;
    List<int> list1 = new List<int>{1,2,3,4};
    List<int> list2 = new List<int>(list1);
    list2[0] = 99;
    list2.ForEach(Console.WriteLine); // 99 2 3 4
    list1.ForEach(Console.WriteLine); // 1 2 3 4

    C#
    using System.Collections.Generic;
    List<int> list1 = new List<int>{1,2,3,4};
    List<int> list2 = list1;
    list2[0] = 99;
    list2.ForEach(Console.WriteLine); // 99 2 3 4
    list1.ForEach(Console.WriteLine); // 99 2 3 4
    belin520
        25
    belin520  
       2021-05-05 17:15:21 +08:00 via iPhone
    面试面基础还是很有必要的,即使是八股文
    很多人即使自己不知道为什么,也不尝试去弄清楚为什么
    OHyn
        26
    OHyn  
       2021-05-05 17:23:15 +08:00
    这个在 java 、c 里头也是一样的呀。。。传值和传引用嘛
    iyaozhen
        27
    iyaozhen  
       2021-05-05 19:39:41 +08:00
    PHP 虽然说是传值,但实际也是引用。然后有个写死复制的机制,就是当发现要修改 A 时,是复制了一份。
    省去了需要自己 copy 的问题,比较符合人的思维
    WillBC
        28
    WillBC  
       2021-05-05 22:03:59 +08:00 via iPhone
    等你感受一下 deep clone
    Nitroethane
        29
    Nitroethane  
       2021-05-05 22:14:38 +08:00
    @JerryCha data[0] 不一定传引用啊,得看 data 的数据类型,如果是 char* data[],那 data[0] 就传的是指针,如果是 char data[],data[0] 照样传值
    anguiao
        30
    anguiao  
       2021-05-05 22:38:50 +08:00 via Android
    虽然 JS 确实很神奇,但是这个是常规操作。
    Yvette
        31
    Yvette  
       2021-05-06 04:51:24 +08:00
    JS 里除了 primitive types 是 pass by value 之外,其余所有的都是 reference
    xuanbg
        32
    xuanbg  
       2021-05-06 06:39:25 +08:00
    因为
    let A = data[0];
    let B = data[1];

    所以 data 的值变成 [
    {x:2, y:3},
    {x:2, y:3},
    ];
    xuanbg
        33
    xuanbg  
       2021-05-06 06:40:16 +08:00
    因为
    let A = data[0];
    let B = data[1];

    A.x = B.x;
    A.y = B.y;

    所以 data 的值变成 [
    {x:2, y:3},
    {x:2, y:3},
    ];
    Marszm
        34
    Marszm  
       2021-05-06 08:46:20 +08:00
    这种需要深拷贝.....PHP 这波属于非主流操作
    oneisall8955
        35
    oneisall8955  
       2021-05-06 08:49:41 +08:00 via Android
    JAVA 的路过,要不是这样的结果才奇怪😳
    yl14786922106
        36
    yl14786922106  
       2021-05-06 09:00:52 +08:00
    js 按值传递和 按引用传递的区别 let A = data[0] 时,A 只是一个指针 指向堆区的 data[0] : {x:0,y:1},所以改变 A.x 时改变的是 data[0]。
    meloncc
        37
    meloncc  
       2021-05-06 09:12:50 +08:00
    这个问题与 Javascript 没有关系
    gtanyin
        38
    gtanyin  
       2021-05-06 10:17:02 +08:00
    果然学编程应该从 C 学起,不然连指针的概念都要惊讶半天
    liuky
        39
    liuky  
       2021-05-06 10:57:20 +08:00   ❤️ 1
    楼主高级黑
    misaka19000
        40
    misaka19000  
       2021-05-06 10:59:55 +08:00
    这是来黑 PHP 的吧
    Leiothrix
        41
    Leiothrix  
       2021-05-06 11:19:20 +08:00
    JavaScript 浅拷贝和深拷贝的区别,浅拷贝两个对象指向同一个地址,深拷贝是新开栈,两个对象指向不同的地址。可使用 JSON.parse(JSON.stringify(obj))进行深拷贝,修改后不会影响到原对象数据。
    ganbuliao
        42
    ganbuliao  
       2021-05-06 11:34:34 +08:00
    object 对象默认是引用 知道这个就清楚了
    est
        44
    est  
       2021-05-06 12:05:24 +08:00
    楼主低级黑
    zhuweiyou
        45
    zhuweiyou  
       2021-05-06 14:06:48 +08:00
    我感觉你在黑 PHP
    zhengfan2016
        46
    zhengfan2016  
       2021-05-06 15:13:59 +08:00
    为什么我看着觉得很正常,我第一门语言是 python,有没有老哥给我讲讲哪儿不正常 233
    IvanLi127
        47
    IvanLi127  
       2021-05-06 16:47:43 +08:00
    我记得 php 里也有引用传参啊,楼主用的啥版本的 php,代码放出来我们品品?
    MonkeyD1
        48
    MonkeyD1  
       2021-05-06 17:26:45 +08:00
    指针啊
    AoEiuV020
        49
    AoEiuV020  
       2021-05-06 17:29:13 +08:00
    深拷贝,浅拷贝,js 无关,一般都有这些区别,
    vueli
        50
    vueli  
       2021-05-06 17:40:12 +08:00
    前面的 = 是指向
    ruike007
        51
    ruike007  
       2021-05-06 17:42:53 +08:00
    这不是深浅拷贝的问题吗?基础啊,大哥
    karott7
        52
    karott7  
       2021-05-06 17:45:16 +08:00
    这不前端正常操作?赋值对象都是引用
    fescover
        53
    fescover  
       2021-05-06 17:54:43 +08:00
    正常操作,还有更 bt 的,猜猜下面输出什么
    NaN===NaN
    null===null
    null==NaN
    {}==={}
    []===[]
    ""===""
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1495 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:08 · PVG 01:08 · LAX 09:08 · JFK 12:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.