Pointers in JavaScript?
Asked Answered
H

15

90

Can we pass a reference of a variable that is immutable as argument in a function?

Example:

var x = 0;
function a(x)
{
    x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0
Harvester answered 19/4, 2012 at 15:49 Comment(1)
Arguable this is bad style as you are intending to use side-effects of a function to cause mutation. This can make your code harder to follow.Taught
B
157

Since JavaScript does not support passing parameters by reference, you'll need to make the variable an object instead:

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 this case, x is a reference to an object. When x is passed to the function a, that reference is copied over to obj. Thus, obj and x refer to the same thing in memory. Changing the Value property of obj affects the Value property of x.

Javascript will always pass function parameters by value. That's simply a specification of the language. You could create x in a scope local to both functions, and not pass the variable at all.

Burdette answered 19/4, 2012 at 15:53 Comment(8)
Is there a way of doing it so another person will just do : var x=0;a(x); and that the function set an object with the value of x ? (or something like that)Harvester
Hey, thanks for introducing me to code snippets on SO. Hadn't heard of them before I saw it used in your answer.Nicolenicolea
@Nicolenicolea - Yup, this feature was just added back in September. Very handy!Burdette
What if you don't know the name for the obj property for example if it was obj.name then next time you want to update obj.surname ? How can you make a function adapt to that kind of flexibility?Myalgia
@Dave this may be a late answer but you can make your function expect for 3 parameters, the obj, the property name and the value. Remember you can access a property of an object by doing obj.propertyname or obj['propertyname'] which will be the way you want when you want flexibility. Pass 3 parameters and do obj['propertyname'] = value and that will be reusable.Bandwagon
@Stuffe - In JavaScript, nothing is passed by reference. Everything is passed by value.Burdette
@sir Very late reply: You could pass the name of the member. Like "function foo (o,m) {o[m]=42}", then if you call with "foo(myobj,"bar")" it will set myobj.bar to 42. *Whether this would be good design would depend on the detals.)Hasp
@BasicBlock The handle of the object is passed by value. If it was passed by reference, then if you wrote "function(myobj) {myobj=otherobj}", when the function return myobj would be changed. Which it isn't.Hasp
D
19

This question may help: How to pass variable by reference in javascript? Read data from ActiveX function which returns more than one value

To summarise, Javascript primitive types are always passed by value, whereas the values inside objects are passed by reference (thanks to commenters for pointing out my oversight). So to get round this, you have to put your integer inside an object:

var myobj = {x:0};

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

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

  
Dictionary answered 19/4, 2012 at 15:52 Comment(4)
Object variables are always passed by value as well -- it's just that the value is a reference to an object. There's a difference between passing by reference and passing a reference by value. Namely, when you pass x by value, whether x is an object or not, you can't replace it with a whole other value in any way the caller will see.Wapiti
whereas objects are passed by reference is simply not true. Nothing in JavaScript is passed by reference.Burdette
If you pass a primate type by value (is referenced to by x), why does x not change after, unless you pass the objectMckenna
To put it another way, if you wrote function foo(o) {o2.x=2; o=o2}, and then call it with let oo={x:1}; foo(oo); console.log(oo.x), the output is "1", not "2". Changing o in the function does not change o in the caller. It is passed by value, not by reference. This may seem confusing since o itself is an object handle which is like a reference.Hasp
B
14

I have found a slightly different way implement pointers that is perhaps more general and easier to understand from a C perspective (and thus fits more into the format of the users example).

In JavaScript, like in C, array variables are actually just pointers to the array, so you can use an array as exactly the same as declaring a pointer. This way, all pointers in your code can be used the same way, despite what you named the variable in the original object.

It also allows one to use two different notations referring to the address of the pointer and what is at the address of the pointer.

Here is an example (I use the underscore to denote a pointer):

var _x = [ 10 ];

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

foo(_x);

console.log(_x[0]);

Yields

output: 20
Beiderbecke answered 19/1, 2014 at 21:21 Comment(0)
L
8

You refer to 'x' from window object

var x = 0;

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

a('x');                   // string
alert(x);
Litman answered 23/12, 2014 at 15:45 Comment(0)
P
4

Late answer but I have come across a way of passing primitive values by reference by means of closures. It is rather complicated to create a pointer, but it works.

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, the code can be shortened to use lambda expressions:

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(() => myName, v => myName = v);

helloWorld(myNamePtr); // joe, jack
console.log(myName); // jack
Proximate answered 29/6, 2015 at 17:49 Comment(0)
H
3

Javascript should just put pointers into the mix coz it solves a lot of problems. It means code can refer to an unknown variable name or variables that were created dynamically. It also makes modular coding and injection easy.

This is what i see as the closest you can come to c pointers in practice

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
Hatty answered 21/2, 2016 at 16:45 Comment(0)
M
2

In JavaScript that would be a global. However, your function would look more like this:

function a(){
   x++;
};

Since x is in the global context, you don't need to pass it into the function.

Mannose answered 19/4, 2012 at 15:53 Comment(1)
Valid point, though I'd point out the variable doesn't need to be global (and many would advise against doing this ever), it simply needs to be in the same scope as the caller and the callee.Burdette
I
1

It might be impossible since JavaScript doesn't have Perl's "" operator to get a primitive by reference, but there is a way to create an "effectively a pointer" object for a primitive using this pattern.

