基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
当前回答
在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;
}
其他回答
基本体(数字、布尔值等)按值传递。字符串是不可变的,所以对它们来说并不重要。对象通过引用传递(引用通过值传递)。
语义!!设置具体的定义必然会使一些答案和注释不兼容,因为即使使用相同的单词和短语,它们也不会描述相同的内容,但克服这种困惑至关重要(尤其是对于新程序员)。
首先,并非每个人都能理解抽象的多个层次。学习过第四代或第五代语言的较新程序员可能很难围绕汇编语言或C语言程序员熟悉的概念进行思考,而不是通过指向指针的指针来实现。通过引用传递不仅仅意味着能够使用函数参数变量更改被引用对象。
变量:引用内存中特定位置值的符号的组合概念。在讨论细节时,这个术语通常太过沉重,不能单独使用。
符号:用于引用变量(即变量名称)的文本字符串。
值:存储在内存中并使用变量符号引用的特定位。
内存位置:存储变量值的位置。(位置本身由与存储在该位置的值不同的数字表示。)
函数参数:在函数定义中声明的变量,用于引用传递给函数的变量。
函数参数:调用方传递给函数的函数外部的变量。
对象变量:其基本基本值不是“对象”本身,而是指向内存中存储对象实际数据的另一个位置的指针(内存位置值)。在大多数更高一代语言中,“指针”方面通过在各种上下文中自动取消引用而被有效隐藏。
原始变量:其值为实际值的变量。即使这个概念也会因为各种语言的自动装箱和类似对象的上下文而变得复杂,但一般的想法是变量的值是由变量符号表示的实际值,而不是指向另一个内存位置的指针。
函数参数和参数不是一回事。此外,变量的值不是变量的对象(正如许多人已经指出的,但显然被忽略了)。这些区别对于正确理解至关重要。
通过值传递或通过共享调用(对于对象):函数参数的值被COPIED到另一个由函数参数符号引用的内存位置(无论它是在堆栈上还是在堆上)。换句话说,函数参数收到了传递参数值的副本。。。AND(关键)参数的值从不被调用函数更新/更改/更改。记住,对象变量的值不是对象本身,而是指向对象的指针,因此逐个传递对象变量会将指针复制到函数参数变量。函数参数的值指向内存中完全相同的对象。对象数据本身可以通过函数参数直接更改,但函数参数的值从未更新,因此在整个函数调用过程中,甚至在函数调用之后,它都将继续指向同一对象(即使其对象的数据已更改,或者如果函数参数被完全分配了不同的对象)。仅仅因为被引用的对象可通过函数参数变量更新,就断定函数参数是通过引用传递的,这是不正确的。
通过引用调用/传递:函数参数的值可以/将由相应的函数参数直接更新。如果有帮助,函数参数将成为参数的有效“别名”——它们有效地引用同一内存位置的相同值。如果函数参数是一个对象变量,则更改对象数据的能力与传递值情况没有区别,因为函数参数仍然指向与参数相同的对象。但是在对象变量的情况下,如果函数参数设置为完全不同的对象,那么参数同样也会指向不同的对象——这在传递值的情况下不会发生。
JavaScript不通过引用传递。如果仔细阅读,你会发现所有相反的意见都误解了传递值的含义,他们错误地得出结论:通过函数参数更新对象数据的能力与“传递值”同义。
对象克隆/复制:创建新对象并复制原始对象的数据。这可以是深层副本或浅层副本,但重点是创建了一个新对象。创建对象副本是与传递值不同的概念。有些语言区分类对象和结构(或类似的),并且可能有不同的行为来传递不同类型的变量。但是JavaScript在传递对象变量时不会自动执行类似的操作。但是,缺少自动对象克隆并不意味着通过引用传递。
“JavaScript:最终指南”一书的这一章对复制、传递和比较值和引用进行了非常详细的解释。
在我们离开主题之前操作对象和阵列参考,我们需要澄清一点术语。短语“路过”“引用”可以有几种含义。对一些读者来说,这个短语指的是一种函数调用技术允许函数分配新值它的论点,并拥有这些外部可见的修改值作用这不是术语的方式本书中使用了。这里,我们的意思是简单地说,对对象的引用或数组--而不是对象本身--传递给函数。A函数可以使用引用修改对象或元素的财产阵列的。但如果函数用对新对象或阵列的引用,该修改不可见在功能之外。读者熟悉这个词可能更喜欢这样说对象和数组值,但传递的值为实际上是一个参考,而不是对象本身。
我理解这一点的简单方法。。。
调用函数时,您将传递内容(引用或值),而不是变量本身。var var1=13;var var2={prop:2};//13和var2的内容(引用)正在此处传递foo(var1,var2);在函数内部,参数变量inVar1和inVar2接收传递的内容。函数foo(inVar1,inVar2){//更改inVar1和inVar2的内容不会影响外部变量inVar1=20;inVar2={prop:7};}由于inVar2收到了{prop:2}的引用,因此可以更改对象属性的值。函数foo(inVar1,inVar2){inVar2.prop=7;}
字符串、数字等基本类型变量始终作为传递按价值计算。基于这两个条件,数组和对象作为引用传递或值传递。如果要使用新的Object或array更改该Object或array的值,则它将通过value传递。object1={item:“car”};数组1=[1,2,3];此处是将新对象或数组分配给旧对象或数组。您没有更改属性的值旧对象的。因此它是按值传递的。如果要更改对象或数组的属性值,则会通过引用传递。object1.key1=“汽车”;阵列1[0]=9;此处您正在更改旧对象的属性值。您没有将新对象或数组分配给旧对象或数组。因此它是通过引用传递的。
Code
function passVar(object1, object2, number1) {
object1.key1= "laptop";
object2 = {
key2: "computer"
};
number1 = number1 + 1;
}
var object1 = {
key1: "car"
};
var object2 = {
key2: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1.key1);
console.log(object2.key2);
console.log(number1);
Output: -
laptop
bike
10