I was wondering recently if this is possible: Passing an object to a function and overriding the entire object with a complete different object inside of that function, so that its value is permanently modified. Since objects are passed by reference, I have a feeling that it must work somehow but I have no idea how. To put it in code, it should do something like this:
function a() {
console.log("i am a");
}
function b() {
console.log("i am b");
}
function override(func1, func2) {
func1 = func2;
}
override(a, b);
a(); //"i am b" expected
FIDDLE
This obviously doesn't work because I'm just overriding the variable func1 but I think you get the idea. And I chose to use functions instead of pure objects, because you could easily "override" an object by just deleting its properties and copying the new properties from the second object. But that's not what I want.
And before you ask, I'm not trying to solve any real life problem with this, I'm just asking out of curiosity. So is there a way to achieve this and if not, is there a reason why not?
Thanks!
This doesn't work because although JS passes references to functions that just means that your func1 and func2 parameters end up referring to the same functions (objects) that the identifiers a and b refer to but when you change what func1 refers to that doesn't affect what a refers to.
To put it another way, when you pass an object to a function the function can change the content of the object by modifying, adding or deleting properties, but it can't change which object a variable outside the function refers to. (At least, not via the function's own argument - a function can modify variables in its scope chain up to and including global variables, but it has to do so by referring to them by their own names.)
In your code
function override(func1, func2) {
func1 = func2;
}
func1 is a variable that points to function a and func2 is a variable that points to function b. The statement func1 = func2 makes func1 point to b. It does not change anything outside the function override.
Please use objects to make use of pass by reference. The code given below illustrates how it works.
function a() {
console.log("i am a");
}
function b() {
console.log("i am b");
}
var object1 = {
func1:a
};
var object2 = {
func2:b
}
function override(object1, object2) {
object1.func1 = object2.func2;
}
override(object1, object2);
object1.func1(); //"i am b"
This code is just for demonstration, might not be useful in a real scenario.
Related
Functions are callable objects in javascript so is it possible to redefine a function definition
?
so basically what I am trying to do is:
let a = function(){console.log('first');}
let b = a;
/**
* alter definition of function 'a' something like:
a.redefine(function(){console.log('second');});
*/
b();//should log 'second'
I looked up for javascript function documentation here as well as here but couldn't find any reference on how/where functions definition are actually stored, even tried to inspect a.prototype as well as altering a.prototype.constructor but got nothing.
A workaround on this can be something like:
let functionHolder={
a:function(){console.log('first');}
}
let a = function(){functionHolder.a();}
let b = a;
functionHolder.a=function(){console.log('second');}
b();//would log 'second'
however my ultimate goal is to understand how functions actually work/stored in js and not a workaround just to achieve this.
It's not possible. Once a function has been defined, its "function code" is immutable. The only way for a variable name which references a function to reference different "function code" would be to reassign the variable name to a new function.
Your
functionHolder.a=function(){console.log('second');}
is essentially the same thing - you're reassigning the function that functionHolder.a refers to.
In the specification, when you call a function, you invoke its internal method [[Call]], which eventually leads you to
OrdinaryCallEvaluateBody, which does:
Return the result of EvaluateBody of the parsed code that is F.[[ECMAScriptCode]] passing F and argumentsList as the arguments.
And the ECMAScriptCode internal property is not reassignable - it's only set in FunctionInitialize, when a new function is created (like when you do
<someIdentifier> = function(){console.log('second');}
)
It is possible by turning the b variable into a getter on the window object.
It's not pretty, but it works:
let a = () => "foo";
console.log("a", a());
Object.defineProperty(window, 'b', {
get() { return a; }
});
console.log("b", b());
a = () => "bar";
console.log("b", b());
a is a reference to a function. Call it a "pointer".
b is a copy of that pointer.
When you re-assign a, you're replacing the pointer. If another variable still points to the value behind the old pointer, that value still exists. That's why in your example, b didn't change: b was a pointer to the old function.
That getter is basically a function that's executed without explicitly having to call it, so it always gets the latest result of whatever the getter function does.
I've been learning Javascript with Khan Academy. I'm looking at : http://www.khanacademy.org/cs/speed-circles/964929070
there is a line that reads "var draw = function() {...}" is he defining a function called draw? Or is the variable draw calling some function (which I don't see defined)?
Thanks!
Yes, a function expression is being assigned to the variable named draw. You can even call it:
var draw = function() {
console.log('xyz');
};
draw(); // 'xyz'
In JavaScript, functions are objects, just like arrays and -logically- objects are. As you may have found out already these objects can be assigned to a multitude of variables, but as soon as you change one of these variables, they all change. That's because JS always assigns by value, but a variable is never assigned an object directly: it's assigned a reference to an object:
var obj = {iam: 'an object'};
var reassign = obj;
console.log(obj);//shows object
console.log(reassign);//surprize, shows the same thing
reassign.bar = 'foobar';
console.log(obj.bar);//logs foobar, the variable obj has gained the same property, because it is the same object.
The same applies to functions, being objects, the can be assigned to variables/properties all over the place, but it'll still be the same object/function:
var foo = function()
{
console.log('I am an object');
};
var second = foo;
second();//logs I am an object
console.log(second === foo);//logs true, because they both reference the same thing
Why, then, you might ask is an anonymous function being assigned to a variable, instead of just declaring a function as you'd expect? Well:
function foo(){}
is hoisted, prior to running any code, JS moves all function declarations and variable declarations to the very top of the scope, but in your case, you're not simply defining a function, or declaring a variable: JS has to do something, too: assign a reference to a variable. The function won't be hoisted:
var foo = function()
{
console.log('foo');
};
foo();//logs foo
foo = function()
{
console.log('bar');
};
foo();//logs bar now
If foo were undefined prior to the assignment, you'd get an error. If any code preceded the code above, JS would hoist the variable declaration of foo, but it's value would still be undefined.
What's the point? This will prove useful when you start playing with closures, or if you need the function to differ, depending on a branch (if (x){ foo = functionX} else { foo = functionY;}). These are just 2 reasons why you'd want to avoid scope hoisting... but the most important reason of all ATM has to be redefining a function on the fly
Note that in processing.js (as used by this Khan academy demo), the function draw is automatically called every frame reference doc.
This bit of code overrides the default (empty) implementation of draw so that the given code is called every frame.
Khan academy has a tutorial about this use of the draw function here.
function draw(){ return "Sample"; };
var draw = function(){ return "Sample"; };
are same meaning.
function () { ... } creates a function value. That is, something that can be passed around just as easily as a number, or any other object in javascript.
He then binds it to the name draw for future reference.
He could as well have written
function draw() {
...
}
For these purposes they are equivalent.
If you have the following code:
var global = this;
function A () {
function B () {
return this;
}
return B();
}
var C = new A();
C === global // true
Why does the this in function B refer to the global space and not the this of the object A?
The value of this is determined upon every function call. Because B is called without any context, the value of this is the global object.
It's possible to preserve this in an outer context by simply copying it:
function A() {
var x = this;
function B() {
return x;
}
return B();
}
this has nothing to do with scope, it's not a variable. It's a keyword that evaluates to the currently executing function's object context. The function's object context is determined by how you call it. It doesn't matter where or how the function is defined.
When you call a function like fn() then it is not in object context and the language wrongly attempts to work around it when it should just throw an error at the mere sight of this. This is somewhat fixed in strict mode where it would evaluate to undefined.
When you call a function as a property of some object I.E. obj.fn() then obj is bound to this for that call.
Since it would be clunky having to attach a function to some object just to get the right object context for the call, all functions inherit a .call method that allows you to specify the object context explicitly:
return B.call(this);
To accompany Pointy's correct answer:
The reasoning for this is because you can do whatever you want with functions.
You can return function B from function A, and save it as a global variable.
Or you could append function B as a method to an Object, or a dozen objects.
Or you could use it in an AJAX callback, or use it as a callback from a timer.
Because the engine doesn't know what's going to happen with function B, the language says that this refers to whatever the function is being called on, at the time it's called.
This adds a lot of dynamism to the language, but it also adds a lot of headache, if you're not sure what "this" is pointing to at any given time.
Rule of thumb:
If the function is directly attached as the method of an object, or a function is being called with .call or .apply and being fed a context, like myFunc.call(myObj), then this refers to window.
Okay, I stumbled upon this piece of code..
How come this works? What sort of evil scheme does JavaScript use to resolve variables?
The way I see it, as a C++ kind of guy: the class/object definition contains a non-existent reference to an object of the class being defined. Seriously, how?
(To be honest, I understand partially - I could deduce a strawman concept of how and when JS resolves names.. but maybe this way the question will be of more use to someone else, someday)
Guilty code:
function Sio() {
this.someValue = 5;
this.doStuff = function() {
console.log("look: "+howDoYouResolveThisYouFoulCreature.someValue);
};
}
var howDoYouResolveThisYouFoulCreature = new Sio();
That seems so wrong.
Lots of concepts here, and I'm not sure which one is giving you troubles…
The two most likely ones are new / this and var.
new / this
When you call a function the value of this is determined by the context in which you call it.
If you use the new keyword, you create an instance of the function and make that instance the context.
When you call howDoYouResolveThisYouFoulCreature.doStuff() you are accessing that instance as a global. It would usually make more sense to:
this.doStuff = function() {
console.log("look: "+ this.someValue);
};
Since foo.doStuff() makes foo the context for that invokation of doStuff() (which makes the function reusable between different instances of Sio)
var
Scope in JavaScript is at the function level.
Using var something anywhere inside a function will scope that variable to that function
It is considered good practise to use a single var statement at the top of a function to avoid confusion
Also, the doStuff function is not called before howDoYouResolveThisYouFoulCreature has a value. Until that point all that matters is that the function is syntactically correct, it doesn't matter what type the variable is.
It works because the function() this.doStuff isn't executed before howDoYouResolveThisYouFoulCreature is created. Keep in mind for as many new Sio()'s that you make this will always console.log the howDoYouResolveThisYouFoulCreature.someValue regardless of the variable name that doStuff() is called from.
This works because:
var howDoYouResolveThisYouFoulCreature = new Sio();
... actually resolves into:
var howDoYouResolveThisYouFoulCreature;
howDoYouResolveThisYouFoulCreature = new Sio();
So at the time the function doStuff is assigned, the var is already declared.
Edit: Forget that, I was being foolish. It turns out pimvdb is right, and here's the proof (also on jsfiddle):
function A() {
this.logValue = function() {
if (b === undefined) {
console.log('Wah, wah, wah...');
} else {
console.log(b.someValue);
}
};
}
function B() {
this.someValue = 42;
}
var a = new A();
a.logValue(); // Wah, wah, wah...
var b = new B();
a.logValue(); // 42
So the execution context is the key. When Sio (or, in this case, A) is constructed, it's scoped to where b might, at some point, be defined. The variable isn't resolved until the function is called, at which point it might be defined. Or not. No biggie. :-)
Examine this code
var _class=function()
{
this.Test=100;
this.Callback=function(msg)
{
alert(msg+"\r\n"+this.Test);
}
}
function run(call)
{
call("Hello world");
}
var obj=new _class();
run(obj.Callback);
I got the result :
[Alert]
Hello world
undefined
but when i call
obj.Callback("Hello world")
i got expected
[Alert]
Hello world
100
why ?
thank for help
There's no intrinsic relationship between an object and the functions defined "inside" it. The only thing that determines the value of this (called the "receiving" object) in a function call is the way in which the function is called.
Call a function with object.func(), and this will be bound to object.
Call a function with "call()" or "apply()", and this is determined by the first parameter.
If a function is called without any implicit object context, however, as in your "callback" example, then this won't refer to anything your object — it will refer to window (or whatever the global context is).
The trick is that when you want to use a function as if it were a "method" on an object, such that the relationship remains intact even though the function reference has been yanked away from the object, you can pre-bind this in a couple of ways:
You can wrap the function in another function, so that you explicitly retain this in a closure.
You can use ".bind()" to (essentially) do the same thing.
The first way would look like this:
run(function() { obj.Callback(); });
The second way would look like this:
run(obj.Callback.bind(obj));
JavaScript is quite different from languages like C# or Java in this respect. In those languages, a function is sort-of stuck forever in a relationship with its class (or instances of its class). Not JavaScript; it really doesn't matter at all, in fact, where a function is defined. Your "_class" function would be equivalent if it were written like this:
function helloThere() {
alert(msg + "\r\n" + this.Test);
}
var _class = function() {
this.Test = 100;
this.Callback = helloThere;
};
edit — #jamietre correctly notes that had your "_class" function contained some var declarations or local functions, then there most certainly would be a difference (though not with respect to the way this behaves when "Callback" is invoked).
edit again — Thanks #Koolinc
this.Test is not defined. The scope of this in that context is the callback function.
This is a quick fix:
var _class=function()
{
var self = this;
this.Test=100;
this.Callback=function(msg)
{
console.log(msg+"\r\n"+self.Test);
}
}