ส่งผ่านตัวแปรตามการอ้างอิงใน Javascript


285

ฉันจะส่งผ่านตัวแปรโดยอ้างอิงใน JavaScript ได้อย่างไร ฉันมีตัวแปร 3 ตัวที่ฉันต้องการใช้ในการดำเนินการหลายอย่างดังนั้นฉันจึงต้องการที่จะใส่มันไว้ในการวนรอบและดำเนินการกับแต่ละคน

รหัสหลอก:

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

วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?


31
คุณกำลังพูดถึง 'ส่งผ่านการอ้างอิง' แต่คุณไม่มีฟังก์ชั่นการโทรในตัวอย่างของคุณดังนั้นจึงไม่มีการส่งผ่านเลยในตัวอย่างของคุณ โปรดอธิบายสิ่งที่คุณพยายามจะทำ
jfriend00

1
ขอโทษสำหรับความสับสน. ฉันไม่จำเป็นต้องเขียนฟังก์ชั่นโดยเฉพาะดังนั้นการ 'ส่งผ่านการอ้างอิง' จึงเป็นทางเลือกที่ไม่ดีของคำ ฉันแค่ต้องการที่จะสามารถดำเนินการบางอย่างกับตัวแปรโดยไม่ต้องเขียน makePretty(var1); makePretty(var2); makePretty(var3); ...
BFTrick

ตามความคิดเห็นของคุณ: arr = [var1, var2, var3]; for (var i = 0, len = arr.length; i < len; i++) { arr[i] = makePretty(arr[i]); }- คุณเพียงแค่ต้องเก็บค่าที่ส่งคืนโดยmakePrettyย้อนกลับเข้าไปในสล็อตในอาร์เรย์
dylnmc

คำตอบ:


415

ไม่มี "การส่งผ่านอ้างอิง" ใน JavaScript คุณสามารถผ่านวัตถุ (ซึ่งก็คือการพูดว่าคุณสามารถผ่านการอ้างอิงถึงวัตถุ) และจากนั้นให้ฟังก์ชั่นแก้ไขเนื้อหาของวัตถุ:

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

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

alterObject(myObj);

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

คุณสามารถวนซ้ำคุณสมบัติของอาร์เรย์ด้วยดัชนีตัวเลขและปรับเปลี่ยนแต่ละเซลล์ของอาร์เรย์ได้หากคุณต้องการ

var arr = [1, 2, 3];

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

สิ่งสำคัญคือให้สังเกตว่า "การอ้างอิงผ่าน" เป็นคำที่เฉพาะเจาะจงมาก ไม่ได้หมายความว่าเป็นไปได้ที่จะส่งการอ้างอิงไปยังวัตถุที่แก้ไขได้ แต่หมายความว่าเป็นไปได้ที่จะส่งผ่านตัวแปรอย่างง่ายในลักษณะที่อนุญาตให้ฟังก์ชันแก้ไขค่านั้นในบริบทการโทร ดังนั้น:

 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 ++ เป็นไปได้ที่จะทำเช่นนั้นเพราะภาษานั้น (เรียงลำดับ) มีการอ้างอิงแบบส่งต่อ

