2014-12-07 2 views
7

В приведенном ниже коде мы передаем объект. Итак, согласно javascript, мы передаем ссылку и манипулируем.Javascript - primitive vs reference types

var a = new Number(10); 
x(a); 
alert(a); 

function x(n) { 
n = n + 2; 
} 

Но 10 предупреждений вместо 12. Почему?

+0

Этот ответ может помочь вам понять «пройти по ссылке» в JavaScript http://stackoverflow.com/a/7744623/1793653 – shree33

ответ

10

n является местным по отношению к x и вначале он имеет то же значение, что и глобальный a. Правая сторона n + 2 затем оценивается как число (примитив). Левая часть задания, n, никогда не оценивается, - это всего лишь идентификатор. Поэтому наша локальная переменная теперь установлена ​​на примитивное значение правой стороны. Значение, на которое ссылается a, фактически не изменяется. См

var a = new Number(10); 
x(a); 
alert(a); // 10 

function x(n) { 
    alert(typeof n); // object 
    n = n + 2; 
    alert(typeof n); // number 
} 
0
var a = new Number(10);  
x(a); 
alert(a); 

function x(n) { 
    n = n + 2; // NOT VALID as this would essentially mean 10 = 10 + 2 since you are passing the 'value' of a and not 'a' itself 
} 

Вы должны написать следующее, чтобы получить его работу

var a = new Number(10); 
x(a); 
alert(a); 

function x(n) { 
    a = n + 2; // reassign value of 'a' equal to the value passed into the function plus 2 
} 
+1

Я не ищу рабочий код. Ваш первый набор объяснений «10 = 10 + 2» неверен. –

+0

Это уравнение недействительно. Поскольку левая сторона - это * номер *. – Anubhav

+0

Нет, его объект –

0

JavaScript мимолетный параметр работает аналогично Java. Отдельные значения передаются по значению, но атрибуты объекта передаются по ссылке через их значения указателя. Само по себе значение не будет изменено в функции, но атрибуты объекта будут изменены.

Рассмотрим следующий код:

function doThis(param1, param2) { 
    param1++; 
    if(param2 && param2.value) { 
     param2.value++; 
    } 
} 

var initialValue = 2; 
var initialObject = {value: 2}; 

doThis(initialValue, initialObject); 

alert(initialValue); //2 
alert(initialObject.value); //3 

http://jsfiddle.net/bfm01b4x/

+0

Объекты Java (и JS) передаются по имени (ссылка на объект передается по значению). Аргументы объекта (а не атрибуты) не передаются по ссылке. Терминология имеет значение. «attribute» в java имеет конкретное значение, которое отличается от «поля» - см. https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7 –

2

Позвольте мне попытаться ответить на него с примерами:

function modify(obj) { 
    // modifying the object itself 
    // though the object was passed as reference 
    // it behaves as pass by value 
    obj = {c:3}; 
} 

var a = {b:2} 
modify(a); 
console.log(a) 
// Object {b: 2} 

function increment(obj) { 
    // modifying the value of an attribute 
    // working on the same reference 
    obj.b = obj.b + 1; 
} 

var a = {b:2} 
increment(a); 
console.log(a) 
// Object {b: 3} 

function augument(obj) { 
    // augument an attribute 
    // working on the same reference 
    obj.c = 3; 
} 

var a = {b:2} 
augument(a); 
console.log(a) 
// Object {b: 2, c: 3} 

Пожалуйста, обратитесь JSFiddle для работы демо.

4

Когда вы вычисляете

n + 2 

это приводит к новому «родному числу», даже если n действительно экземпляр по Number объекту.

Присвоение n затем просто изменяет локальную переменную n и не изменяет экземпляр объекта Number. Вы можете видеть, что с

n = new Number(10); 
console.log(typeof n);  // ---> "object" 
console.log(n + 2);  // ---> 12 
console.log(typeof (n+2)); // ---> "number" 
n = n + 2; 
console.log(typeof n);  // ---> "number" 

В JavaScript (или Python или Lisp) нет никакого способа, чтобы пройти «адрес» переменной, так что вызываемая функция мутирует его. Единственным, что вы можете сделать, это пропускание функции сеттера ... например:

function foo(setter) { 
    setter(42); 
} 

