原始类型(例如数字、字符串等)通过值传递,但对象不同,因为它们既可以按值传递(在这种情况下,我们认为保存对象的变量实际上是对该对象的引用),也可以按引用传递(当我们认为变量对对象本身持有该对象时)。
虽然最终并不重要,但我想知道呈现参数传递约定的正确方式是什么。是否有来自JavaScript规范的节选,定义了关于此事应该是什么语义?
原始类型(例如数字、字符串等)通过值传递,但对象不同,因为它们既可以按值传递(在这种情况下,我们认为保存对象的变量实际上是对该对象的引用),也可以按引用传递(当我们认为变量对对象本身持有该对象时)。
虽然最终并不重要,但我想知道呈现参数传递约定的正确方式是什么。是否有来自JavaScript规范的节选,定义了关于此事应该是什么语义?
这篇文章讲的是编程语言中的“性能”、“速度”和简单来说就是“内存管理”。在javascript中,我们可以将值分为两种类型:类型1——对象
和类型2——所有其他类型的值,例如字符串
、布尔类型
等。
如果你将内存想象成下面这个方格图,其中每个方格只能保存一个类型2的值:
每个类型2的值(绿色)都是一个单独的方格,而类型1的值(蓝色)则是由一组方格组成的:
重点是,如果要表示类型2的值,地址是明确的,但如果要对类型1的值做同样的事情,则非常困难!:
更复杂的情况是:
虽然这里的绿色箭头是一个典型的变量,而紫色箭头是一个对象变量,但因为绿色箭头(典型变量)只有一个任务(即指示典型值),所以我们不需要将其值与箭头分开,而是将其与值一起移动到任何位置,并在所有赋值、函数等中使用。
但是我们不能对紫色箭头做同样的事情,我们可能想要移动“约翰”单元格或许多其他东西,所以紫色箭头将固定在其位置上,只有被分配给它的典型箭头会移动...
一个非常令人困惑的情况是你无法意识到你的引用变量如何改变,让我们看一个很好的例子:
let arr = [1, 2, 3, 4, 5]; //arr is an object now and a purple arrow is indicating it
let obj2 = arr; // now, obj2 is another purple arrow that is indicating the value of arr obj
let obj3 = ['a', 'b', 'c'];
obj2.push(6); // first pic below - making a new hand for the blue circle to point the 6
//obj2 = [1, 2, 3, 4, 5, 6]
//arr = [1, 2, 3, 4, 5, 6]
//we changed the blue circle object value (type1-value) and due to arr and obj2 are indicating that so both of them changed
obj2 = obj3; //next pic below - changing the direction of obj2 array from blue circle to orange circle so obj2 is no more [1,2,3,4,5,6] and it's no more about changing anything in it but we completely changed its direction and now obj2 is pointing to obj3
//obj2 = ['a', 'b', 'c'];
//obj3 = ['a', 'b', 'c'];
这是关于按值传递和按引用传递(JavaScript)的进一步解释。在这个概念中,它们谈论的是通过引用传递变量和通过值传递变量。
按值传递(基本类型)
var a = 3;
var b = a;
console.log(a); // a = 3
console.log(b); // b = 3
a=4;
console.log(a); // a = 4
console.log(b); // b = 3
按引用传递(对象)
var c = { "name" : "john" };
var d = c;
console.log(c); // { "name" : "john" }
console.log(d); // { "name" : "john" }
c.name = "doe";
console.log(c); // { "name" : "doe" }
console.log(d); // { "name" : "doe" }
c
,并指向某个内存地址,比如(0x012)。d
指向相同的位置(0x012)。特殊情况,按引用传递(对象)
c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }
所有东西都是按值传递的。
基本类型是按值传递的(即实际变量值的新副本被传递到函数中)。
复杂类型(对象)作为“指向对象的指针”传递。因此,您传递的实际内容是一个指针,该指针按值传递(它是一个地址,像任何其他数字值一样)。显然,如果您尝试在函数内部修改对象的属性,则修改将反映在函数之外。这是因为您通过指向唯一属性副本的指针访问属性。
“按值传递指针”和“按引用传递对象”是相同的。
按值传递或按共享调用(针对对象):函数参数的值被复制到另一个内存位置,该位置由函数的参数符号引用(无论它是在堆栈还是堆上)。换句话说,函数参数接收了传递参数值的副本...并且(关键是)调用函数永远不会更新/更改/改变参数的值。请记住,对象变量的值不是对象本身,而是指向对象的指针,因此通过按值传递对象变量会将指针复制到函数参数变量中。函数参数的值指向完全相同的内存中的对象。可以直接通过函数参数修改对象数据,但是函数参数的值永远不会更新,因此即使在函数调用期间和之后(即使其对象数据已更改或如果函数参数分配了完全不同的对象),它仍将继续指向相同的对象。错误的结论是函数参数是按引用传递的,只是因为通过函数参数变量可以更新所引用的对象。
调用/按引用传递:函数参数的值可以/将直接由相应的函数参数更新。如果有帮助,函数参数将成为参数的有效“别名”-它们有效地引用相同的值在同一内存位置。如果函数参数是对象变量,则更改对象数据的能力与按值传递情况没有区别,因为函数参数仍将指向与参数相同的对象。但在对象变量情况下,如果将函数参数设置为完全不同的对象,则参数也将指向不同的对象-这在按值传递情况下不会发生。
JavaScript不是按引用传递的。如果您仔细阅读,您将意识到所有相反的观点都误解了按值传递的含义,并错误地得出结论,通过函数参数变量更新对象数据的能力等同于“按值传递”。
对象克隆/复制:创建一个新对象并复制原始对象的数据。这可以是深层复制或浅层复制,但重点是创建了一个新对象。创建对象副本是与按值传递分开的概念。一些语言区分类对象和结构体(或类似物),并且可能对不同类型的变量传递具有不同的行为。但是,当传递对象变量时,JavaScript不会自动执行任何此类操作。但是,缺少自动对象克隆并不等同于按引用传递。
分享我对JavaScript中引用的了解
在JavaScript中,当将一个对象赋给一个变量时,被赋值的变量实际上是指向该对象的引用:
var a = {
a: 1,
b: 2,
c: 3
};
var b = a;
// b.c is referencing to a.c value
console.log(b.c) // Output: 3
// Changing value of b.c
b.c = 4
// Also changes the value of a.c
console.log(a.c) // Output: 4
let a = { prop: 1 };
let b = a; // a and b hold the same value
a.prop = "test"; // The object gets mutated, can be observed through both a and b
b = { prop: 2 }; // b holds now a different value
现在,人们经常无休止地争论Java等语言实际上是否正确描述了"按引用传递"。重点在于:
- 传递对象不会复制该对象。
- 传递给函数的对象可以被函数修改其成员。
- 传递给函数的原始值不能被函数修改,需要进行复制。
在我的书里,这被称为按引用传递。
这里有一篇反驳文章:
我理解这个的简单方法是...
When calling a function, you are passing the content (reference or value) of the argument variables, not the the variables themselves.
var var1 = 13;
var var2 = { prop: 2 };
//13 and var2's content (reference) are being passed here
foo(var1, var2);
Inside the function, parameter variables, inVar1
and inVar2
, receive the contents being passed.
function foo(inVar1, inVar2){
//changing contents of inVar1 and inVar2 won't affect variables outside
inVar1 = 20;
inVar2 = { prop: 7 };
}
Since inVar2
received the reference of { prop: 2 }
, you can change the value of the object's property.
function foo(inVar1, inVar2){
inVar2.prop = 7;
}
/*
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;
}
var num = 5;
- Danail Nachev
var x=3, y=x; f(x); alert(y === x);
,那么函数f()
可以使得alert
报告false
而不是true
。在JavaScript中,这是不可能的,所以它不是“按引用传递”。能够传递可修改对象的引用是好的,但这并不是“按引用传递”的意思。就像我说的,术语混淆真是令人遗憾。 - Pointy