8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

JavaScript 是按引用传递语言还是按值传递语言?

mrSoh 2月前

175 0

基本类型(数字、字符串等)通过值传递。然而,对象是未知的,因为它们都可以通过值传递(在这种情况下,我们认为保存对象的变量是

基本类型(数字、字符串等)通过值传递。但对象是未知的,因为它们既可以通过值传递(在这种情况下,我们认为保存对象的变量是对象的引用),也可以通过引用传递(我们认为对象的变量保存对象本身)。

虽然最终这并不重要,但我想知道传递参数约定的正确方式是什么。是否有 JavaScript 规范摘录,其中定义了关于此的语义应该是什么?

帖子版权声明 1、本帖标题:JavaScript 是按引用传递语言还是按值传递语言?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由mrSoh在本站《arrays》版块原创发布, 转载请注明出处!
最新回复 (0)
  • function passByCopy ([...array], {...object})
    {
       console .log ("copied objects", array, object)
    }
    
    passByCopy ([1,2,3], {a:1, b:2, c:3})
    
    function passByReference (array, object)
    {
       console .log ("same objects", array, object)
    }
    
    passByReference ([1,2,3], {a:1, b:2, c:3})
    
  • 如果您想要像其他语言一样的(正常)函数参数行为(传递值的副本),那么只需在传递到函数之前克隆对象:

    function run()
    {
        var test = [];
        test.push(1);
    
        console.log('before: '+test); // 1
    
        changeVariable(_.clone(test)); // (Note: I am using lodash _.clone() function)
     
        console.log('after: '+test); // 1 
    }
    
    
    function changeVariable(test2) {
      var test1 = test2;
      test1.push(2); 
      console.log('inside func:', test1);  // inside func: [1,2]
    }   
    
    
    run();    
    
  • 这个答案实际上是错误的。JavaScript 不会进行这样的转换。在 JavaScript 中不可能通过引用传递。“通过引用传递”的全部意义在于让函数能够更改 myAge 的值。在 JavaScript 中你无法做到这一点。你可以更改对象 myAge 引用的属性,但不能更改 myAge 变量本身。这就是“通过引用传递”的意思,能够在函数外部更改变量的值。

  • 不,在 C++ 中不需要(或不允许)取消引用引用。要么是取消引用的指针,要么是未取消引用的引用。

  • Dewi 2月前 0 只看Ta
    引用 6

    在低级语言中,如果您想通过引用传递变量,则必须在创建函数时使用特定的语法:

    int myAge = 14;
    increaseAgeByRef(myAge);
    function increaseAgeByRef(int &age) {
      *age = *age + 1;
    }
    

    &age 对 的引用 myAge ,但如果您想要该值,则必须使用以下方法转换该引用 *age .

    JavaScript 是一种高级语言,可以为您完成这种转换。

    因此,尽管对象是通过引用传递的,但语言会将引用参数转换为值。您无需 & 在函数定义上使用 来通过引用传递它,也无需 * 在函数主体上使用 来将引用转换为值,JavaScript 会为您完成此操作。

    这就是为什么当您尝试通过替换其值(即)来更改函数内部的对象时, age = {value:5} 更改不会持久,但如果您更改其属性(即 age.value = 5 ),它就会持久。

    了解更多

  • 当我想将一个对象作为参数传入,该参数可以进行修改或完全替换时, 我发现 Underscore.js 库extend 方法

    function replaceOrModify(aObj) {
      if (modify) {
    
        aObj.setNewValue('foo');
    
      } else {
    
       var newObj = new MyObject();
       // _.extend(destination, *sources) 
       _.extend(newObj, aObj);
      }
    }
    
  • JavaScript 变量按值传递。例如:

    function process(a){
        a = 20
        console.log(a)
    }
    
    
    var a = 10
    
    process(a) // prints 20
    console.log(a) // print 10
    

    但是 javascript 对象是通过引用传递的。例如:

    function process(obj){
        obj.a = 'aa'
        console.log(obj)
    }
    
    let obj ={
        a: 'a_val',
        b: 'b_val'
    }
    
    process(obj)
    console.log(obj)
    

    输出:

     {a: 'aa', b: 'b_val' }
     { a: 'aa', b: 'b_val' }
    

    要将对象作为按值传递函数,可以使用扩展运算符,如下所示

    function process({...obj}){
        obj.a = 'aa'
        console.log(obj)
    }
    
    let obj ={
        a: 'a_val',
        b: 'b_val'
    }
    
    process(obj)
    console.log(obj)
    

    输出:

    { a: 'aa', b: 'b_val' }
    { a: 'a_val', b: 'b_val' }
    

    希望能够解释清楚。

  • 不,对象是否可变并不是真正的问题。一切都总是按值传递。这只取决于您传递的内容(值还是引用)。请参阅此内容。

  • Barbara Liskov 所说的 “通过共享呼叫” 的技术定义后,我才真正明白

    共享调用的语义与引用调用的不同之处在于,函数内对函数参数的赋值对调用者不可见(与引用语义不同)[需要引证],因此,例如,如果传递了一个变量,则无法在调用者的范围内模拟对该变量的赋值。但是,由于函数可以访问与调用者相同的对象(不进行复制),因此如果对象是可变的,则函数内对这些对象的改变对调用者是可见的,这似乎与值调用语义不同。函数内可变对象的改变对调用者是可见的,因为该对象不会被复制或克隆 — 它是共享的。

    也就是说,如果你访问参数值本身,参数引用是可以改变的。另一方面,对参数的赋值将在求值后消失,函数调用者无法访问。

  • 不,所有内容都是按值传递的。这只取决于您传递的内容(值还是引用)。请参阅此内容。

  • 我发现最简洁的解释是在 AirBNB 风格指南 :

    • p1

      • string
      • number
      • boolean
      • null
      • undefined

    例如:

    var foo = 1,
        bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
    
    • p3

      • object
      • array
      • function

    例如:

    var foo = [1, 2],
        bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9
    

    即,实际上原始类型是通过值传递的,而复杂类型是通过引用传递的。

  • 引用提问者的话:

    原始类型(数字、字符串等)通过值传递,但对象 [...$ 既可以按值传递(在这种情况下,我们认为保存对象的变量实际上是对该对象的引用),也可以按引用传递(当我们认为对象的变量保存对象本身时)。

    事实并非如此。对象作为参数传递的方式只有一种。尽管其他答案也区分了原始值和非原始值,但这是一种干扰,而且无关紧要。

    无引用传递

    考虑一下此代码,它不关心其是否 a 是原始类型还是对象:

    function alter(arg) {  /* some magic happening here to `arg` */ }
    
    function main() {
        var a, b;
        a = b = { x: 1 }; // Example value. It can be an object or primitive: irrelevant here
        console.log(a === b); // true
        alter(a);
        console.log(a === b); // false? (not possible)
    }
    

    如果函数 alter 有某种方式来实现第二个输出 false , ,那么 我们可以说这是按引用传递的,因为 then arg 别名 a 。但这在 JavaScript 中是不可能的。原始的概念与此无关:JavaScript 中没有按引用传递。

    对象

    在 JavaScript 中,对象是 引用 。当使用对象作为参数调用函数时,这 不会创建新的属性集合 。函数的参数变量(局部变量)将接收相同的值(即 对属性集合的 引用

    变量赋值与对象变异

    调用者的数据结构可能会发生变化,也可以通过函数调用进行。这显然只适用于 可变 值(根据定义),在 JavaScript 中,这是通过为属性赋值来实现的需要区分两件事:

    • 对对象属性的赋值 会改变 调用者和被调用者都引用的对象。
    • 赋值给参数变量不会 改变 调用者的数据。具体来说,如果该参数变量是一个对象(引用),则该引用会被覆盖,因此函数会将 自身与调用者的数据 分离
  • 规范中的引用与所讨论的行为无关。它是一个中间构造,用于解释为什么 ab = 1 能够知道属性 (b) 设置在哪个对象 (a) 上(因为 ab 计算为引用 { a, \'b\' })。

  • 我一直对很多人对按值传递的参数、按引用传递的参数、对整个对象的操作以及对其属性的操作之间的区别感到困惑而感到惊讶。1979 年,我没有获得计算机科学学位,而是选择在我的 MBA 课程中增加 15 小时左右的计算机科学选修课。尽管如此,我很快就意识到,我对这些概念的掌握至少与任何拥有计算机科学或数学学位的同事一样好。学习一下 Assembler,你就会明白了。

  • 对于编程语言律师,我已经阅读了 ECMAScript 5.1(比最新版本更容易阅读)的以下部分,甚至 在 ECMAScript 邮件列表中 询问

    TL;DR :所有东西都是通过值传递的,但是对象的属性是引用,而对象(Object)的定义在标准中却非常缺乏。

    参数列表的构造

    第 11.2.4 节“参数列表”说明了如何生成仅由 1 个参数组成的参数列表:

    生产的 ArgumentList : AssignmentExpression 评估如下:

    1. 让 ref 成为评估 AssignmentExpression 的结果。
    2. 让 arg 成为 GetValue(ref)。
    3. 返回唯一项目为 arg 的列表。

    本节还列举了参数列表中有 0 个或 >1 个参数的情况。

    因此,一切都是通过引用传递的。

    访问对象属性

    第 11.2.1 节“属性访问器”

    产生式 MemberExpression : MemberExpression [ Expression ] 的求值如下:

    1. 让 baseReference 成为评估 MemberExpression 的结果。
    2. 令 baseValue 为 GetValue(baseReference)。
    3. 让 propertyNameReference 成为评估 Expression 的结果。
    4. 让 propertyNameValue 为 GetValue(propertyNameReference)。
    5. 调用 CheckObjectCoercible(baseValue)。
    6. 让 propertyNameString 成为 ToString(propertyNameValue)。
    7. 如果正在评估的句法产生式包含在严格模式代码中,则让 strict 为真,否则让 strict 为假。
    8. 返回一个 Reference 类型的值 ,其基值为 baseValue ,引用名称为 propertyNameString ,且严格模式标志为 strict。

    因此,对象的属性始终可作为参考。

    关于参考

    第 8.7 节“引用规范类型”中描述了引用不是语言中的真实类型 - 它们仅用于描述 delete、typeof 和赋值运算符的行为。

    \'对象\' 的定义

    5.1 版中定义“对象是属性的集合”。因此,我们可以推断,对象的值是集合,但至于集合的值是什么,规范中定义不明确,需要花点 功夫 才能理解。

  • 引用 17

    @DanailNachev:虽然从技术上来说这可能确实如此,但这种差异只对可变对象有影响,而 ECMAScript 原语则没有。

  • zwb8 2月前 0 只看Ta
    引用 18

    我认为在 JavaScript 中情况并非如此:```javascript var num = 5;

  • 在 JavaScript 中向函数传递参数类似于在 C 中通过指针值传递参数:

    /*
    The following C program demonstrates how arguments
    to JavaScript functions are passed in a way analogous
    to pass-by-pointer-value in C. The original JavaScript
    test case by @Shog9 follows with the translation of
    the code into C. This should make things clear to
    those transitioning from C to JavaScript.
    
    function changeStuff(num, obj1, obj2)
    {
        num = num * 10;
        obj1.item = "changed";
        obj2 = {item: "changed"};
    }
    
    var num = 10;
    var obj1 = {item: "unchanged"};
    var obj2 = {item: "unchanged"};
    changeStuff(num, obj1, obj2);
    console.log(num);
    console.log(obj1.item);    
    console.log(obj2.item);
    
    This produces the output:
    
    10
    changed
    unchanged
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    struct obj {
        char *item;
    };
    
    void changeStuff(int *num, struct obj *obj1, struct obj *obj2)
    {
        // make pointer point to a new memory location
        // holding the new integer value
        int *old_num = num;
        num = malloc(sizeof(int));
        *num = *old_num * 10;
        // make property of structure pointed to by pointer
        // point to the new value
        obj1->item = "changed";
        // make pointer point to a new memory location
        // holding the new structure value
        obj2 = malloc(sizeof(struct obj));
        obj2->item = "changed";
        free(num); // end of scope
        free(obj2); // end of scope
    }
    
    int num = 10;
    struct obj obj1 = { "unchanged" };
    struct obj obj2 = { "unchanged" };
    
    int main()
    {
        // pass pointers by value: the pointers
        // will be copied into the argument list
        // of the called function and the copied
        // pointers will point to the same values
        // as the original pointers
        changeStuff(&num, &obj1, &obj2);
        printf("%d\n", num);
        puts(obj1.item);
        puts(obj2.item);
        return 0;
    }
    
  • “在我的书中,这被称为通过引用传递。”——在每一本编译器书籍、解释器书籍、编程语言理论书籍和计算机科学书籍中,这都不是。

返回
作者最近主题: