Zeiger in JavaScript?

79

Können wir eine Referenz einer Variablen übergeben, die als Argument in einer Funktion unveränderlich ist?

Beispiel:

var x = 0;
function a(x)
{
    x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0
user1342369
quelle
Es ist anzunehmen, dass dies ein schlechter Stil ist, da Sie beabsichtigen, Nebenwirkungen einer Funktion zu verwenden, um eine Mutation zu verursachen. Dies kann es schwieriger machen, Ihrem Code zu folgen.
spex

Antworten:

139

Da JavaScript die Übergabe von Parametern als Referenz nicht unterstützt, müssen Sie die Variable stattdessen zu einem Objekt machen:

var x = {Value: 0};

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

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

In diesem Fall xhandelt es sich um eine Referenz auf ein Objekt. Wenn xan die Funktion übergeben wird a, wird diese Referenz in kopiert obj. Also, objund xbeziehen sich auf das gleiche im Gedächtnis. Das Ändern der ValueEigenschaft von objwirkt sich auf die ValueEigenschaft von aus x.

Javascript übergibt Funktionsparameter immer als Wert. Das ist einfach eine Spezifikation der Sprache. Sie könnenx in einem für beide Funktionen lokalen Bereich erstellen und die Variable überhaupt nicht übergeben.

Mike Christensen
quelle
Gibt es eine Möglichkeit, dies zu tun, damit eine andere Person einfach Folgendes tut: var x = 0; a (x); und dass die Funktion ein Objekt mit dem Wert von x setzt? (oder so ähnlich)
user1342369
6
Hey, danke, dass du mir Code-Snippets auf SO vorgestellt hast . Ich hatte noch nie von ihnen gehört, bevor ich sah, dass sie in Ihrer Antwort verwendet wurden.
Joeytje50
@ Joeytje50 - Ja, diese Funktion wurde erst im September hinzugefügt. Sehr praktisch!
Mike Christensen
Was ist, wenn Sie den Namen für die Eigenschaft obj nicht kennen, beispielsweise wenn es obj.name war, und wenn Sie das nächste Mal obj.surname aktualisieren möchten? Wie können Sie eine Funktion an diese Flexibilität anpassen?
Sir
1
@ Dave Dies kann eine späte Antwort sein, aber Sie können Ihre Funktion für 3 Parameter erwarten lassen, das obj, den Eigenschaftsnamen und den Wert. Denken Sie daran, dass Sie auf eine Eigenschaft eines Objekts zugreifen können, indem Sie obj.propertyname oder obj ['propertyyname'] ausführen. Dies ist die gewünschte Vorgehensweise, wenn Sie Flexibilität wünschen. Übergeben Sie 3 Parameter und machen Sie obj ['propertyyname'] = value. Das ist wiederverwendbar.
Carlos Calla
19

Diese Frage kann helfen: Wie übergebe ich eine Variable als Referenz in Javascript? Lesen Sie Daten aus der ActiveX-Funktion, die mehr als einen Wert zurückgibt

Zusammenfassend lässt sich sagen, dass primitive Javascript-Typen immer als Wert übergeben werden, während die Werte in Objekten als Referenz übergeben werden (danke an Kommentatoren, die auf mein Versehen hingewiesen haben). Um dies zu umgehen, müssen Sie Ihre Ganzzahl in ein Objekt einfügen:

var myobj = {x:0};

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

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

  

n00dle
quelle
2
Objektvariablen werden immer auch als Wert übergeben - der Wert ist lediglich eine Referenz auf ein Objekt. Es gibt einen Unterschied zwischen der Übergabe als Referenz und der Übergabe einer Referenz als Wert . Wenn Sie einen xWert übergeben, unabhängig davon, ob xes sich um ein Objekt handelt oder nicht, können Sie es nicht durch einen ganz anderen Wert ersetzen, wie es der Aufrufer sehen wird.
CHao
wohingegen Objekte als Referenz übergeben werden, ist einfach nicht wahr. Nichts in JavaScript wird als Referenz übergeben.
Mike Christensen
Wenn Sie einen Primatentyp als Wert übergeben (auf den x verweist), warum ändert sich x danach nicht, es sei denn, Sie übergeben das Objekt
SuperUberDuper
13

Ich habe einen etwas anderen Weg gefunden, Zeiger zu implementieren, der vielleicht allgemeiner und aus C-Sicht leichter zu verstehen ist (und daher besser in das Format des Benutzerbeispiels passt).

In JavaScript sind Array-Variablen wie in C eigentlich nur Zeiger auf das Array, sodass Sie ein Array genauso verwenden können wie das Deklarieren eines Zeigers. Auf diese Weise können alle Zeiger in Ihrem Code auf dieselbe Weise verwendet werden, obwohl Sie die Variable im ursprünglichen Objekt benannt haben.

Es erlaubt auch, zwei verschiedene Notationen zu verwenden, die sich auf die Adresse des Zeigers und die Adresse des Zeigers beziehen.

Hier ist ein Beispiel (ich benutze den Unterstrich, um einen Zeiger zu bezeichnen):

var _x = [ 10 ];

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

foo(_x);

console.log(_x[0]);

Erträge

output: 20
William Oliver
quelle
8

Sie verweisen auf 'x' aus dem Fensterobjekt

var x = 0;

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

a('x');                   // string
alert(x);
AlexisK
quelle
3

Späte Antwort, aber ich bin auf eine Möglichkeit gestoßen, primitive Werte durch Verweise durch Verschlüsse zu übergeben. Es ist ziemlich kompliziert, einen Zeiger zu erstellen, aber es funktioniert.

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

In ES6 kann der Code gekürzt werden, um Lambda-Ausdrücke zu verwenden:

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

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

In JavaScript wäre das ein globaler. Ihre Funktion würde jedoch eher so aussehen:

function a(){
   x++;
};

Da xes sich um einen globalen Kontext handelt, müssen Sie ihn nicht an die Funktion übergeben.

Maess
quelle
1
Gültiger Punkt, obwohl ich darauf hinweisen möchte, dass die Variable nicht global sein muss (und viele davon abraten würden), muss sie sich einfach im selben Bereich wie der Anrufer und der Angerufene befinden.
Mike Christensen
1

Javascript sollte nur Zeiger in die Mischung einfügen, da es viele Probleme löst. Dies bedeutet, dass Code auf einen unbekannten Variablennamen oder auf Variablen verweisen kann, die dynamisch erstellt wurden. Es macht auch die modulare Codierung und Injektion einfach.

Dies ist das, was ich als das Beste sehe, was man in der Praxis an c Zeigern erreichen kann

in 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

in 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
Emmanuel Mahuni
quelle
1

Es ist möglicherweise unmöglich, da JavaScript nicht über den Perl-Operator "\" verfügt, um ein Grundelement als Referenz abzurufen. Es gibt jedoch eine Möglichkeit, mithilfe dieses Musters ein "effektiv ein Zeiger" -Objekt für ein Grundelement zu erstellen.

Diese Lösung ist am sinnvollsten, wenn Sie das Grundelement bereits haben (Sie können es also nicht mehr in ein Objekt einfügen, ohne anderen Code ändern zu müssen), aber dennoch einen Zeiger darauf übergeben müssen, damit andere Teile Ihres Codes basteln können mit seinem Zustand; Sie können also weiterhin mit dem nahtlosen Proxy, der sich wie ein Zeiger verhält, an seinem Status basteln.

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);
Dmitry
quelle
0

