programing

JavaScript에서 참조로 변수 전달

projobs 2022. 10. 2. 15:19
반응형

JavaScript에서 참조로 변수 전달

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 variables

어떻게 하면 좋을까요?

JavaScript에서 사용할 수 있는 "pass by reference"는 없습니다.오브젝트(즉, 오브젝트에 대한 참조를 값별로 전달할 수 있음)를 전달하고 함수를 통해 오브젝트 내용을 수정할 수 있습니다.

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

"pass-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++와 같은 언어에서는 그 언어에는 pass-by-reference가 있기 때문에 그렇게 할 수 있습니다.

편집 - 이 최근(2015년 3월)은 아래에 나와 유사한 블로그 투고를 통해 Reddit에 다시 한번 폭팔했습니다.단, 이 경우 Java에 관한 것입니다.레딧의 코멘트를 읽고 있을 때, 나는 혼란의 큰 부분이 "참조"라는 단어와 관련된 불행한 충돌에서 비롯되었다는 생각이 들었다."pass by reference"와 "pass by value"라는 용어는 프로그래밍 언어에서 사용할 "objects"를 갖는 개념보다 앞서 있습니다.실제로는 객체에 관한 것이 아니라 함수 파라미터, 특히 함수 파라미터가 호출환경에 어떻게 "연결"되어 있는지(또는 그렇지 않은지)에 관한 것입니다.특히 오브젝트를 수반하는 진정한 패스 바이 레퍼런스 언어에서는 오브젝트의 내용을 변경할 수 있으며 JavaScript와 거의 동일하게 보입니다.그러나 호출 환경에서는 오브젝트 참조를 변경할 수도 있습니다.이것은 JavaScript에서는 할 수 없는 중요한 기능입니다.참조별 언어는 참조 자체가 아니라 참조에 대한 참조를 전달합니다.

edit : 이 토픽에 관한 블로그 투고입니다.(C++는 실제로 pass-by-reference를 가지고 있지 않다는 것을 설명하는 게시물에 대한 코멘트를 참고하십시오.그것은 사실이에요.단, C++에는 플레인 변수에 대한 참조를 작성할 수 있는 기능이 있습니다.이것은 포인터를 작성하기 위한 함수 호출 포인트로 명시적으로 작성하거나 인수 타입의 시그니처가 그 처리를 요구하는 함수를 호출할 때 암묵적으로 작성하거나 둘 중 하나입니다.이것들은 JavaScript가 지원하지 않는 주요 요소입니다.)

  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 { prop: "laptop" }
console.log(object2); // output: Object { prop: "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();

심플 오브젝트

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"


커스텀 오브젝트

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

어떤 ( 또 은 "에 의해 닫힘 변수를 "on fly"로이다.eval하게 사용: 「엄격하게 사용」에 해 주세요).eval는 JavaScript 예기치않은 결과가 할 수 있습니다).

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

사실 꽤 침울한 게 있어요

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

저는 개인적으로 다양한 프로그래밍 언어에서 제공되는 "참조별 패스" 기능을 싫어합니다.기능 프로그래밍의 개념을 발견한 지 얼마 안 됐기 때문인지 부작용을 일으키는 기능(기준으로 전달된 파라미터를 조작하는 기능 등)을 보면 항상 소름이 돋는다.저는 개인적으로 '단일 책임' 원칙을 강하게 지지합니다.

IMHO, 함수는 return 키워드를 사용하여 하나의 결과/값만 반환해야 합니다.파라미터/인수를 변경하는 대신 변경된 파라미터/인수값을 반환하고 원하는 재할당은 발신자 코드에 맡깁니다.

단, 경우에 따라서는 (매우 드물게) 같은 함수에서2개 이상의 결과값을 반환할 필요가 있습니다.이 경우, 나는 모든 결과 값을 하나의 구조나 객체에 포함시키는 것을 선택한다.다시 말씀드리지만, 재할당 처리는 발신자 코드에 따라 다릅니다.

예:

인수 목록에서 '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);

이러한 코드 예는 매우 간단하지만, 내가 개인적으로 어떻게 대처해야 하는지를 대략적으로 보여줍니다.여러 가지 책임을 제대로 지우는 데 도움이 됩니다.

해피 코딩.:)