แก้ไข - เมื่อเร็ว ๆ นี้ (มีนาคม 2015) ได้ระเบิด Reddit อีกครั้งผ่านบล็อกโพสต์คล้ายกับที่ฉันพูดถึงด้านล่าง แต่ในกรณีนี้เกี่ยวกับ Java มันเกิดขึ้นกับฉันในขณะที่อ่านไปมาในความคิดเห็น Reddit ว่าส่วนใหญ่ของความสับสนเกิดจากการชนที่โชคร้ายที่เกี่ยวข้องกับคำว่า "อ้างอิง" คำศัพท์ "ผ่านโดยอ้างอิง" และ "ผ่านค่า" มาก่อนแนวคิดของการมี "วัตถุ" เพื่อทำงานกับในภาษาการเขียนโปรแกรม มันไม่เกี่ยวกับวัตถุเลย มันเกี่ยวกับพารามิเตอร์ของฟังก์ชั่นและโดยเฉพาะว่าพารามิเตอร์ของฟังก์ชั่นนั้น "เชื่อมต่อ" (หรือไม่) กับสภาพแวดล้อมการโทรได้อย่างไร โดยเฉพาะอย่างยิ่ง,และมันจะดูสวยเหมือนใน JavaScript แต่หนึ่งจะยังสามารถที่จะปรับเปลี่ยนการอ้างอิงวัตถุในสภาพแวดล้อมการเรียกและนั่นคือสิ่งที่สำคัญที่คุณไม่สามารถทำใน JavaScript ภาษาผ่านโดยการอ้างอิงจะผ่านไม่ได้อ้างอิงตัวเอง แต่อ้างอิงถึงการอ้างอิง

แก้ไข - นี่คือโพสต์บล็อกในหัวข้อ (หมายเหตุความคิดเห็นไปยังโพสต์นั้นซึ่งอธิบายว่า C ++ ไม่มีการอ้างอิงแบบ pass-by-reference จริง ๆ แล้วอย่างไรก็ตามสิ่งที่ C ++ มีคือความสามารถในการสร้างการอ้างอิงไปยังตัวแปรธรรมดาไม่ว่าที่จุดของฟังก์ชัน การเรียกใช้เพื่อสร้างตัวชี้หรือโดยปริยายเมื่อเรียกใช้ฟังก์ชันที่มีการเรียกใช้ลายเซ็นประเภทอาร์กิวเมนต์เพื่อให้ทำสิ่งเหล่านี้คือสิ่งสำคัญที่ JavaScript ไม่สนับสนุน)


8
คุณสามารถส่งการอ้างอิงไปยังวัตถุหรืออาร์เรย์ที่อนุญาตให้คุณเปลี่ยนวัตถุหรืออาร์เรย์เดิมซึ่งฉันเชื่อว่าเป็นสิ่งที่ OP ต้องการถามจริง ๆ
jfriend00

2
โอพีใช้คำศัพท์ แต่รหัสจริงดูเหมือนจะไม่เกี่ยวข้องกับ "การผ่าน" เลย :-) ฉันไม่แน่ใจว่าเขาพยายามทำอะไร
แหลม

5
การส่งการอ้างอิงโดยค่านั้นไม่เหมือนกับการส่งผ่านการอ้างอิงถึงแม้ว่ามันอาจปรากฏขึ้นในบางสถานการณ์เช่นนี้
Travis Webb

5
บล็อกเกอร์ของคุณผิดเกี่ยวกับ C ++ ซึ่งอ้างอิงแบบไม่ผ่านและโพสต์ของเขาไม่สมเหตุสมผล ไม่เกี่ยวข้องที่คุณไม่สามารถเปลี่ยนค่าของการอ้างอิงหลังจากเริ่มต้นได้ มันไม่มีส่วนเกี่ยวข้องกับ 'pass by reference' คำพูดของเขาที่ความหมายของ "การอ้างอิงโดยอ้างอิง" สามารถย้อนกลับผ่าน C # 'ควรมีสัญญาณเตือนภัย
EML

7
@Pointy นี่คือคำตอบที่น่ากลัว ถ้าฉันต้องการความช่วยเหลือสิ่งสุดท้ายที่ฉันต้องการคือมีคนสอนฉันเกี่ยวกับความหมาย "Pass-by-reference" นั้นหมายถึงว่า "ฟังก์ชั่นในระดับหนึ่งสามารถเปลี่ยนค่าของตัวแปรที่ถูกส่งผ่านเป็นอาร์กิวเมนต์" (ในบริบทของคำถาม) มันไม่ซับซ้อนอย่างที่คุณคิด
crownlessking

