Bagaimana saya lulus variabel dengan referensi di JavaScript? Saya memiliki 3 variabel yang ingin saya melakukan beberapa operasi, jadi saya ingin menempatkan mereka dalam loop for dan melakukan operasi untuk masing-masing.
pseudo code:
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 vars
Apa cara terbaik untuk melakukan hal ini?
Tidak ada "lewat referensi" tersedia dalam JavaScript. Anda dapat melewati objek (yang adalah untuk mengatakan, anda dapat pass-by-value referensi ke objek) dan kemudian memiliki fungsi memodifikasi objek isi:
function alterObject(obj) {
obj.foo = "goodbye";
}
var myObj = { foo: "hello world" };
alterObject(myObj);
alert(myObj.foo); // "goodbye" instead of "hello world"
Anda dapat iterate atas sifat dari sebuah array dengan indeks numerik dan memodifikasi setiap sel dari array, jika anda ingin.
var arr = [1, 2, 3];
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] + 1;
}
It's penting untuk dicatat bahwa "pass-by-reference" adalah istilah tertentu. Ini tidak hanya berarti bahwa itu's mungkin untuk melewati sebuah referensi ke objek yang dapat dimodifikasi. Sebaliknya, itu berarti bahwa itu's mungkin untuk melewati sederhana variabel sedemikian rupa untuk memungkinkan fungsi untuk mengubah nilai tersebut di menelepon konteks. Jadi:
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"
Dalam bahasa seperti C++, it's mungkin untuk melakukan itu karena bahasa itu tidak (sort of) memiliki pass-by-reference.
edit — ini baru-baru ini (Maret 2015) meledak di Reddit lagi di atas posting blog mirip dengan tambang yang disebutkan di bawah ini, meskipun dalam hal ini tentang Jawa. Itu terjadi kepada saya saat membaca kembali-dan-sebagainya di Reddit komentar bahwa bagian besar dari kebingungan berasal dari malang tabrakan yang melibatkan kata "referensi". Istilah "lewat referensi" dan "lulus dengan nilai" mendahului konsep memiliki "benda" untuk bekerja dengan dalam bahasa pemrograman. It's benar-benar bukan tentang benda-benda sama sekali; itu's tentang parameter fungsi, dan secara khusus bagaimana fungsi parameter adalah "terhubung" (atau tidak) untuk memanggil lingkungan. Secara khusus, perhatikan bahwa dalam true pass-by-reference bahasa — salah satu yang tidak melibatkan benda-benda — satu masih akan memiliki kemampuan untuk memodifikasi objek isi, dan ini akan terlihat cukup banyak persis seperti yang dilakukannya dalam JavaScript. Namun, satu akan juga mampu memodifikasi objek referensi dalam pemanggilan lingkungan, dan yang's hal utama yang anda bisa 't lakukan dalam JavaScript. Pass-by-reference bahasa akan lulus bukan referensi itu sendiri, tetapi a referensi ke referensi.
edit — berikut adalah posting blog pada topik. (Catatan komentar untuk posting yang menjelaskan bahwa C++ doesn't benar-benar memiliki pass-by-reference. Itu adalah benar. Apa C++ tidak memiliki, bagaimanapun, adalah kemampuan untuk membuat referensi polos variabel, baik secara eksplisit pada titik fungsi doa untuk membuat pointer, atau secara implisit saat memanggil fungsi dan tipe argumen signature panggilan untuk itu harus dilakukan. Mereka adalah hal-hal penting JavaScript doesn't dukungan.)
object1 = {prop: "mobil"}; array1 = [1,2,3];
object1.prop = "mobil"; array1[0] = 9;
Kode
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 {item:"laptop"}
console.log(object2); //output: Object {item:"bike"}
console.log(number1); //ouput: 10
Solusi untuk lulus variabel seperti dengan referensi:
var a = 1;
inc = function(variableName) {
window[variableName] += 1;
};
inc('a');
alert(a); // 2
EDIT
yup, sebenarnya anda bisa melakukannya tanpa akses global
inc = (function () {
var variableName = 0;
var init = function () {
variableName += 1;
alert(variableName);
}
return init;
})();
inc();
var ref = { value: 1 };
function Foo(x) {
x.value++;
}
Foo(ref);
Foo(ref);
alert(ref.value); // Alert: 3
rvar
function rvar (name, value, context) {
if (this instanceof rvar) {
this.value = value;
Object.defineProperty(this, 'name', { value: name });
Object.defineProperty(this, 'hasValue', { get: function () { return this.value !== undefined; } });
if ((value !== undefined) && (value !== null))
this.constructor = value.constructor;
this.toString = function () { return this.value + ''; };
} else {
if (!rvar.refs)
rvar.refs = {};
if (!context)
context = window;
// Private
rvar.refs[name] = new rvar(name, value);
// Public
Object.defineProperty(context, name, {
get: function () { return rvar.refs[name]; },
set: function (v) { rvar.refs[name].value = v; },
configurable: true
});
return context[name];
}
}
rvar('test_ref');
test_ref = 5; // test_ref.value = 5
Atau:
rvar('test_ref', 5); // test_ref.value = 5
rvar('test_ref_number');
test_ref_number = 5;
function Fn1 (v) { v.value = 100; }
console.log("rvar('test_ref_number');");
console.log("test_ref_number = 5;");
console.log("function Fn1 (v) { v.value = 100; }");
console.log('test_ref_number.value === 5', test_ref_number.value === 5);
console.log(" ");
Fn1(test_ref_number);
console.log("Fn1(test_ref_number);");
console.log('test_ref_number.value === 100', test_ref_number.value === 100);
console.log(" ");
test_ref_number++;
console.log("test_ref_number++;");
console.log('test_ref_number.value === 101', test_ref_number.value === 101);
console.log(" ");
test_ref_number = test_ref_number - 10;
console.log("test_ref_number = test_ref_number - 10;");
console.log('test_ref_number.value === 91', test_ref_number.value === 91);
console.log(" ");
console.log("---------");
console.log(" ");
rvar('test_ref_str', 'a');
console.log("rvar('test_ref_str', 'a');");
console.log('test_ref_str.value === "a"', test_ref_str.value === 'a');
console.log(" ");
test_ref_str += 'bc';
console.log("test_ref_str += 'bc';");
console.log('test_ref_str.value === "abc"', test_ref_str.value === 'abc');
rvar('test_ref_number');
test_ref_number = 5;
function Fn1 (v) { v.value = 100; }
test_ref_number.value === 5 true
Fn1(test_ref_number);
test_ref_number.value === 100 true
test_ref_number++;
test_ref_number.value === 101 true
test_ref_number = test_ref_number - 10;
test_ref_number.value === 91 true
---------
rvar('test_ref_str', 'a');
test_ref_str.value === "a" true
test_ref_str += 'bc';
test_ref_str.value === "abc" true
Namun pendekatan lain untuk lulus (lokal, primitif) variabel dengan referensi adalah dengan membungkus variabel dengan penutupan "on the fly" oleh eval
. Ini juga bekerja dengan "penggunaan ketat". (Catatan: perlu diketahui bahwa eval
tidak cocok untuk JS pengoptimalan, juga hilang tanda kutip nama variabel dapat menyebabkan hasil yang tidak dapat diperkirakan)
"use strict"
//return text that will reference variable by name (by capturing that variable to closure)
function byRef(varName){
return "({get value(){return "+varName+";}, set value(v){"+varName+"=v;}})";
}
//demo
//assign argument by reference
function modifyArgument(argRef, multiplier){
argRef.value = argRef.value * multiplier;
}
(function(){
var x = 10;
alert("x before: " + x);
modifyArgument(eval(byRef("x")), 42);
alert("x after: " + x);
})()
Live sampel
I've telah bermain-main dengan sintaks untuk melakukan hal semacam ini, tetapi hal ini membutuhkan beberapa pembantu yang sedikit tidak biasa. Dimulai dengan tidak menggunakan 'var', tapi sederhana 'MENYATAKAN' penolong yang menciptakan variabel lokal dan mendefinisikan lingkup untuk itu melalui anonim callback. Dengan mengendalikan bagaimana variabel-variabel yang dinyatakan, kita dapat memilih untuk membungkus mereka menjadi benda-benda sehingga mereka selalu dapat dikirimkan dengan referensi, pada dasarnya. Hal ini mirip dengan salah satu Eduardo Cuomo's jawaban di atas, tetapi solusi berikut tidak memerlukan menggunakan string sebagai variabel pengenal. Berikut ini's beberapa kode minimal untuk menunjukkan konsep.
function Wrapper(val){
this.VAL = val;
}
Wrapper.prototype.toString = function(){
return this.VAL.toString();
}
function DECLARE(val, callback){
var valWrapped = new Wrapper(val);
callback(valWrapped);
}
function INC(ref){
if(ref && ref.hasOwnProperty('VAL')){
ref.VAL++;
}
else{
ref++;//or maybe throw here instead?
}
return ref;
}
DECLARE(5, function(five){ //consider this line the same as 'let five = 5'
console.log("five is now " + five);
INC(five); // increment
console.log("five is incremented to " + five);
});
Ada's benar-benar cantik solusi:
function updateArray(context, targetName, callback) {
context[targetName] = context[targetName].map(callback);
}
var myArray = ['a', 'b', 'c'];
updateArray(this, 'myArray', item => {return '_' + item});
console.log(myArray); //(3) ["_a", "_b", "_c"]
Saya pribadi tidak suka "lewat referensi" fungsi yang ditawarkan oleh berbagai bahasa pemrograman. Mungkin itu's karena saya hanya menemukan konsep-konsep dari pemrograman fungsional, tapi aku selalu merinding ketika saya melihat fungsi yang menyebabkan efek samping (seperti memanipulasi parameter-parameter yang dikirimkan dengan referensi). Saya pribadi sangat merangkul "satu tanggung jawab" prinsip.
IMHO, fungsi harus mengembalikan hanya satu hasil/nilai menggunakan kembali kata kunci. Bukan memodifikasi parameter/argumen, saya hanya akan kembali diubah parameter/argumen nilai dan meninggalkan apapun yang diinginkan pengaturan kembali untuk memanggil kode.
Tapi kadang-kadang (mudah-mudahan sangat jarang), hal ini diperlukan untuk mengembalikan dua atau lebih nilai-nilai hasil dari fungsi yang sama. Dalam kasus itu, saya akan memilih untuk mencakup semua nilai yang dihasilkan dalam satu struktur atau objek. Lagi, memproses pengaturan kembali harus sampai kode panggilan.
Contoh:
Misalkan passing parameter akan didukung dengan menggunakan kata kunci khusus seperti 'ref' dalam daftar argumen. Kode saya mungkin terlihat seperti ini:
//The Function
function doSomething(ref value) {
value = "Bar";
}
//The Calling Code
var value = "Foo";
doSomething(value);
console.log(value); //Bar
Sebagai gantinya, aku akan benar-benar lebih memilih untuk melakukan sesuatu seperti ini:
//The Function
function doSomething(value) {
value = "Bar";
return value;
}
//The Calling Code:
var value = "Foo";
value = doSomething(value); //Reassignment
console.log(value); //Bar
Ketika saya akan perlu untuk menulis sebuah fungsi yang mengembalikan beberapa nilai, saya tidak akan menggunakan parameter yang disahkan oleh referensi yang baik. Jadi saya akan menghindari kode seperti ini:
//The Function
function doSomething(ref value) {
value = "Bar";
//Do other work
var otherValue = "Something else";
return otherValue;
}
//The Calling Code
var value = "Foo";
var otherValue = doSomething(value);
console.log(value); //Bar
console.log(otherValue); //Something else
Sebagai gantinya, aku akan benar-benar lebih memilih untuk kembali kedua nilai-nilai baru dalam sebuah objek, seperti ini:
//The Function
function doSomething(value) {
value = "Bar";
//Do more work
var otherValue = "Something else";
return {
value: value,
otherValue: otherValue
};
}
//The Calling Code:
var value = "Foo";
var result = doSomething(value);
value = result.value; //Reassignment
console.log(value); //Bar
console.log(result.otherValue);
Ini contoh kode yang cukup sederhana, tapi itu kira-kira menunjukkan bagaimana saya secara pribadi akan menangani hal-hal seperti itu. Itu membantu saya untuk menjaga berbagai tanggung jawab di tempat yang benar.
Happy coding. :)
function action(){
/* process this.arg, modification allowed */
}
action.arg = [ ["empty-array"],"some string",0x100,"last argument" ];
action();
anda juga dapat janji barang-barang untuk menikmati rantai terkenal: berikut adalah seluruh hal, dengan janji-seperti struktur
function action(){
/* process this.arg, modification allowed */
this.arg = ["a","b"];
}
action.setArg = function(){this.arg = arguments; return this;}
action.setArg(["empty-array"],"some string",0x100,"last argument")()
atau lebih baik lagi..
tindakan.setArg(["kosong-array"],"beberapa string",0x100,"argumen terakhir").call()
Aku tahu persis apa yang anda maksud. Hal yang sama di Swift akan ada masalah.
Intinya adalah menggunakan kita
tidak var
.
Fakta bahwa primitif yang lulus dengan nilai tapi fakta bahwa nilai var i
pada titik iterasi tidak akan disalin ke dalam fungsi anonim cukup mengejutkan untuk sedikitnya.
for (let i = 0; i < boxArray.length; i++) {
boxArray[i].onclick = function() { console.log(i) }; // correctly prints the index
}
Javascript dapat memodifikasi array item di dalam fungsi (hal ini lulus sebagai referensi ke objek/array).
function makeAllPretty(items) {
for (var x = 0; x < myArray.length; x++){
//do stuff to the array
items[x] = makePretty(items[x]);
}
}
myArray = new Array(var1, var2, var3);
makeAllPretty(myArray);
Berikut ini's contoh lain:
function inc(items) {
for (let i=0; i < items.length; i++) {
items[i]++;
}
}
let values = [1,2,3];
inc(values);
console.log(values);
// prints [2,3,4]
JS tidak menjadi jenis yang kuat, memungkinkan anda untuk menyelesaikan masalah dalam berbagai cara, seperti yang tampak dalam tapak.
Namun, untuk rawatan pandang, saya akan setuju dengan Bart Hofland. Fungsi harus mendapatkan args untuk melakukan sesuatu dengan dan mengembalikan hasil. Membuat mereka dengan mudah dapat digunakan kembali.
Jika anda merasa bahwa variabel yang perlu diteruskan oleh referensi anda mungkin akan lebih baik dilayani Bangunan mereka menjadi benda-benda IMHO.