JavaScript의 포인터?


81

변하지 않는 변수의 참조를 함수의 인수로 전달할 수 있습니까?

예:

var x = 0;
function a(x)
{
    x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0

변이를 일으키기 위해 함수의 부작용을 사용하려는 의도이므로 이것은 잘못된 스타일입니다. 이로 인해 코드를 따르기가 더 어려워 질 수 있습니다.
spex

답변:


140

JavaScript는 참조에 의한 매개 변수 전달을 지원하지 않으므로 대신 변수를 객체로 만들어야합니다.

var x = {Value: 0};

function a(obj)
{
    obj.Value++;
}

a(x);
document.write(x.Value); //Here i want to have 1 instead of 0

이 경우 x는 객체에 대한 참조입니다. x함수에가 전달 되면 a해당 참조가로 복사됩니다 obj. 따라서, objx메모리에 같은 일을 참조하십시오. 변화 Value의 특성은 obj에 영향을 미치는 Value의 속성을 x.

Javascript는 항상 값으로 함수 매개 변수를 전달합니다. 이것은 단순히 언어의 사양입니다. 당신은 할 수 만들 x두 기능의 로컬 범위에서, 모든에 변수를 전달하지.


다른 사람이 할 수 있도록하는 방법이 있습니까? var x = 0; a (x); 함수가 x 값으로 객체를 설정 했습니까? (또는 이와 비슷한 것)
user1342369

6
저에게 SO에 대한 코드 스 니펫 을 소개해 주셔서 감사합니다 . 당신의 대답에 사용 된 것을보기 전에는 들어 본 적이 없었습니다.
Joeytje50

@ Joeytje50-예, 이 기능 은 지난 9 월에 다시 추가되었습니다. 매우 편리합니다!
Mike Christensen

예를 들어 obj.name이면 obj 속성의 이름을 모르면 다음에 obj.surname을 업데이트하고 싶습니까? 함수가 그러한 유연성에 어떻게 적응하도록 할 수 있습니까?
선생님

1
@Dave 이것은 늦은 대답 일 수 있지만 함수가 3 개의 매개 변수, obj, 속성 이름 및 값을 기대하도록 만들 수 있습니다. 유연성을 원할 때 원하는 방식으로 obj.propertyname 또는 obj [ 'propertyname']을 수행하여 객체의 속성에 액세스 할 수 있습니다. 3 개의 매개 변수를 전달하고 obj [ 'propertyname'] = value를 수행하면 다시 사용할 수 있습니다.
Carlos Calla

19

이 질문이 도움이 될 수 있습니다 : 자바 스크립트에서 참조로 변수를 전달하는 방법? 둘 이상의 값을 반환하는 ActiveX 함수에서 데이터 읽기

요약하자면 Javascript 기본 유형은 항상 값으로 전달되는 반면 객체 내부의 값은 참조로 전달됩니다 (내 감독을 지적한 주석가에게 감사). 따라서이 문제를 해결하려면 정수를 객체 안에 넣어야합니다.

var myobj = {x:0};

function a(obj)
{
    obj.x++;
}

a(myobj);
alert(myobj.x); // returns 1

  


2
객체 변수는 항상 값으로도 전달됩니다. 단지 값이 객체에 대한 참조 일뿐입니다 . 참조전달하는 것과 value 로 참조전달하는 것에 는 차이가 있습니다 . 즉, 객체 x인지 아닌지 값으로 전달할 때 x호출자가 볼 수있는 방식으로 완전히 다른 값으로 바꿀 수 없습니다.
cHao

객체는 참조로 전달되는 반면 단순히 사실이 아닙니다. JavaScript의 어떤 것도 참조로 전달되지 않습니다.
Mike Christensen

영장류 유형을 값으로 전달하는 경우 (x로 참조 됨) 객체를 전달하지 않는 한 x가 변경되지 않는 이유
SuperUberDuper

14

C 관점에서 더 일반적이고 이해하기 쉬운 포인터를 구현하는 약간 다른 방법을 발견했습니다 (따라서 사용자 예제의 형식에 더 적합).

C에서와 같이 JavaScript에서 배열 변수는 실제로 배열에 대한 포인터 일 뿐이므로 포인터를 선언하는 것과 똑같이 배열을 사용할 수 있습니다. 이렇게하면 원래 개체에서 변수의 이름을 지정 했음에도 불구하고 코드의 모든 포인터를 동일한 방식으로 사용할 수 있습니다.

또한 포인터의 주소와 포인터의 주소를 가리키는 두 가지 다른 표기법을 사용할 수 있습니다.

다음은 예입니다 (밑줄을 사용하여 포인터를 나타냄).

var _x = [ 10 ];

function foo(_a){
    _a[0] += 10;
}

foo(_x);

console.log(_x[0]);

수율

output: 20

8

창 개체에서 'x'를 참조합니다.

var x = 0;

function a(key, ref) {
    ref = ref || window;  // object reference - default window
    ref[key]++;
}

a('x');                   // string
alert(x);

3

늦게 대답했지만 클로저를 통해 참조로 원시 값을 전달하는 방법을 발견했습니다. 포인터를 만드는 것은 다소 복잡하지만 작동합니다.

function ptr(get, set) {
    return { get: get, set: set };
}

function helloWorld(namePtr) {
    console.log(namePtr.get());
    namePtr.set('jack');
    console.log(namePtr.get())
}

var myName = 'joe';
var myNamePtr = ptr(
    function () { return myName; },
    function (value) { myName = value; }
);

helloWorld(myNamePtr); // joe, jack
console.log(myName); // jack

ES6에서는 람다 식을 사용하도록 코드를 줄일 수 있습니다.

var myName = 'joe';
var myNamePtr = ptr(=> myName, v => myName = v);

helloWorld(myNamePtr); // joe, jack
console.log(myName); // jack

1

JavaScript에서 그것은 글로벌이 될 것입니다. 그러나 함수는 다음과 유사합니다.

function a(){
   x++;
};

이후 x글로벌 맥락에서, 당신은 함수에 전달할 필요가 없습니다.


1
유효한 점은 변수가 전역일 필요는없고 (많은 사람들이이 작업을하지 않는 것이 좋습니다), 단순히 호출자 및 피 호출자와 동일한 범위에 있어야한다는 점을 지적합니다.
Mike Christensen

1

Javascript는 많은 문제를 해결하는 믹스 코즈에 포인터를 넣어야합니다. 이는 코드가 동적으로 생성 된 알 수없는 변수 이름 또는 변수를 참조 할 수 있음을 의미합니다. 또한 모듈 식 코딩과 삽입을 쉽게 할 수 있습니다.

이것은 실제로 c 포인터에 가장 가깝다고 생각하는 것입니다.

js에서 :

var a = 78;       // creates a var with integer value of 78 
var pointer = 'a' // note it is a string representation of the var name
eval (pointer + ' = 12'); // equivalent to: eval ('a = 12'); but changes value of a to 12

c에서 :

int a = 78;       // creates a var with integer value of 78 
int pointer = &a; // makes pointer  to refer to the same address mem as a
*pointer = 12;   // changes the value of a to 12

1

JavaScript가 Perl의 "\"연산자를 가지고 있지 않기 때문에 참조로 프리미티브를 얻는 것이 불가능할 수도 있지만,이 패턴을 사용하여 프리미티브에 대해 "효과적으로 포인터"객체를 생성하는 방법이 있습니다.

이 솔루션은 이미 프리미티브를 가지고 있지만 (다른 코드를 수정할 필요없이 더 이상 객체에 넣을 수 없지만) 코드의 다른 부분을 수정하기 위해 포인터를 전달해야하는 경우에 가장 적합합니다. 그 상태와 함께; 따라서 포인터처럼 동작하는 심리스 프록시를 사용하여 상태를 조정할 수 있습니다.

var proxyContainer = {};

// | attaches a pointer-lookalike getter/setter pair
// | to the container object.
var connect = function(container) {
    // | primitive, can't create a reference to it anymore
    var cant_touch_this = 1337;

    // | we know where to bind our accessor/mutator
    // | so we can bind the pair to effectively behave
    // | like a pointer in most common use cases.
    Object.defineProperty(container, 'cant_touch_this', {
        'get': function() {
            return cant_touch_this;
        },                
        'set': function(val) {
            cant_touch_this = val;
        }
    });
};

// | not quite direct, but still "touchable"
var f = function(x) {
    x.cant_touch_this += 1;
};

connect(proxyContainer);

// | looks like we're just getting cant_touch_this
// | but we're actually calling the accessor.
console.log(proxyContainer.cant_touch_this);

// | looks like we're touching cant_touch_this
// | but we're actually calling the mutator.
proxyContainer.cant_touch_this = 90;

// | looks like we touched cant_touch_this
// | but we actually called a mutator which touched it for us.
console.log(proxyContainer.cant_touch_this);

f(proxyContainer);

// | we kinda did it! :)
console.log(proxyContainer.cant_touch_this);

0

JavaScript에서는 함수에 대한 참조로 변수를 전달할 수 없습니다. 그러나 참조로 객체를 전달할 수 있습니다.


3
사실이 아닙니다. JavaScript에서는 참조로 아무것도 전달할 수 없습니다.
Mike Christensen

1
객체 참조는 값으로 전달되므로 모든 것이 값으로 전달됩니다.
Carlos Calla

흥미로운 관찰; JavaScript에서 기존 기본 요소에 대한 참조를 만드는 것은 불가능한 것 같습니다. 일단 프리미티브가 바인드되면, 리퍼 런트가 변수가 프리미티브 인 값을 가리 키기 때문에이 프리미티브에 대한 모든 변경 사항은 순진한 리퍼 런트에 의해 알아 차릴 수 없습니다. 따라서 프리미티브를 "지키"하는 유일한 방법은 프리미티브가 typeof가 "Object"인 변수에 래핑 된 경우입니다. 다른 유형은 참조를 저장할 수 없습니다. TLDR; JavaScript에는 Perl "\"연산자가 없습니다. 시작하기위한 참조이거나 결코 가리킬 수 없습니다.
Dmitry

이것의 성가신 부분은 공유 상태의 백을 만들려는 경우입니다. 예를 들어 "window.shared"는 현재 null / undefined 변수에 대한 참조 맵으로 나중에 설정합니다. 이 경우 현재 null / undefined 상태의 값을 설정하면 "window.shared"변수가 변경 사항을 인식하지 못합니다. 변경 사항이 Object 유형에 저장되어 있어도 이미 너무 늦습니다. 이것이 작동하려면 "null / undefined"값이 Object 유형 내에 있어야합니다 (예 : [null] [undefined]).
Dmitry

즉, 아직 설정되지 않은 각 변수에 대한 getter 및 setter가있는 이러한 전역 변수에 영리하고 함수를 넣을 수 있으며 이러한 함수는 동적으로 기본 요소의 CURRENT 상태를 찾아 가져오고 설정합니다. 그러나 해당 변수에 대한 포인터를 반환 할 수 없습니다 (하지만 해당 변수와 동일한 방식으로 효과적으로 동작 할 수있는 프록시를 반환하고 getter / setter를 사용하여 간접적으로 변경할 수 있음).
Dmitry

0

나는 C 또는 포인터가있는 언어와는 반대로 생각하고 있습니다.

/** Javascript **/
var o = {x:10,y:20};
var o2 = {z:50,w:200};
  • 분명히 자바 스크립트 에서는 메모리의 객체 oo2 주소에 액세스 할 수 없습니다.
  • 하지만 당신은 할 수없는 비교 자신의 주소도 : (어떤 사소한 가능성이하는 분류되지 를하고하여 다음 액세스 이분법 )

.

o == o2 // obviously false : not the same address in memory
o <= o2 // true !
o >= o2 // also true !!

그것은 큰 문제입니다.

  • 즉, 애플리케이션에서 생성 (할당) 한 모든 객체를 나열 / 관리 할 수 ​​있습니다.

  • 그에서 거대한 목록 객체, (그들은 예를 들어 서로 연결하는 방법)이에 대한 몇 가지 정보를 계산

  • 그러나 특정 객체에 대해 생성 한 정보를 검색하려는 경우 이분법으로 거대한 목록 에서 찾을 수 없습니다 . 실제 메모리 주소를 대체 할 수있는 객체 별 고유 식별자 가 없습니다.

이것은 마지막으로 자바 스크립트로 작성하려는 경우 이것이 큰 문제임을 의미합니다.

  • 자바 스크립트 디버거 / IDE
  • 또는 특별히 최적화 된 가비지 수집기
  • 데이터 구조 서랍 / 분석기

0

JavaScript는 참조에 의한 기본 유형 전달을 지원하지 않습니다. 하지만 해결 방법이 있습니다.

전달해야하는 모든 변수를 객체에 넣으십시오. 이 경우 변수는 하나뿐입니다 x. 변수를 전달하는 대신 변수 이름을 문자열로 전달하십시오 "x".

var variables = {x:0};
function a(x)
{
    variables[x]++;
}
a("x");
alert(variables.x);


0

수행하려는 작업에 따라 변수 이름을 저장 한 다음 나중에 다음과 같이 액세스 할 수 있습니다.

function toAccessMyVariable(variableName){
  alert(window[variableName]);
}

var myFavoriteNumber = 6; 

toAccessMyVariable("myFavoriteNumber");

특정 예에 적용하려면 다음과 같이 할 수 있습니다.

var x = 0;
var pointerToX = "x";

function a(variableName)
{
    window[variableName]++;
}
a(pointerToX);
alert(x); //Here I want to have 1 instead of 0

이것은 브라우저 환경에서만 작동하며 window객체에 따라 다릅니다 . 또한 같은 이름의 변수가 이미있을 수 있으므로 전역 변수를 사용하는 것은 권장되지 않습니다.
JayJay

0

포인터를 지원하지 않습니다. 스토리 끝 :-(.

추가하고 싶습니다. 저는 새로운 C 배경에서 왔지만 이벤트 루프 및 스택에 대해 읽고있는 내용에서 가능한 한 호출자에 가까운 개체를 유지해야합니다. 내가 아주 새롭기 때문에 나는 이것을 잘못 가질 수 있습니다.

여기에 많은 답변이 그것을 전역으로 만들 것을 제안하지만 올바르게 읽는다면 스택 홉을 증가시킬 수 있으며 어떤 식 으로든 이벤트 루프를 불필요하게 조각화 할 수 있습니다 (호출 된 객체가 현재 수행중인 작업에 따라 다름).

또한 포인터를 모방 한 모든 예는 포인터가 아닌 동일한 작업을 수행하는 여러 가지 방법에서 단지 1입니다.


-1

귀하의 예에서 실제로 동일한 이름을 가진 2 개의 변수가 있습니다. (전역) 변수 x 및 함수 범위 변수 x. 동일한 이름의 2 개의 변수로 수행 할 작업을 선택할 때 자바 스크립트가 함수 범위 이름과 함께 이동하고 범위를 벗어난 변수를 무시한다는 점이 흥미 롭습니다.

자바 스크립트가 항상 이런 식으로 작동한다고 가정하는 것은 안전하지 않습니다.

건배!


이 답변은이 게시물에 어떤 가치도 추가하지 않습니다. @Mike Christensen의 답변은 더 자세하고 이미 받아 들여졌습니다.
Alexander

-1

아니 당신은 할 수 없습니다. 브라우저는 시스템 메모리 및 변수에 대한 액세스 권한을 부여하지 않습니다. 노드와 같은 환경에서는 가능해야하지만 브라우저 내부에서는 해커가 아니면 불가능합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.