Programing

자바 스크립트에서 참조로 변수 전달

lottogame 2020. 3. 30. 08:44
반응형

자바 스크립트에서 참조로 변수 전달


JavaScript에서 변수를 참조로 전달하려면 어떻게합니까? 여러 작업을 수행하려는 3 개의 변수가 있으므로 for 루프에 넣고 각 작업을 수행하려고합니다.

의사 코드 :

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

가장 좋은 방법은 무엇입니까?


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

"by-by-by-reference"는 매우 구체적인 용어입니다. 단순히 수정 가능한 객체에 대한 참조를 전달할 수 있다는 의미는 아닙니다. 대신 함수가 호출 컨텍스트 에서 해당 값을 수정할 수 있도록 간단한 변수를 전달할 수 있음을 의미합니다 . 그래서:

 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 년 3 월) 아래에서 언급 한 것과 유사한 블로그 게시물을 통해 Reddit을 다시 시작했지만이 경우에는 Java에 대한 것입니다. Reddit에서 앞뒤로 읽는 동안 혼란의 큰 부분은 "참조"라는 단어가 포함 된 불행한 충돌에서 비롯된 것입니다. "참조로 전달"및 "값으로 전달"이라는 용어는 프로그래밍 언어에서 "개체"를 다루는 개념보다 우선합니다. 그것은 실제로 물체에 관한 것이 아닙니다. 함수 매개 변수, 특히 함수 매개 변수가 호출 환경에 "연결된"방법에 관한 것입니다. 특히,JavaScript에서와 똑같이 보입니다. 그러나 호출 환경에서 객체 참조를 수정할 수도 있으며 이것이 JavaScript에서 수행 수없는 핵심 사항입니다 . 참조 별 언어는 참조 자체가 아니라 참조에 대한 참조를 전달 합니다.

편집여기 주제에 대한 블로그 게시물이 있습니다. (이 게시물에 대한 주석은 C ++에 실제로 참조를 통한 전달이 없음을 설명합니다. 사실입니다. 그러나 C ++의 기능은 함수 시점에서 명시 적으로 일반 변수에 대한 참조를 생성하는 기능입니다 포인터를 생성하기위한 호출 또는 인수 유형 서명이 수행되어야하는 함수를 호출 할 때 내재적으로 JavaScript가 지원하지 않는 핵심 요소입니다.)


  1. 문자열 및 숫자와 같은 기본 유형 변수는 항상 값으로 전달됩니다.
  2. 배열과 객체는 다음 조건에 따라 참조 또는 값으로 전달됩니다.

    • 객체 또는 배열의 값을 설정하는 경우 Pass by Value입니다.

      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


참조로 변수를 전달하는 해결 방법 :

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

간단한 객체

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 

참조에 의해 (로컬, 프리미티브) 변수를 전달하는 또 다른 방법은 변수를 "바로"클로저로 래핑하는 것 eval입니다. "엄격한 사용"에서도 작동합니다. (참고 : evalJS 옵티 마이저에게는 친숙하지 않으며 변수 이름에 따옴표가 없으면 예기치 않은 결과가 발생할 수 있습니다.)

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


나는 이런 종류의 일을하기 위해 구문을 가지고 놀고 있지만 약간 특이한 도우미가 필요합니다. '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);
});

실제로 꽤 해결책이 있습니다.

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

실제로는 정말 쉽습니다.

문제는 일단 고전적인 인수를 전달하면 다른 읽기 전용 영역 으로 범위가 지정된다는 것을 이해하는 것입니다 .

해결책은 JavaScript의 객체 지향 디자인을 사용하여 인수를 전달하는 것입니다.

args를 전역 / 범위 변수에 넣는 것과 동일하지만 더 좋습니다 ...

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


다양한 프로그래밍 언어에서 제공하는 "참조로 전달"기능을 개인적으로 싫어합니다. 아마도 그것은 함수형 프로그래밍의 개념을 발견하기 때문일 수도 있지만 부작용을 일으키는 함수 (참조로 전달되는 매개 변수 조작과 같은)를 볼 때 항상 구즈 범프를 얻습니다. 나는 개인적으로 "단일 책임"원칙을 강하게 받아들입니다.

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

이 코드 예제는 매우 간단하지만 개인적으로 이러한 작업을 처리하는 방법을 대략적으로 보여줍니다. 올바른 장소에서 다양한 책임을 지도록 도와줍니다.

행복한 코딩. :)


무슨 말인지 정확히 알아 Swift에서도 마찬가지입니다. 결론은 사용 let하지 않습니다 var.

프리미티브는 값에 의해 전달되지만 var i반복 시점의 값이 익명 함수에 복사되지 않는다는 사실은 가장 놀랍습니다.

for (let i = 0; i < boxArray.length; i++) {
  boxArray[i].onclick = function() { console.log(i) }; // correctly prints the index
}

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]

JS는 강력한 유형이 아니기 때문에이 트레드와 같이 여러 가지 방법으로 문제를 해결할 수 있습니다.

그러나 유지 관리 측면에서 Bart Hofland에 동의해야합니다. 함수는 인수로 무언가를 수행하고 결과를 반환해야합니다. 쉽게 재사용 할 수 있습니다.

변수를 참조로 전달해야한다고 생각하면 IMHO 객체로 변수를 작성하는 것이 더 좋습니다.


통과 기준 토론을 제외하고, 언급 된 질문에 대한 해결책을 찾고있는 사람들은 다음을 사용할 수 있습니다.

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

참고 URL : https://stackoverflow.com/questions/7744611/pass-variables-by-reference-in-javascript

반응형