109
  1. ตัวแปรชนิดดั้งเดิมเช่นสตริงและตัวเลขจะถูกส่งผ่านตามค่าเสมอ
  2. อาร์เรย์และวัตถุถูกส่งผ่านโดยการอ้างอิงหรือตามค่าตามเงื่อนไขเหล่านี้:

    • หากคุณกำลังตั้งค่าของวัตถุหรืออาร์เรย์มันคือผ่านค่า

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

    • ถ้าคุณกำลังเปลี่ยนค่าคุณสมบัติของวัตถุหรืออาร์เรย์มันจะผ่านการอ้างอิง

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

รหัส

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


21
นั่นไม่ใช่ความหมายของ "ส่งต่อโดยอ้างอิง" คำนี้ไม่มีส่วนเกี่ยวข้องกับวัตถุ แต่มีความสัมพันธ์ระหว่างพารามิเตอร์ในฟังก์ชันที่เรียกว่าและตัวแปรในสภาพแวดล้อมการโทร
Pointy

12
ทุกสิ่งถูกส่งผ่านตามค่าเสมอ ด้วย non-primitives ค่าที่ส่งผ่านคือการอ้างอิง การกำหนดให้กับการอ้างอิงการเปลี่ยนแปลงนั้นอ้างอิง - โดยธรรมชาติเนื่องจากเป็นค่า - และดังนั้นจึงไม่สามารถเปลี่ยนวัตถุอื่น ๆ ที่ถูกอ้างอิงในตอนแรก การกลายวัตถุที่ชี้ไปโดยการอ้างอิงจะทำหน้าที่อย่างที่คุณคาดไว้โดยการกลายวัตถุที่ชี้ไปที่ ทั้งสองสถานการณ์มีความสอดคล้องกันอย่างสมบูรณ์และไม่มีการเปลี่ยนแปลงอย่างน่าอัศจรรย์ว่า JavaScript ทำงานอย่างไรโดยย้อนเวลากลับไปและเปลี่ยนวิธีการส่งผ่านเข้าไปในฟังก์ชัน
Matthew อ่าน

9
คำตอบนี้ทำให้ชัดเจนก่อนหน้านี้ซึ่งแม้ว่ามันจะมีคะแนนมากกว่า (287 ในขณะนี้ของการเขียนและมันก็เป็นคนที่ยอมรับ) ก็ไม่ชัดเจนพอว่าจะผ่านมันโดยอ้างอิงใน JS จริง ๆ ในระยะสั้นรหัสในคำตอบนี้ใช้งานได้คำตอบที่รวบรวมคะแนนมากขึ้นไม่ได้
Pap

25

วิธีแก้ปัญหาเพื่อส่งผ่านตัวแปรเช่นโดยการอ้างอิง:

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

inc('a');

alert(a); // 2


แก้ไข

ใช่จริงคุณสามารถทำได้โดยไม่ต้องเข้าถึงทั่วโลก

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

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

    return init;
})();

inc();

@ มันเป็นเรื่องดีที่จะต้องระมัดระวังเกี่ยวกับค่าทั่วโลก / หน้าต่าง แต่ในบางจุดทุกอย่างที่เราทำในเบราว์เซอร์เป็นลูกหรือลูกหลานของวัตถุหน้าต่าง ใน nodejs ทุกอย่างเป็นสายเลือดของ GLOBAL ในภาษาอ็อบเจกต์ที่คอมไพล์นั่นคือโดยปริยายถ้าไม่ใช่วัตถุพาเรนต์ที่ชัดเจนเนื่องจากการทำเช่นนั้นจะทำให้การจัดการฮีปมีความซับซ้อนมากขึ้น (และเพื่ออะไร)
dkloke

1
@dkloke: ใช่ในที่สุดวัตถุในหน้าต่างจะต้องมีการสัมผัสเช่น jQuery ใช้หน้าต่าง $ / window.jQuery และวิธีการอื่น ๆ อยู่ภายใต้สิ่งนี้ ฉันกำลังพูดถึงมลภาวะของเนมสเปซทั่วโลกที่คุณเพิ่มตัวแปรลงไปมากกว่าที่จะให้มันอยู่ภายใต้เนมสเปซที่รวมกัน
Phil

