Javascript по ссылке или по значению

Я ищу хороший хороший материал для чтения, когда Javascript передает что-то по значению и когда по ссылке и когда изменение переданного элемента влияет на значение вне функции, а когда нет. Меня также интересует, когда присвоение другой переменной осуществляется по ссылке или по значению, и следует ли это за любыми разными правилами, кроме передачи в качестве параметра функции.

Я много раз искал и нашел множество конкретных примеров (многие из них здесь, на SO), из которых я могу начать собирать кусочки реальных правил, но я еще не нашел ни одного, ну написанный документ, который описывает все это.

Кроме того, существуют ли способы в языке контролировать, передается ли что-либо по ссылке или по значению?

Вот некоторые из типов вопросов, которые я хочу понять. Это всего лишь примеры - я на самом деле хочу понять правила, на которых идет речь, а не только ответы на конкретные примеры. Но вот несколько примеров:

function f(a,b,c) {
   a = 3;
   b.push("foo");
   c.first = false;
}

var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);

Когда содержимое x, y и z изменено вне области f для всех разных типов?

function f() {
    var a = ["1", "2", "3"];
    var b = a[1];
    a[1] = "4";
    // what is the value of b now for all possible data types that the array in "a" might hold?
}

function f() {
    var a = [{yellow: "blue"}, {red: "cyan"}, {green: "magenta"}];
    var b = a[1];
    a[1].red = "tan";
    // what is the value of b now and why?
    b.red = "black";
    // did the value of a[1].red change when I assigned to b.red?
}

Если я хочу сделать полностью независимую копию объекта (без каких-либо ссылок), какой способ лучше всего это сделать?

Ответ 1

Я понимаю, что это на самом деле очень просто:

  • Javascript всегда передается по значению, но когда переменная ссылается на объект (включая массивы), "значение" является ссылкой на объект.
  • Изменение значения переменной никогда не изменяет базовый примитив или объект, оно просто указывает переменную на новый примитив или объект.
  • Однако изменение свойства объекта, на которое ссылается переменная, изменяет базовый объект.

Итак, для работы с некоторыми из ваших примеров:

function f(a,b,c) {
    // Argument a is re-assigned to a new value.
    // The object or primitive referenced by the original a is unchanged.
    a = 3;
    // Calling b.push changes its properties - it adds
    // a new property b[b.length] with the value "foo".
    // So the object referenced by b has been changed.
    b.push("foo");
    // The "first" property of argument c has been changed.
    // So the object referenced by c has been changed (unless c is a primitive)
    c.first = false;
}

var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
console.log(x, y, z.first); // 4, ["eeny", "miny", "mo", "foo"], false

Пример 2:

var a = ["1", "2", {foo:"bar"}];
var b = a[1]; // b is now "2";
var c = a[2]; // c now references {foo:"bar"}
a[1] = "4";   // a is now ["1", "4", {foo:"bar"}]; b still has the value
              // it had at the time of assignment
a[2] = "5";   // a is now ["1", "4", "5"]; c still has the value
              // it had at the time of assignment, i.e. a reference to
              // the object {foo:"bar"}
console.log(b, c.foo); // "2" "bar"

Ответ 2

Javascript всегда проходит по значению. Однако, если вы передаете объект функции, "значение" действительно является ссылкой на этот объект, поэтому функция может изменять эти свойства объекта, но не вызывать переменную вне функции, указывающую на какой-либо другой объект.

Пример:

function changeParam(x, y, z) {
  x = 3;
  y = "new string";
  z["key2"] = "new";
  z["key3"] = "newer";

  z = {"new" : "object"};
}

var a = 1,
    b = "something",
    c = {"key1" : "whatever", "key2" : "original value"};

changeParam(a, b, c);

// at this point a is still 1
// b is still "something"
// c still points to the same object but its properties have been updated
// so it is now {"key1" : "whatever", "key2" : "new", "key3" : "newer"}
// c definitely doesn't point to the new object created as the last line
// of the function with z = ...

Ответ 3

Да, Javascript всегда проходит по значению, но в массиве или объекте значение является ссылкой на него, поэтому вы можете "изменить" содержимое.

Но, я думаю, вы уже прочитали его на SO; здесь у вас есть требуемая документация:

http://snook.ca/archives/javascript/javascript_pass

Ответ 4

  • Переменная примитивного типа, как строка, номер всегда проходит как проход по значению.
  • Массив и объект передаются как проход по ссылке или передаются по значению на основе этих двух условий.

    • если вы изменяете значение этого Объекта или массива с помощью нового объекта или массива, тогда оно передается по значению.

      object1 = {item: "car"}; array1=[1,2,3];

    здесь вы назначаете новый объект или массив старым. Вы не меняете значение свойства старого объекта. Также это пропуск по значению.

    • если вы изменяете значение свойства объекта или массива, тогда оно передается по ссылке.

      object1.item= "car"; array1[0]=9;

    здесь вы меняете значение свойства старого объекта. Вы не назначаете новый объект или массив в old one.so он проходит по ссылке.

код

    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