This solution makes the most sense for when you already have the primitive(so you can't put it into an object anymore without needing to modify other code), but still need to pass a pointer to it for other parts of your code to tinker with its state; so you can still tinker with its state using the seamless proxy which behaves like a pointer.

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);
Indigo answered 29/1, 2017 at 18:7 Comment(0)
S
0

In JavaScript, you cannot pass variables by reference to a function. However you can pass an object by reference.

Salvatore answered 19/4, 2012 at 15:55 Comment(5)
Simply not true. You cannot pass anything by reference in JavaScript.Burdette
The object reference is passed as value, so everything is passed as value.Bandwagon
interesting observation; it seems to be IMPOSSIBLE to create a reference to an existing primitive in JavaScript; once a primitive is bound, any changes to this primitive can never be noticed by its naive referants because the referants point to the value that the variable, which happens to be a primitive; so the only way to "point" to a primitive is if the primitive is wrapped in a variable whose typeof is "Object"; as no other types can store a reference. TLDR; there is no Perl "\" operator in JavaScript; it's either a reference to begin with, or you can never point to it.Indigo
The annoying part of this is when you want to create a bag of shared state eg "window.shared" as a map of references to variables which are currently null/undefined which you will set later; in this case, as you set the values of the state which is currently null/undefined, the "window.shared" variable will not recognize the changes, even though they are stored in an Object type, it's already too late; the "null/undefined" values have to be inside Object types to begin with for this to work, eg [null] [undefined].Indigo
That said, you can be clever and put in functions in such a global variable, which have a getter and setter for each of these not yet set variables, and these functions WILL dynamically find the CURRENT state of the primitive and get/set it, but it can't return a pointer to that variable(but can return a proxy that can effectively behave the same way as that variable and mutate it indirectly, using getters/setters).Indigo
H
0

In your example you actually have 2 variables with the same name. The (global) variable x and the function scoped variable x. Interesting to see that javascript, when given a choice of what to do with 2 variables of the same name, goes with the function scoped name and ignores the out-of-scope variable.

It's probably not safe to presume javascript will always behave this way...

Cheers!

Hultin answered 6/7, 2015 at 23:0 Comment(1)
This answer doesn't add any value to this post. @Mike Christensen's answer is more detailed and already accepted.Kantor
S
0

I'm thinking that in contrary to C or any language with pointers :

/** Javascript **/
var o = {x:10,y:20};
var o2 = {z:50,w:200};
  • obviously in javascript you cannot access to objects o and o2 addresses in memory
  • but you can't compare their address neither : (no trivial possibility to sort them, and then access by dichotomy)

.

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

that's a huge problem :

  • it means that you can list/manage every objects created (allocated) by your application,

  • from that huge list of objects, compute some information about these (how they are linked together for example)

  • but when you want to retrieve the information you created about a specific object, you cannot find it in your huge list by dichotomy : there is no unique identifier per object that could be used as a replacement of the real memory address

this finally means that this is a huge problem, if you want to write in javascript :

  • a javascript debugger / IDE
  • or a specially optimized garbage collector
  • a data structure drawer / analyzer
Sanyu answered 20/10, 2015 at 23:20 Comment(0)
M
0

JavaScript doesn't support passing primitive types by reference. There is a workaround, though.

Put all the variables you need to pass in an object. In this case, there's only one variable, x. Instead of passing the variable, pass the variable name as a string, which is "x".

var variables = {x:0};
function a(x)
{
    variables[x]++;
}
a("x");
alert(variables.x);
Mountebank answered 6/6, 2016 at 15:22 Comment(0)
T
0

Depending on what you would like to do, you could simply save the variable name, and then access it later on like so:

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

var myFavoriteNumber = 6; 

toAccessMyVariable("myFavoriteNumber");

To apply to your specific example, you could do something like this:

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

function a(variableName)
{
    window[variableName]++;
}
a(pointerToX);
alert(x); //Here I want to have 1 instead of 0
Thumbsdown answered 5/3, 2017 at 17:43 Comment(1)
This only works in a browser environment and is specific to window object. Also, it is less recommended to use global variables, since there might already be a variable with the same name.Colonial
G
0

It just doesn't support pointers, end of story :-(.

I would like to add that, while I'm brand new and coming from a C background, from what I'm reading about the event loop and stack, you should keep whichever object as close to its caller as possible. As I'm brand new, I could have this wrong.

A lot of answers here suggest to make it global, but again if I'm reading correctly, that could possibly increase the stack hops and in a way, possibly fragment your event loop needlessly (depending on what the called object is currently doing) .

Also, any example given that mimics pointers, is just 1 in many ways to do the same thing, which will not be a pointer.

Geoid answered 14/12, 2018 at 16:9 Comment(1)
In JS, it is often considered bad practice to make variables global. You should't really need to unless the variable will be heavily used that way. For instance, in a web app, the object representing the current user may be stored globally, however is advised against, as this exposes it to the developer tools and clutters the global namespace. Instead, it's best to use state managers, with global instances, which contain user objects. When fetching the values within objects, these are references, IE pointers. These behave like traditional C pointers, however, can't be allocated manually.Stertorous
E
0

I'll agree with the most quotet answer, but please be aware from 'var' argument, use 'let', or better in this case 'const', because the pointer, or the pointing object shouldn`t be change anytime.

const x = {value: 0};

function foo(obj){
  ++obj.value;
}

foo(x);
alert(x.value);
Esurient answered 3/1, 2022 at 12:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.