2
ฉันไม่สามารถหาคำพูดที่ดีเพื่อแสดงให้เห็นว่าวิธีการนั้นเลวร้ายเพียงใด (
SOReader

ฉันรักทางออกสุดท้าย (ฉบับแก้ไข) แม้ว่ามันจะไม่ผ่านตัวแปรโดยการอ้างอิง นั่นเป็นข้อได้เปรียบเพราะคุณสามารถเข้าถึงตัวแปรได้โดยตรง
John Boe

11

วัตถุอย่างง่าย

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

หรือ:

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 

5

แต่อีกวิธีหนึ่งที่จะผ่านใด ๆ (ท้องถิ่นดั้งเดิม) ตัวแปรโดยอ้างอิงจากตัวแปรห่อกับการปิด "ในทันที" evalโดย วิธีนี้ใช้ได้กับ "ใช้เข้มงวด" (หมายเหตุ: โปรดทราบว่าevalการเพิ่มประสิทธิภาพ JS ไม่เป็นมิตรกับคำพูดที่หายไปเกี่ยวกับชื่อตัวแปรอาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิด)

"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);

})()

ตัวอย่างสดhttps://jsfiddle.net/t3k4403w/


นี่มันสุดยอดมาก
hard_working_ant

3

จริงๆแล้วมีวิธีแก้ปัญหาที่ค่อนข้างสวย:

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"]

3

ฉันไม่ชอบฟังก์ชั่น "การอ้างอิงโดยอ้างอิง" ที่เสนอโดยภาษาการเขียนโปรแกรมที่หลากหลาย อาจเป็นเพราะฉันเพิ่งค้นพบแนวคิดของฟังก์ชันการเขียนโปรแกรม แต่ฉันมักจะได้รับห่านเมื่อฉันเห็นฟังก์ชั่นที่ทำให้เกิดผลข้างเคียง (เช่นการจัดการพารามิเตอร์ที่ส่งผ่านโดยการอ้างอิง) โดยส่วนตัวแล้วฉันยอมรับอย่างมากว่าหลักการ

IMHO ฟังก์ชันควรส่งคืนผลลัพธ์ / ค่าเดียวโดยใช้คีย์เวิร์ด return แทนที่จะแก้ไขพารามิเตอร์ / อาร์กิวเมนต์ฉันจะคืนค่าพารามิเตอร์ / อาร์กิวเมนต์ที่แก้ไขแล้วและปล่อยให้การกำหนดใหม่ที่ต้องการถึงรหัสการโทร

แต่บางครั้ง (หวังมากไม่ค่อย) มีความจำเป็นต้องคืนค่าผลลัพธ์สองค่าขึ้นไปจากฟังก์ชันเดียวกัน ในกรณีนั้นฉันจะเลือกที่จะรวมค่าผลลัพธ์ทั้งหมดในโครงสร้างหรือวัตถุเดียว อีกครั้งการประมวลผลการมอบหมายใหม่ควรขึ้นอยู่กับรหัสการโทร

ตัวอย่าง:

สมมติว่าพารามิเตอร์การส่งผ่านจะได้รับการสนับสนุนโดยใช้คำหลักพิเศษเช่น 'ref' ในรายการอาร์กิวเมนต์ รหัสของฉันอาจมีลักษณะเช่นนี้:

//The Function
function doSomething(ref value) {
    value = "Bar";
}

//The Calling Code
var value = "Foo";
doSomething(value);
console.log(value); //Bar

ฉันอยากทำสิ่งนี้มากกว่า:

//The Function
function doSomething(value) {
    value = "Bar";
    return value;
}

//The Calling Code:
var value = "Foo";
value = doSomething(value); //Reassignment
console.log(value); //Bar

