JavaScript'te değişkenleri referans ile geçirme


JavaScript'te değişkenleri referans yoluyla nasıl geçiririm?

Üzerinde birkaç işlem yapmak istediğim üç değişkenim var, bu yüzden onları bir for döngüsüne koymak ve işlemleri her birine uygulamak istiyorum.

Sözde kod:

myArray = new Array(var1, var2, var3);
for (var x = 0; x < myArray.length; x++){
    // Do stuff to the array
    makePretty(myArray[x]);
}
// Now do stuff to the updated variables

Bunu yapmanın en iyi yolu nedir?

Cevap #1

JavaScript'te "referansla geçiş" mevcut değildir. Bir nesne geçirebilirsiniz (yani, bir nesneye referansı değer olarak geçirebilirsiniz) ve sonra bir fonksiyon nesne içeriğini değiştirebilir:

function alterObject(obj) {
  obj.foo = "goodbye";
}

var myObj = { foo: "hello world" };

alterObject(myObj);

alert(myObj.foo); // "goodbye" instead of "hello world"

İsterseniz, sayısal bir indekse sahip bir dizinin özellikleri üzerinde yineleme yapabilir ve dizinin her hücresini değiştirebilirsiniz.

var arr = [1, 2, 3];

for (var i = 0; i < arr.length; i++) { 
    arr[i] = arr[i] + 1; 
}

“Referansla geçirme” çok özel bir terim olduğuna dikkat etmek önemlidir. Bu, sadece değiştirilebilir bir nesnenin referansını geçirebilmenin mümkün olduğu anlamına gelmez. Bunun yerine, basit bir değişkenin, bir fonksiyonun bu değeri çağıran bağlamda değiştirmesine izin verecek şekilde geçirilmesinin mümkün olduğu anlamına gelir. Yani:

 function swap(a, b) {
   var tmp = a;
   a = b;
   b = tmp; //assign tmp to b
 }

 var x = 1, y = 2;
 swap(x, y);

 alert("x is " + x + ", y is " + y); // "x is 1, y is 2"

C++ gibi bir dilde bunu yapmak mümkündür çünkü bu dil (bir nevi) referans ile geçişi desteklemektedir.

düzenle — bu kısa süre önce (Mart 2015) Reddit'te benim aşağıda bahsettiğimle benzer bir blog yazısı üzerinden tekrar gündeme geldi, ancak bu durumda Java ile ilgiliydi. Reddit yorumlarındaki karşılıklı yazışmaları okurken aklıma, kafa karışıklığının büyük bir kısmının "referans" kelimesiyle yaşanan talihsiz çakışmadan kaynaklandığı geldi. "referans ile geçiş" ve "değer ile geçiş" terimleri, programlama dillerinde kullanıcıların "nesnelerle" çalışması kavramından çok önce ortaya çıkmıştır. Aslında bu tamamen nesnelerle ilgili değil; fonksiyon parametreleriyle ilgili ve özellikle fonksiyon parametrelerinin çağıran ortamla nasıl "bağlantılı" olduğu (veya olmadığı) ile ilgilidir. Özellikle, gerçek bir referansla geçiş (pass-by-reference) dilinde — nesneleri dahil eden bir dil — nesne içeriklerini değiştirme yeteneğinin hala olacağını ve bunun JavaScript'te göründüğü gibi görüneceğini unutmayın. Ancak, çağıran ortamda nesne referansını da değiştirebilme imkanı olur ve bu, JavaScript'te yapamayacağınız ana şeydir. Bir referansla geçiş dili, referansın kendisini değil, bir referansa referansı geçirir.

