Почему этот объект не передается по ссылке при назначении ему чего-то еще?
Я знаю, что в JS объекты передаются по ссылке, например:
function test(obj) {
obj.name = 'new name';
}
var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // new name
Но почему не работает ниже:
function test(obj) {
obj = {};
}
var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // foo
Я установил объект в {}
(пустой), но он все еще говорит foo
.
Может ли кто-нибудь объяснить логику этого?
Ответы
Ответ 1
Если вы знакомы с указателями, то аналогию вы можете взять. Вы фактически передаете указатель, поэтому obj.someProperty
будет разыменовывать это свойство и фактически переопределить это, в то время как просто переопределение obj
уничтожит указатель и не перезапишет объект.
Ответ 2
Поскольку JavaScript фактически передает объекты по пропуску copy -reference.
Когда вы передаете my_obj
в свою test
функцию, передается копия ссылки на этот объект. В результате при повторном назначении объекта в test
, вы действительно только перенаправляете копию ссылки на исходный объект; ваш оригинальный my_obj
остается неизменным.
Ответ 3
Потому что вы переписываете ссылку, а не объект.
// Create a new object and assign a reference to it
// to the variable my_obj
var my_obj = { name: 'foo' };
// Pass the reference to the test function
test(my_obj);
// Assign the reference to a variable called obj
// (since that is the first argument)
function test(obj) {
// Create a new (empty) object and assign a reference to it to obj
// This replaces the existing REFERENCE
obj = {};
}
// my_obj still has a reference to the original object,
// because my_obj wasn't overwritten
alert(my_obj.name); // foo
Ответ 4
Javascript не имеет поддержки для передачи по ссылке (хотя объекты передаются по ссылке и эта ссылка поддерживается до тех пор, пока она не перезаписана присвоением, например, с помощью =
), но вы можете имитировать ref
ключевое слово С#, используя следующий метод:
function test(obj) {
obj.Value = {};
//obj.Value = {name:"changed"};
}
var my_obj = { name: 'foo' };
(function ()
{
my_obj = {Value: my_obj};
var $return = test(my_obj);
my_obj = my_obj.Value;
return $return;
}).call(this);
alert(my_obj.name); // undefined, as expected
// In the question this returns "foo" because
// assignment causes dereference
Конечно, вы можете использовать глобальные функции и функцию вызова без аргументов, и в этом случае ссылки не пропущены следующим образом:
var obj = { name: 'foo' };
function test() {
obj = {};
}
test();
alert(obj.name); // undefined
Если у вас есть весь код в закрытии, тогда все проще и выше, как глобальные глобальные пространства имен не загрязняют:
(function(){
var obj = { name: 'foo' };
function test() {
obj = {};
}
test();
alert(obj.name); // undefined
}).call(this);
Вышеупомянутые "глобалы внутри закрытия" -техника хороши, если вам нужно перенести в Javascript некоторый код С# с аргументами ref
. Например. Следующий код С#:
void MainLoop()
{
// ...
MyStruct pt1 = CreateMyStruct(1);
MyStruct pt2 = CreateMyStruct(2);
SwapPoints(ref pt1, ref pt2);
// ...
}
void SwapPoints(ref MyStruct pt1, ref MyStruct pt2)
{
MyStruct tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
можно портировать на Javascript, используя что-то вроде:
(function(){
var pt1, pt2;
function CreateMyStruct(myvar)
{
return {"myvar":myvar}
}
function MainLoop()
{
// ...
pt1 = CreateMyStruct(1);
pt2 = CreateMyStruct(2);
console.log("ORIG:",pt1,pt2);
SwapPoints();
console.log("SWAPPED:",pt1,pt2);
// ...
}
function SwapPoints()
{
var tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
MainLoop();
}).call(this);
или если необходимо использовать локальные переменные и аргументы функции, тогда решение может быть основано на первом примере моего ответа следующим образом:
(function(){
function CreateMyStruct(myvar)
{
return {"myvar":myvar}
}
function MainLoop()
{
// ...
var pt1 = CreateMyStruct(1);
var pt2 = CreateMyStruct(2);
console.log("ORIG:",pt1,pt2);
(function ()
{
pt1 = {Value: pt1};
pt2 = {Value: pt2};
var $return = SwapPoints(pt1, pt2);
pt1 = pt1.Value;
pt2 = pt2.Value;
return $return;
}).call(this);
console.log("SWAPPED:",pt1,pt2);
// ...
}
function SwapPoints(pt1, pt2)
{
var tmp = pt1.Value;
pt1.Value = pt2.Value;
pt2.Value = tmp;
}
MainLoop();
}).call(this);
Действительно, нужно сказать, что Javascript не хватает, когда у него нет родного ref
! Код будет намного проще.