funciton bar() { 
    var x = 12; 
    foo(function(newx){x = newx;}); 
    console.log(x); // ---> 42 
} 
+0

Так цифры являются непреложными? Если 'x = new Number (5)' или 'x = 5', нет операции, так что' x' поддерживает одну и ту же ссылку, но имеет другое значение. Когда я делаю 'console.log (новый номер (5))' он дает 'Number {[[PrimitiveValue]]: 5}'. Но я предполагаю, что вы не можете мутировать этот «[[PrimitiveValue]]», верно? – soktinpk

+0

@soktinpk: да, число строк неизменно в Javascript. Однако вы можете создать объект с помощью метода 'valueOf()', который может вести себя как число в математических выражениях, но с измененным состоянием, которым вы можете управлять. – 6502

2

ответ довольно просто: потому, что ECMAScript является передача по значению и не проход по ссылке, и вашим код доказывает это. (Точнее, это передача по отдельности, которая является определенным видом передачи по значению.)

См. Is JavaScript a pass-by-reference or pass-by-value language? для получения дополнительной информации.

ECMAScript использует pass-by-value, или, точнее, частный случай pass-by-value, где переданное значение равно всегда указатель. Этот специальный случай также иногда называют совместным использованием вызовов, совместным использованием вызовов по вызову или позором.

Это то же соглашение, что и Java (для объектов), C# (по умолчанию для ссылочных типов), Smalltalk, Python, Ruby и более или менее каждый объектно-ориентированный язык, когда-либо созданный.

Примечания: некоторые типы (например) Number с фактически передаваемыми непосредственно по значению и не с посредническим указателем. Однако, поскольку они неизменяемы, в этом случае не наблюдается наблюдаемой поведенческой разницы между передачей по значению и совместным использованием вызова по объекту, поэтому вы можете значительно упростить свою ментальную модель, просто обработав все как вызов по-умолчанию, объект совместного пользования. Просто интерпретируйте эти особые случаи как внутреннюю оптимизацию компилятора, о которой вам не нужно беспокоиться.

Вот простой пример, который вы можете запустить, чтобы определить аргумент прохождения конвенции о ECMAScript (или любой другой язык, после перевода его):

function isEcmascriptPassByValue(foo) { 
 
    foo.push('More precisely, it is call-by-object-sharing!'); 
 
    foo = 'No, ECMAScript is pass-by-reference.'; 
 
    return; 
 
} 
 

 
var bar = ['Yes, of course, ECMAScript *is* pass-by-value!']; 
 

 
isEcmascriptPassByValue(bar); 
 

 
console.log(bar); 
 
// Yes, of course, ECMAScript *is* pass-by-value!, 
 
// More precisely, it is call-by-object-sharing!

Если вы знакомы с C# , это очень хороший способ понять различия между передачей по значению и передачей по ссылке для типов значений и ссылочных типов, поскольку C# поддерживает все 4 комбинации: pass-by-value для типов значений («традиционный pass- по-значение "), пошаговые значения для ссылочных типов (совместное использование вызовов, вызов по объекту, обмен вызовами по-объектам, как в ECMAScript), пошаговые ссылки для ссылочных типов и пошаговые ссылки для типов значений.

(На самом деле, даже если вы не знаю C#, это не слишком трудно следовать.)

struct MutableCell 
{ 
    public string value; 
} 

class Program 
{ 
    static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux) 
    { 
     foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value."; 
     foo = new string[] { "C# is not pass-by-reference." }; 

     bar.value = "For value types, it is *not* call-by-sharing."; 
     bar = new MutableCell { value = "And also not pass-by-reference." }; 

     baz = "It also supports pass-by-reference if explicitly requested."; 

     qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." }; 
    } 

    static void Main(string[] args) 
    { 
     var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" }; 

     var corge = new MutableCell { value = "For value types it is pure pass-by-value." }; 

     var grault = "This string will vanish because of pass-by-reference."; 

     var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." }; 

     IsCSharpPassByValue(quux, corge, ref grault, ref garply); 

     Console.WriteLine(quux[0]); 
     // More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value. 

     Console.WriteLine(corge.value); 
     // For value types it is pure pass-by-value. 

     Console.WriteLine(grault); 
     // It also supports pass-by-reference if explicitly requested. 

     Console.WriteLine(garply.value); 
     // Pass-by-reference is supported for value types as well. 
    } 
}