javascript中的作用域
对象及其引用在javascript中传递。这意味着任何地方的物体变化都应该得到反映。 在本例中,console.log(a)的预期输出为{} 这里发生了什么?据我所知,这不应该是因为功能范围。javascript中的作用域,javascript,function,scope,pass-by-reference,Javascript,Function,Scope,Pass By Reference,对象及其引用在javascript中传递。这意味着任何地方的物体变化都应该得到反映。 在本例中,console.log(a)的预期输出为{} 这里发生了什么?据我所知,这不应该是因为功能范围。 谢谢函数上下文中的变量“a”与函数外部的变量“a”不同。此代码在语义上与您的代码等效: function change(foo,bar) { foo.x = 'added'; foo = bar;//assigning foo as {} to bar } a={} b={} change
谢谢函数上下文中的变量“a”与函数外部的变量“a”不同。此代码在语义上与您的代码等效:
function change(foo,bar) {
foo.x = 'added';
foo = bar;//assigning foo as {} to bar
}
a={}
b={}
change(a,b);
console.log(a); //expected {} but output {x:'added'}
console.log(b)
很明显,在这种情况下,“foo”变量只存在于函数内部,而doing
foo=bar
不会因为引用是通过值传递的而改变a
。对象是通过引用传递的,对函数中对象所做的任何更改都会反映在任何地方。这就是为什么在函数中添加x
属性会修改函数外部的对象
您缺少的是行a=b代码>不修改对象,它修改对象的引用。如果需要设置引用,可以在另一个容器对象/数组中传递这两个对象:
function change(container) {
container.a.x = 'added';
container.a = container.b;//assigning a as {} to b
}
var container = { a: {}, b: {}};
change(container);
console.log(container.a);
console.log(container.b)
如果您添加了另一行,您可以更清楚地了解正在发生的事情:
function change(a,b) {
a.x = 'added';
a = b;
a.x = 'added as well';
};
a={};
b={};
change(a,b);
console.log(a); //{x:'added'}
console.log(b); //{x:'added as well'}
当您执行a=b
操作时,您正在将局部变量a
分配给b
所持有的引用。这将有助于解决您的问题:
var obj = {}, anotherObj = {};
// in case if they are not global, make them global or define parent scope to be able to modify inside the function
window.obj = obj;
window.anotherObj = anotherObj;
function swap(a, b) {
window[a].newProp = 'XYZ';
window[a] = window[b]; // now obj is gone, because replaced with anotherObj
}
swap('obj','anotherObj');
console.log(obj); // now it would give Object {}
好的,您已经发现JavaScript对象具有引用语义,因此修改referent会对原始范围内的同一对象产生影响
你还需要意识到,=
不是这些规则的一部分;它不仅执行赋值,还将引用重新绑定到新对象
在引擎盖下,可以说,这就是你最初引用的基本形成方式
对象及其引用在javascript中传递
不,他们不是。ECMAScript/JavaScript严格按值传递。(更准确地说,是通过共享调用,这是通过值传递的特殊情况。)
这里发生了什么
这只是正常的传递值
您的困惑源于您错误地认为ECMAScript/JavaScript是通过引用传递的,而实际上不是
ECMAScript使用按值传递,或者更准确地说,是按值传递的一种特殊情况,其中传递的值始终是指针。这种特殊情况有时也称为按共享调用、按对象调用共享或按对象调用
这与Java(用于对象)、C#(默认情况下用于引用类型)、Smalltalk、Python、Ruby以及几乎所有创建的面向对象语言所使用的约定相同
注意:某些类型(例如,Number
s)实际上是通过值直接传递的,而不是通过中间指针。然而,由于这些是不可变的,在这种情况下,传递值和按对象调用共享之间没有明显的行为差异,因此您可以通过简单地将所有内容视为按对象调用共享来大大简化您的心智模型。只需将这些特殊情况解释为不需要担心的内部编译器优化
下面是一个简单的示例,您可以运行它来确定ECMAScript(或任何其他语言,在翻译后)的参数传递约定:
函数isEcmascriptPassByValue(foo){
push('更准确地说,它是由对象共享调用的!');
foo='否,ECMAScript是通过引用传递的。';
返回;
}
var bar=[“是的,当然,ECMAScript*是*传递值!”;
isEcmascriptPassByValue(bar);
控制台日志(bar);
//当然,ECMAScript*是*按值传递!,
//更准确地说,它是由对象共享调用的代码>对象引用作为功能参数传递。因此,无论您在函数中做了什么更改,它都会影响实际对象。@VigneswaranMarimuthu所以输出应该是{x:'added'},对吗?但这里的情况并非如此,在函数内将b
赋值给a
没有任何效果,因为函数范围内的a
与全局范围内的a
是不同的变量。我喜欢你说你知道对象是通过引用传递的,然后对对象是通过引用传递表示极大的震惊和惊讶。这只是混淆,因为函数参数中的变量与全局变量使用相同的名称。如果函数参数名是foo
和bar
,那么可能更容易理解为什么它会这样工作。是的,谢谢你这个例子,尼古拉的回答实际上解决了我的问题。这真是一个令人费解的问题。用几行代码很好的解释!我认为这需要太多的行动。看看我的,但是对象不是通过引用传递的<代码>a=b
仅修改本地引用(变量)!“对象是通过引用传递的,这是对的”——不,它们不是。JavaScript严格按值传递,OP的代码很好地证明了这一点。如果JavaScript是通过引用传递的,OP的代码将起作用,他一开始就不会问这个问题。我在Java世界中熟悉的术语,我认为也适用于这里,是通过引用的副本传递。@Bergi:这个链接就是答案:)它准确地解释了OP的问题。这个人明白了<代码>函数更改(a,b)
创建局部变量a和b,因此赋值a=b
分配给局部变量a,而不是全局变量。换言之:foo
保存对a
也引用的对象的引用foo
不是对a
的引用。我看不出你的答案与这个问题有什么关系。您的代码所显示的是,即使对象和数组也不是通过引用传递的(如果是,您就不需要那个“范围”)。@Bergi这个想法与Nikola的答案相同。唯一的区别是容器是wi
var obj = {}, anotherObj = {};
// in case if they are not global, make them global or define parent scope to be able to modify inside the function
window.obj = obj;
window.anotherObj = anotherObj;
function swap(a, b) {
window[a].newProp = 'XYZ';
window[a] = window[b]; // now obj is gone, because replaced with anotherObj
}
swap('obj','anotherObj');
console.log(obj); // now it would give Object {}