düzenle — işte konu hakkında bir blog yazısı. (O yazıya yapılan ve C++'ın gerçekten referans ile geçişe sahip olmadığını açıklayan yorumu dikkate alın. Bu doğru. Ancak C++'ın sahip olduğu şey, ya işlev çağrısı sırasında açıkça bir işaretçi oluşturmak için ya da argüman türü imzasının bunu gerektirdiği fonksiyonlar çağrılırken örtük olarak düz değişkenlere referans oluşturabilme yeteneğidir. Bunlar, JavaScript'in desteklemediği temel şeylerdir.)

Cevap #2

  1. Stringler ve sayılar gibi ilkel tür değişkenler her zaman değerle aktarılır.
  2. Diziler ve Nesneler, bu koşullara bağlı olarak referansla veya değerle iletilir:
  • Eğer bir nesnenin ya da dizinin değerini ayarlıyorsanız, bu Değerle Geçiştir.

     object1 = { prop: "car" };
     array1 = [1,2,3];
    
  • Eğer bir nesnenin veya dizinin bir özellik değerini değiştiriyorsanız, bu Referans ile Geçirilmektir.

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

Kod

function passVar(obj1, obj2, num) {
    obj1.prop = "laptop"; // will CHANGE original
    obj2 = { prop: "computer" }; //will NOT affect original
    num = num + 1; // will NOT affect original
}

var object1 = {
    prop: "car"
};
var object2 = {
    prop: "bike"
};
var number1 = 10;

passVar(object1, object2, number1);
console.log(object1); // output: Object { prop: "laptop" }
console.log(object2); // output: Object { prop: "bike" }
console.log(number1); // ouput: 10

Cevap #3

Değişkeni referans gibi geçirmek için çözüm yolu:

var a = 1;
inc = function(variableName) {
  window[variableName] += 1;
};

inc('a');

alert(a); // 2

Ve evet, aslında bunu bir global değişkene erişmeden yapabilirsiniz:

inc = (function () {
    var variableName = 0;

    var init = function () {
        variableName += 1;
        alert(variableName);
    }

    return init;
})();

inc();

Cevap #4

Basit Nesne

function foo(x) {
  // Function with other context
  // Modify `x` property, increasing the value
  x.value++;
}

// Initialize `ref` as object
var ref = {
  // The `value` is inside `ref` variable object
  // The initial value is `1`
  value: 1
};

// Call function with object value
foo(ref);
// Call function with object value again
foo(ref);

console.log(ref.value); // Prints "3"

Özel Nesne

Nesne rvar

/**
 * Aux function to create by-references variables
 */
function rvar(name, value, context) {
  // If `this` is a `rvar` instance
  if (this instanceof rvar) {
    // Inside `rvar` context...

    // Internal object value
    this.value = value;

    // Object `name` property
    Object.defineProperty(this, 'name', { value: name });

    // Object `hasValue` property
    Object.defineProperty(this, 'hasValue', {
      get: function () {
        // If the internal object value is not `undefined`
        return this.value !== undefined;
      }
    });

    // Copy value constructor for type-check
    if ((value !== undefined) && (value !== null)) {
      this.constructor = value.constructor;
    }

    // To String method
    this.toString = function () {
      // Convert the internal value to string
      return this.value + '';
    };
  } else {
    // Outside `rvar` context...

    // Initialice `rvar` object
    if (!rvar.refs) {
      rvar.refs = {};
    }

    // Initialize context if it is not defined
    if (!context) {
      context = this;
    }

    // Store variable
    rvar.refs[name] = new rvar(name, value, context);

    // Define variable at context
    Object.defineProperty(context, name, {
      // Getter
      get: function () { return rvar.refs[name]; },
      // Setter
      set: function (v) { rvar.refs[name].value = v; },
      // Can be overrided?
      configurable: true
    });

    // Return object reference
    return context[name];
  }
}

// Variable Declaration

// Declare `test_ref` variable
rvar('test_ref_1');

// Assign value `5`
test_ref_1 = 5;
// Or
test_ref_1.value = 5;

// Or declare and initialize with `5`:
rvar('test_ref_2', 5);

// ------------------------------
// Test Code

// Test Function
function Fn1(v) { v.value = 100; }

// Test
function test(fn) { console.log(fn.toString()); console.info(fn()); }

// Declare
rvar('test_ref_number');

// First assign
test_ref_number = 5;
test(() => test_ref_number.value === 5);

// Call function with reference
Fn1(test_ref_number);
test(() => test_ref_number.value === 100);

// Increase value
test_ref_number++;
test(() => test_ref_number.value === 101);

// Update value
test_ref_number = test_ref_number - 10;
test(() => test_ref_number.value === 91);

İlgili makaleler