เมื่อฉันต้องการเขียนฟังก์ชันที่คืนค่าหลายค่าฉันจะไม่ใช้พารามิเตอร์ที่ส่งผ่านโดยการอ้างอิง ดังนั้นฉันจะหลีกเลี่ยงรหัสเช่นนี้

//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

แต่ฉันอยากกลับทั้งสองค่าใหม่ภายในวัตถุเช่นนี้

//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);

ตัวอย่างโค้ดเหล่านี้ค่อนข้างง่าย แต่มันแสดงให้เห็นอย่างคร่าวๆว่าฉันจะจัดการกับสิ่งเหล่านั้นอย่างไร มันช่วยให้ฉันรักษาความรับผิดชอบต่าง ๆ ในตำแหน่งที่ถูกต้อง

การเข้ารหัสที่มีความสุข :)


การกำหนดและมอบหมายสิ่งต่าง ๆ (โดยไม่มีการตรวจสอบประเภทใด ๆ ด้วย) เป็นสิ่งที่ทำให้ฉันขนลุก สำหรับความรับผิดชอบฉันคาดหวังให้ doSomething () ทำสิ่งนั้นไม่ใช่ทำสิ่งนั้นรวมทั้งสร้างอ็อบเจกต์บวกและกำหนดตัวแปรให้กับคุณสมบัติ สมมติว่าฉันมีอาร์เรย์ที่ต้องค้นหาฉันต้องการรายการที่ตรงกันที่อยู่ในอาร์เรย์ที่สองและฉันต้องการทราบว่ามีการค้นพบจำนวนเท่าใด โซลูชันมาตรฐานจะเรียกใช้ฟังก์ชันดังนี้: 'var foundArray; if ((findStuff (inArray, & foundArray))> 1) {// process foundArray} ' ไม่มีที่ใดในสถานการณ์จำลองที่เป็นวัตถุใหม่ที่ไม่รู้จักที่ต้องการหรือต้องการ
Elise van Looij

@ElisevanLooij ในกรณีตัวอย่างของคุณฉันต้องการที่จะfindStuffคืนค่าอาร์เรย์ผลลัพธ์ คุณก็ต้องประกาศfoundArrayตัวแปรดังนั้นฉันจะกำหนดอาร์เรย์ผลลัพธ์โดยตรงให้กับมัน: var foundArray = findStuff(inArray); if (foundArray.length > 0) { /* process foundArray */ }. สิ่งนี้จะ 1) ทำให้รหัสการโทรสามารถอ่าน / เข้าใจได้ง่ายขึ้นและ 2) ทำให้การทำงานภายในง่ายขึ้น (และยังเป็นการทดสอบ) ของfindStuffวิธีการทำให้ความยืดหยุ่นในการใช้งาน / สถานการณ์ / สถานการณ์แตกต่างกันมากขึ้น
Bart Hofland

@ElisevanLooij อย่างไรก็ตามฉันยอมรับว่าการมอบหมายใหม่ (เหมือนในคำตอบของฉัน) นั้นเป็น "รหัสกลิ่น" และฉันก็ต้องการหลีกเลี่ยงสิ่งเหล่านั้นให้มากที่สุดเท่าที่จะเป็นไปได้ ฉันจะคิดถึงการแก้ไข (หรือแม้แต่การปฏิรูป) คำตอบของฉันในแบบที่มันจะสะท้อนความเห็นที่แท้จริงของฉันในเรื่องนี้ได้ดียิ่งขึ้น ขอบคุณสำหรับปฏิกิริยาของคุณ :)
Bart Hofland

2