In JavaScript können Sie keine Variablen als Referenz auf eine Funktion übergeben. Sie können ein Objekt jedoch als Referenz übergeben.

d4rkpr1nc3
quelle
3
Einfach nicht wahr. Sie können in JavaScript nichts als Referenz übergeben.
Mike Christensen
1
Die Objektreferenz wird als Wert übergeben, sodass alles als Wert übergeben wird.
Carlos Calla
interessante Beobachtung; Es scheint UNMÖGLICH zu sein, einen Verweis auf ein vorhandenes Grundelement in JavaScript zu erstellen. Sobald ein Primitiv gebunden ist, können Änderungen an diesem Primitiv von seinen naiven Referenten niemals bemerkt werden, da die Referenten auf den Wert der Variablen verweisen, die zufällig ein Primitiv ist. Der einzige Weg, auf ein Grundelement zu "zeigen", besteht darin, dass das Grundelement in eine Variable eingeschlossen ist, deren Typ "Objekt" ist. da kein anderer Typ eine Referenz speichern kann. TLDR; In JavaScript gibt es keinen Perl-Operator "\". Es ist entweder zunächst eine Referenz, oder Sie können niemals darauf verweisen.
Dmitry
Der ärgerliche Teil davon ist, wenn Sie eine Tasche mit gemeinsam genutztem Status erstellen möchten, z. B. "window.shared" als Zuordnung von Verweisen auf Variablen, die derzeit null / undefiniert sind und die Sie später festlegen werden. In diesem Fall erkennt die Variable "window.shared" beim Festlegen der Werte des Status, der derzeit null / undefiniert ist, die Änderungen nicht, obwohl sie in einem Objekttyp gespeichert sind. Es ist bereits zu spät. Die "null / undefinierten" Werte müssen sich zunächst innerhalb der Objekttypen befinden, damit dies funktioniert, z. B. [null] [undefiniert].
Dmitry
Das heißt, Sie können klug sein und Funktionen in eine solche globale Variable einfügen, die einen Getter und einen Setter für jede dieser noch nicht gesetzten Variablen haben, und diese Funktionen werden den AKTUELLEN Zustand des Grundelements dynamisch finden und ihn abrufen / setzen. Es kann jedoch keinen Zeiger auf diese Variable zurückgeben (es kann jedoch ein Proxy zurückgegeben werden, der sich effektiv genauso verhält wie diese Variable und indirekt mithilfe von Gettern / Setzern mutiert).
Dmitry
0