저는 이런 종류의 일을 하기 위해 구문을 가지고 놀았습니다만, 조금 특이한 도우미를 필요로 합니다.처음에는 'var'를 전혀 사용하지 않고 단순히 'DECARE' 도우미를 사용하여 로컬 변수를 만들고 익명 콜백을 통해 로컬 변수의 범위를 정의합니다.변수가 선언되는 방법을 제어함으로써 기본적으로 항상 참조로 전달될 수 있도록 변수를 개체로 줄바꿈하도록 선택할 수 있습니다.이는 위의 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);
});

사실 정말 쉬워요.문제는 기존 인수를 전달하면 다른 읽기 전용 영역으로 범위가 지정된다는 것을 이해하는 것입니다.

해결책은 JavaScript의 객체 지향 설계를 사용하여 인수를 전달하는 것입니다.이것은 인수를 글로벌/범위 변수에 넣는 것과 동일하지만 더 나은 방법입니다.

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

레퍼런스별 논의는 차치하고, 기재된 질문에 대한 해결책을 찾고 있는 고객은 다음을 이용할 수 있습니다.

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

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]

javascript pass by reference 기능이 없기 때문에 이 기능을 실행하는 유일한 방법은 함수가 값을 반환하고 호출자가 값을 할당하도록 하는 것입니다.

그렇게

"makePretty(myArray[x]);"

그래야 한다

"myArray[x] = makePretty(myArray[x]);"

함수 내에서 할당이 필요한 경우, 변환만 필요한 경우 객체를 전달하고 변환하는 것으로 충분합니다.

당신의 말 뜻을 정확히 알아요.스위프트에서도 같은 것은 문제 없습니다.요점은 사용법입니다.let,것은 아니다.var.

원형이 가치로 전달된다는 사실, 그러나 원형이 가치로 전달된다는 사실var i반복의 시점에서 익명 함수에 복사되지 않는 것은 적어도 놀라운 일이다.

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

참조로 변수를 전달하려면 개체에서 인수를 전달한 후 다음을 사용하여 값을 변경하는 것이 좋습니다.window:

window["varName"] = value;

예:

// Variables with first values
var x = 1, b = 0, f = 15;


function asByReference (
    argumentHasVars = {},   // Passing variables in object
    newValues = [])         // Pass new values in array
{
    let VarsNames = [];

    // Getting variables names one by one
    for(let name in argumentHasVars)
        VarsNames.push(name);

    // Accessing variables by using window one by one
    for(let i = 0; i < VarsNames.length; i += 1)
        window[VarsNames[i]] = newValues[i]; // Set new value
}

console.log(x, b, f); // Output with first values

asByReference({x, b, f}, [5, 5, 5]); // Passing as by reference

console.log(x, b, f); // Output after changing values

이 예시와 같이 JavaScript에서 부족한 부분을 참조로 해결하는 것을 좋아합니다.

여기서 중요한 것은 참조로 를 작성하려고 하지 않는다는 것입니다.대신 반환 기능을 사용하여 여러 값을 반환할 수 있도록 합니다.따라서 어레이나 오브젝트에 값을 삽입할 필요가 없습니다.

var x = "First";
var y = "Second";
var z = "Third";

log('Before call:',x,y,z);
with (myFunc(x, y, z)) {x = a; y = b; z = c;} // <-- Way to call it
log('After call :',x,y,z);


function myFunc(a, b, c) {
  a = "Changed first parameter";
  b = "Changed second parameter";
  c = "Changed third parameter";
  return {a:a, b:b, c:c}; // <-- Return multiple values
}

function log(txt,p1,p2,p3) {
  document.getElementById('msg').innerHTML += txt + '<br>' + p1 + '<br>' + p2 + '<br>' + p3 + '<br><br>'
}
<div id='msg'></div>

여기서 Destructuring을 사용하는 것은 3개의 변수가 있으며 각 변수에 대해 여러 연산을 수행하는 예입니다.

  • 값이 0보다 작으면 0으로 변경합니다.
  • 255보다 크면 1로 변경합니다.
  • 그 이외의 경우는, 0 ~255 의 범위에서 0 ~1 의 범위로 변환하기 위해서, 번호를 255 로 디브 합니다.
let a = 52.4, b = -25.1, c = 534.5;
[a, b, c] = [a, b, c].map(n => n < 0 ? 0 : n > 255 ? 1 : n / 255);
console.log(a, b, c); // 0.20549019607843136 0 1

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

반응형