ฉันได้เล่นกับไวยากรณ์เพื่อทำสิ่งนี้ แต่ต้องมีผู้ช่วยที่ผิดปกติเล็กน้อย มันเริ่มต้นด้วยการไม่ใช้ 'var' เลย แต่เป็นผู้ช่วย 'DECLARE' ที่เรียบง่ายที่สร้างตัวแปรท้องถิ่นและกำหนดขอบเขตสำหรับมันผ่านการโทรกลับแบบไม่ระบุชื่อ โดยการควบคุมวิธีการประกาศตัวแปรเราสามารถเลือกที่จะห่อมันลงในวัตถุเพื่อให้พวกเขาสามารถถูกส่งผ่านโดยการอ้างอิงเป็นหลัก นี่คล้ายกับหนึ่งในคำตอบของ Eduardo Cuomo ด้านบน แต่โซลูชันด้านล่างไม่ต้องการใช้สตริงเป็นตัวระบุตัวแปร นี่คือโค้ดขั้นต่ำที่จะแสดงแนวคิด

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);
});

2

จริงๆแล้วมันง่ายจริงๆ

ปัญหาคือการเข้าใจว่าเมื่อผ่านการขัดแย้งคลาสสิกคุณจะถูกกำหนดขอบเขตในโซนอ่านอย่างเดียวอื่น

โซลูชั่นคือการส่งผ่านข้อโต้แย้งโดยใช้การออกแบบเชิงวัตถุของ JavaScript

มันเหมือนกับการใส่ args ในตัวแปร global / scoped แต่ดีกว่า ...

function action(){
  /* process this.arg, modification allowed */
}

action.arg = [ ["empty-array"],"some string",0x100,"last argument" ];
action();

นอกจากนี้คุณยังสามารถสัญญาสิ่งต่าง ๆ เพื่อเพลิดเพลินไปกับห่วงโซ่ที่รู้จักกันดี: นี่คือสิ่งทั้งหมดที่มีโครงสร้างเหมือนสัญญา

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")()

หรือดีกว่า .. action.setArg(["empty-array"],"some string",0x100,"last argument").call()


this.argใช้ได้กับactionอินสแตนซ์เท่านั้น สิ่งนี้ใช้ไม่ได้
Eduardo Cuomo

1

Javascript สามารถแก้ไขรายการของอาเรย์ภายในฟังก์ชั่น (มันถูกส่งผ่านเป็นการอ้างอิงไปยังวัตถุ / อาเรย์)

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);

นี่เป็นอีกตัวอย่าง:

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]

1

JS ไม่ใช่ประเภทที่แข็งแกร่งมันช่วยให้คุณแก้ไขปัญหาได้หลายวิธีตามที่เห็นในดอกยางนี้

อย่างไรก็ตามเพื่อการบำรุงรักษาในมุมมองของฉันจะต้องเห็นด้วยกับ Bart Hofland ฟังก์ชั่นควรรับ args เพื่อทำบางสิ่งบางอย่างด้วยและส่งคืนผลลัพธ์ ทำให้สามารถนำมาใช้ซ้ำได้อย่างง่ายดาย

หากคุณรู้สึกว่าตัวแปรจำเป็นต้องผ่านการอ้างอิงคุณอาจจะได้รับการบริการที่ดีขึ้นการสร้างพวกมันให้เป็นวัตถุ IMHO


1

นอกเหนือจากการสนทนาแบบอ้างอิงถึงตัวบุคคลที่ยังคงมองหาวิธีการแก้ปัญหาของคำถามที่กล่าวมาสามารถใช้:

const myArray = new Array(var1, var2, var3);
myArray.forEach(var => var = makePretty(var));

0

ฉันรู้ว่าคุณหมายถึงอะไร สิ่งเดียวกันใน Swift จะไม่มีปัญหา บรรทัดล่างคือการใช้งานไม่ได้letvar

ความจริงที่ว่าดั้งเดิมถูกส่งผ่านโดยค่า แต่ความจริงที่ว่าค่าของvar iณ จุดของการทำซ้ำไม่ได้คัดลอกลงในฟังก์ชั่นที่ไม่ระบุชื่อค่อนข้างน่าแปลกใจที่จะพูดอย่างน้อย

for (let i = 0; i < boxArray.length; i++) {
  boxArray[i].onclick = function() { console.log(i) }; // correctly prints the index
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.