Ich denke, dass im Gegensatz zu C oder einer Sprache mit Zeigern:

/** Javascript **/
var o = {x:10,y:20};
var o2 = {z:50,w:200};
  • Offensichtlich können Sie in Javascript nicht auf Objekte o und o2 Adressen im Speicher zugreifen
  • aber Sie können ihre Adresse auch nicht vergleichen : (keine triviale Möglichkeit, sie zu sortieren und dann durch Dichotomie zuzugreifen )

.

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

Das ist ein großes Problem:

  • Dies bedeutet, dass Sie alle von Ihrer Anwendung erstellten (zugewiesenen) Objekte auflisten / verwalten können.

  • Berechnen Sie aus dieser riesigen Liste von Objekten einige Informationen über diese (wie sie zum Beispiel miteinander verknüpft sind).

  • Wenn Sie jedoch die Informationen abrufen möchten, die Sie über ein bestimmtes Objekt erstellt haben, können Sie diese nicht durch Dichotomie in Ihrer großen Liste finden : Es gibt keine eindeutige Kennung pro Objekt , die als Ersatz für die reale Speicheradresse verwendet werden könnte

Dies bedeutet schließlich, dass dies ein großes Problem ist, wenn Sie in Javascript schreiben möchten:

  • ein Javascript-Debugger / IDE
  • oder ein speziell optimierter Müllsammler
  • eine Datenstruktur Schublade / Analysator
reuns
quelle
0

JavaScript unterstützt nicht die Übergabe primitiver Typen als Referenz. Es gibt jedoch eine Problemumgehung.

Fügen Sie alle Variablen, die Sie übergeben müssen, in ein Objekt ein. In diesem Fall gibt es nur eine Variable x. Anstatt die Variable zu übergeben, übergeben Sie den Variablennamen als Zeichenfolge "x".

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

Clickbait
quelle
0

Je nachdem, was Sie tun möchten, können Sie den Variablennamen einfach speichern und später wie folgt darauf zugreifen:

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

var myFavoriteNumber = 6; 

toAccessMyVariable("myFavoriteNumber");

Um sich auf Ihr spezielles Beispiel zu beziehen, können Sie Folgendes tun:

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

function a(variableName)
{
    window[variableName]++;
}
a(pointerToX);
alert(x); //Here I want to have 1 instead of 0
Löwin
quelle
Dies funktioniert nur in einer Browserumgebung und ist windowobjektspezifisch. Es wird auch weniger empfohlen, globale Variablen zu verwenden, da möglicherweise bereits eine Variable mit demselben Namen vorhanden ist.
JayJay
0

Es unterstützt nur keine Zeiger, Ende der Geschichte :-(.

Ich möchte hinzufügen, dass Sie, obwohl ich brandneu bin und einen C-Hintergrund habe, nach dem, was ich über die Ereignisschleife und den Stapel lese, jedes Objekt so nah wie möglich an seinem Aufrufer halten sollten. Da ich brandneu bin, könnte ich das falsch machen.

Viele Antworten hier schlagen vor, es global zu machen, aber wenn ich richtig lese, könnte dies möglicherweise die Stapelsprünge erhöhen und in gewisser Weise Ihre Ereignisschleife unnötig fragmentieren (abhängig davon, was das aufgerufene Objekt gerade tut).

Außerdem ist jedes Beispiel, das Zeiger nachahmt, in vielerlei Hinsicht nur 1, um dasselbe zu tun, was kein Zeiger sein wird.


quelle
0

Nein, du kannst nicht. Der Browser gewährt Ihnen keinen Zugriff auf den Systemspeicher und seine Variablen. Es sollte mit einer Umgebung wie einem Knoten möglich sein, aber im Browser ist dies nur möglich, wenn Sie ein Hacker sind.

Ionut Eugen
quelle
-1

In Ihrem Beispiel haben Sie tatsächlich 2 Variablen mit demselben Namen. Die (globale) Variable x und die Variable x mit Funktionsbereich . Es ist interessant zu sehen, dass Javascript, wenn es die Wahl hat, was mit zwei gleichnamigen Variablen zu tun ist, zum Funktionsbereichsnamen passt und die Variable außerhalb des Gültigkeitsbereichs ignoriert.

Es ist wahrscheinlich nicht sicher anzunehmen, dass sich Javascript immer so verhält ...

Prost!

tpaytn
quelle
Diese Antwort fügt diesem Beitrag keinen Wert hinzu. Die Antwort von @Mike Christensen ist detaillierter und bereits akzeptiert.
Alexander
-1

var x = 0; Funktion a () {x ++; } a (x); console.log (x);

amit saini
quelle
Wie beantwortet dies die Frage? Könnten Sie eine Erklärung hinzufügen?
Marsh-Wiggle