59

Consider this javascript code:

var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();

When running this code I get "A". Is this behavior a part of javascript specification and can I rely on it?

niaher
  • 9,460
  • 7
  • 67
  • 86

11 Answers11

69

In other examples, nothing was passed by value; everything was passed by reference.

bar and foo are BOTH pointers

All vars/handles to NON primitive objects in javascript are pointers; pointers ARE native to javascript, they are the default.

var bar = function () { alert("A"); } //bar is a pointer to function1
var foo = bar;  //pointer copied; foo is now also a pointer to function1
bar = function () { alert("B"); };  //bar points to function2
foo();  //foo is still a pointer to function1

You will run into hidden errors and bugs if you think they are copies. Especially so if you work with complex objects. For example

function person(name){this.name = name}
var john = new person("john")
var backup = john
backup.name //john
john.name = "jack"
backup.name //jack, NOT john

To really COPY a non-primitive in javascript takes more work than just a = b. For example:

function person(name){  this.name = name}
var john = new person("john")
var backup = new Object()
backup = JSON.parse(JSON.stringify(john))
backup.__proto__ = john.__proto__   //useful in some cases
john.name = "jack"
backup.name //john
JoshJordan
  • 12,676
  • 10
  • 53
  • 63
siingCoder
  • 691
  • 5
  • 3
  • 3
    Thank you for clarifying this, I was confused searching online if "functions" were primitive when I was told they weren't. – thed0ctor Dec 19 '12 at 10:25
  • 2
    This answer should serve as a proof why we should be learning more computer science and less programming... – EugenSunic Jan 24 '17 at 13:00
  • This answer is completely false. I know this is old but clearly people are still stumbling into this. Javascript does NOT have a concept of pointers whatsoever. Javascript uses references, which are distinctly different from pointers. – Greg Mar 08 '19 at 21:25
  • How so? In, e.g., C++ they were different in that you had to use a dereferencing operator to get the object pointed to by a pointer whereas a reference didn't need dereferencing. But, in JS (like in Java) all pointers are hidden from the developer. There is no explicit dereferencing. So...I don't see why pointer and reference would mean anything different. "Under the hood" it's a value that is a lookup to a location in memory with the value that's pointed to. Whether you call it a pointer or reference doesn't matter. – stuckj Jul 10 '20 at 20:39
39

Yes that is expected and by design.

Your question is basically: does foo reference bar as a pointer or reference would in another language?

The answer is no: the value of bar at the time of assignment is assigned to foo.

cletus
  • 616,129
  • 168
  • 910
  • 942
  • 1
    why is a copy of the value passed when functions aren't primitive types? – thed0ctor Dec 19 '12 at 10:17
  • 6
    Just for clarifying the last sentence of this answer, remember that the 'value of bar' is a 'pointer to the function', not the function itself. So, after `foo = bar`, foo receives a copy -by value- of that pointer, so both foo and bar point to the standalone function object. – drodsou Jun 02 '13 at 11:08
21

I'm a bit late here but I thought I'd give an answer anyways and flesh something out.

It's best not to think in terms of pointers and memory references when discussing the internals of JavaScript (or ECMAScript) when dealing with the specifications. Variables are environment records internally and are stored and referenced by name, not memory address. What your assignment statement is doing, internally and by design, is looking up the environment record name (either "foo" or "bar") and assigning the value to that record.

So,

var bar = function () { alert("A"); }

is assigning the environment record "bar" the value (anonymous function).

var foo = bar;

internally calls GetValue("bar") which retrieves the value associated with the record "bar" and then associates that value with the record "foo". Hence, afterwards the original value of bar can still be used as it's now associated with foo.

Because JavaScript references by string and not memory address is precisely why you can do things like this:

someObject["someProperty"]

which is looking up the value based on the property name.

Bob
  • 7,851
  • 5
  • 36
  • 48
7

You are assigning the value of an anonymous function to a variable not a pointer.
If you want to play with pointers, you can use objects that are passed by reference, not copy.

Here are some examples:

"obj2" is a reference of "obj1", you change "obj2", and "obj1" is changed. It will alert false:

var obj1 = {prop:true},
    obj2 = obj1;
obj2.prop = false;
alert(obj1.prop);

"prop" points to a property that is not an object, "prop" is not a pointer to this object but a copy. If you change "prop", "obj1" is not changed. It will alert true:

var obj1 = {prop:true},
    prop = obj1.prop;
prop = false;
alert(obj1.prop);

"obj2" is a reference to the "subObj" property of "obj1". if "obj2" is changed, "obj1" is changed. It will alert false:

var obj1 = {subObj:{prop:true}},
    obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
Mario
  • 2,397
  • 2
  • 24
  • 41
Mic
  • 24,812
  • 9
  • 57
  • 70
5

Yes, there's nothing special about the fact that the variables are referring to functions, there's no aliasing involved.

var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
3

Yes, this is the correct behavior.

//create variable bar and assign a function to it
var bar = function () { alert("A"); }
//assign value of bar to the newly created variable foo
var foo = bar;
//assign a new function to the variable bar
//since foo and bar are not pointers, value of foo doesn't change
bar = function () { alert("B"); };
//call the function stored in foo
foo();
Amarghosh
  • 58,710
  • 11
  • 92
  • 121
2

This is assigning a variable to an unnamed function, not a pointer to a function

Svetlozar Angelov
  • 21,214
  • 6
  • 62
  • 67
2

Yes, you've created a pointer to the original "A" function. When you reassign bar, you're reassigning it, but you're still leaving any references to the old function alone.

So to answer your question, yes, you can rely on it.

David Morton
  • 16,338
  • 3
  • 63
  • 73
2

Those are not function pointers (and there are no pointers in JS natively). Functions in JS can be anonymous and are first class objects. Hence

function () { alert("A"); }

creates an anonymous function that alerts "A" on execution;

var bar = function () { alert("A"); };

assign that function to bar;

var foo = bar;

assign foo to bar, which is the function "A".

bar = function () { alert("B"); };

rebind bar to an anonymous function "B". This won't affect foo or the other function "A".

foo();

Call the function stored in foo, which is the function "A".


Actually in languages where there are function points e.g. C it won't affect foo either. I don't know where you get the idea of getting "B" on reassignment.

void A(void) { printf("A\n"); }
void B(void) { printf("B\n"); }
typedef void(*fptr_t)(void);
fptr_t foo = A;
fptr_t bar = foo;
bar = B;
foo(); // should print "A"
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
0

I would just like to add this also works for pre-defined named functions as well:

function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();

This will do the same thing, indicating that function names act like array names (pointers).

user3015682
  • 1,215
  • 12
  • 13
0

For each FunctionDeclaration f in code, in source text order do:

Let fn be the Identifier in FunctionDeclaration f.

Let fo be the result of instantiating FunctionDeclaration f as described in Clause 13.

Let funcAlreadyDeclared be the result of calling env’s HasBinding concrete method passing fn as the argument.

If funcAlreadyDeclared is false, call env’s CreateMutableBinding concrete method passing fn and configurableBindings as the arguments.

References

Community
  • 1
  • 1
Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265