redefine function definition in javascript without reassigning it - javascript

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.

Related

How to use in-scope variables in functions passed as parameter

This is probably a basic question, and I am aware that there have been some similar questions around here, but still I did not find an answer. Please consider the following code:
function Outer(inner2) {
var x = 5;
this.inner1 = function() {return (x);}
this.inner2 = inner2.bind(this);
}
var outer = new Outer(function() {return (x);});
alert(outer.inner1()); // works
alert(outer.inner2()); // does not work
If I would replace the second line by this.x = 5;, the second alert would work. So I guess the problem is that x when declared with var is not part of this, so that bind will have no effect.
Is there any way to make this work without using this.x?
Is there any way to make this work without using this.x?
No.
Btw, you probably don't even need to use bind, just calling inner2 as a method on the object would suffice when both the constructor and the method use this.x.
If you don't want to make x a property of the object, but keep it as a local variable, the usual strategy would be to pass it to the callback as an argument, not trying to somehow make it available in its scope implicitly:
function Outer(callback) {
var x = 5;
this.inner1 = function() { return x; };
this.inner2 = function() { return callback(x); };
// ^^^
}
var outer = new Outer(function(y) { return y; });
// ^ ^
alert(outer.inner1()); // works
alert(outer.inner2()); // works
I think you need clarification on what the word "this" is referring to.
"this" is not pointing to the function "Outer."
When you invoke a constructor function with the "new" keyword, a few things happen.
The constructor function returns an object.
The "this" variable is changed, so that it is set to point to that object that is returned.
(Also, the .proto of the object returned is set to the .prototype of the constructor function, but that step is not relevant here).
So, you are binding the callback function to the object that you are returning from the constructor function, not the constructor function itself.
Thus, the callback function is bound to outer (with a lower-case), not outer (with an upper-case).
Also, when you bind, you are not binding to the scope of a function. X is not assigned to any property. I think you only can bind to an object and access its properties with this.a etc.
The x in the first function worked because its value was assigned in the scope of the function.
I found an, albeit ugly, solution:
function Outer(inner2) {
var x = 5;
this.inner1 = function() {return (x);}
eval('this.inner2 = ' + inner2.toString());
}
This works and shows my point: the parameter inner2 is just a prescription of how this.inner2 should look like; it is never invoked itself.
Let me know, if you have a neater solution than this.

how to interpret "this" in this example

Hello I am a javascript beginner and I read about how to interpret the this keyword but in this example I am still confused:
<script>
function example(param) {
this.a = param;
var b = true;
this.getB = function() {
return b;
}
this.setB = function(x) {
b = x;
}
}
document.write(window.a); //prints "undefined" (line A)
document.write(window.b); //prints "undefined" (line B)
document.write(window.getB(); //generates an error "undefined is not a function (Line C)"
For Line A, I guess the explanation is that this refers to the object that owns the function example, in this case, the window object. Therefore you can reference window.a, but it is not defined so it prints undefined
I cannot understand Line B. Isn't var b restricting b to a local scope? Which should mean that you can only reference b within the function? I was expecting Line B to generate an error, not printing undefined.
I have totally no clue about Line C, why does it generate an error, and what does this mean in this case?
Many thanks!
The this variable depends on how the function is being used.
If you instantiate the function (treat it like a class) then this will refer to the instance of the class:
new example("foo").getB(); // `this` is an instance of example
If you call it with Function.prototype.call then this will refer to whatever object you passed to the call method:
example.call(anotherObject, "foo"); // `this` refers to anotherObject
If you just execute it directly then this may refer to the window or whatever other surrounding scope.
example("foo"); // `this` likely refers to the window object
You can also use Function.prototype.bind to wrap your function in a specific scope to help clear things up:
var wrappedExample = example.bind(aSpecificObject);
wrappedExample(); // Doesn't matter how it's called, `this` will refer to aSpecificObject
Of course you may want to consider your target browsers before using bind (or use a polyfill).
First - you never call the example() function. So nothing it does has any effect.
Second - you have a syntax error on the last line, you are missing a ).
If you were to fix those issues, the results would be different:
function example(param) {
this.a = param;
var b = true;
this.getB = function() {
return b;
}
this.setB = function(x) {
b = x;
}
}
example("data");
document.write(window.a); //prints "undefined" (line A)
document.write(window.b); //prints "undefined" (line B)
document.write(window.getB()); //generates an error "undefined is not a function (Line C)"
For Line A, I guess the explanation is that "this" refers to the object that owns the function "example", in this case, the window object. Therefore you can reference window.a, but it is not defined so it prints "undefined"
It wasn't defined because you weren't calling the function. If you were to call it, then it is defined as the value of param.
I cannot understand Line B. Isn't "var b" restricting b to a local scope? Which should mean that you can only reference b within the function? I was expecting Line B to generate an error, not printing "undefined".
The locally scoped variable b is distinct from the b property of the object that is stored in this.
Accessing an undefined property of an object doesn't throw an error in JavaScript, it gives you undefined.
If you were to access an undeclared variable, then you would have a Reference Error.
I have totally no clue about Line C, why does it generate an error, and what does "this" mean in this case?
As with the other examples, you don't use this for lines A, B or C. You use window. this is only used inside the function.
You were getting an error because you never ran the function, so window.getB was never set. Calling the undefined value as a function throws an error.
If you fix the problem, as described above, you get the value of the local b variable.
If you are using this within a function, it will refer to the global window object.
function whatsThis(){
console.log(this);
}
whatsThis(); //displays the window object
If the function exists within an object created by a constructor function, however, this will refer to the parent object
var WhatsThis = function(){
this.showThis = function(){
console.log(this);
};
};
var obj = new WhatsThis();
obj.showThis(); //displays the instance of WhatsThis
Likewise with object literals, this refers to the containing object.

Understanding JavaScript this with private function and self executing function

I was reading Angus Croll understanding JS this blog and found this
var a = {
b: function() {
var c = function() {
return this;
};
return c();
}
};
a.b();//window
To me it looks like, at the time of invoking c, c was inside b. that should be the invoking context (correct me, if i am wrong). when it executes, Why context(this) of c() is window?
there is another example i found in that blog
var a = {
b: function() {
return (function() {return this;})();
}
};
a.b(); //window
why context of b is window? Does anonymous function always run in the global context?
Here's a good way to understand this (pun intended):
The value of this inside a function is determined by the way the function is called. With one exception, it doesn't have to do with where the function is defined, what other functions it may be nested inside, what object it was defined as part of, what kind of function it is, or any of that.
When you call a function using a method call like foo.bar() or foo[bar](), this inside the function is the foo object.
When you call a function with an ordinary function call like foo(), this in the function is the window object, or if the function uses strict mode it is undefined.
That's the one exception - if the function itself or its surrounding code has "use strict"; it changes this for a plain function call. For good code that shouldn't make a difference - you shouldn't be writing code that depends on this being the window object anyway.
Otherwise, what you care about is what object this refers to in a method call. And that's always determined by how the function is called, not how it's defined.
Let's go through your first example.
When you call a.b(), you're calling b as a method of the a object. So inside the b function, this is the same as a.
As it happens, it doesn't do us any good to know that, because the b function never does anything with this. All it does is call c() as an ordinary function. So inside c, this is the window object, or it would be undefined if you were in strict mode.
The c function simply returns its this value, or window. And that is also the return value from b. So that's why you see window as the result: it all comes from how the code calls the b and c functions.
Now about the second example: well, that's just terribly obfuscated code, isn't it? Who would ever write this code and expect anyone to understand it at first glance?
So let's turn it into a more readable form. This line is the problem:
return (function() {return this;})();
Let's take out the parenthesized function expression:
(function() {return this;})
and assign it to a temp variable:
var temp = (function() {return this;});
We don't need the extra parentheses any more, and let's indent the code for readability:
var temp = function() {
return this;
};
and we can call that temp variable as a function in the return statement:
return temp();
Now we can put this back into the b function in the code example:
var a = {
b: function() {
var temp = function() {
return this;
};
return temp();
}
};
a.b(); //window
Hey! Doesn't that code look familiar? In fact, it's identical to the first example except for the name of the temp variable. So now you see why it works the same as the first one.
One key to look for is the new keyword, which establishes a new context. Don't see a new? Then the context hasn't changed, which means this hasn't changed. If you called this from within window, then that's your context, and that's your this. (This changes if you use call() or apply() with a scope, but that obviously doesn't apply here.)

Verifying my understanding of the scope chain

(Question 1)
In Flanagan's JS Definitive Guide, he defines the Function method bind() in case it's not available (wasn't available n ECMAScript 3).
It looks like this:
function bind(f, o) {
if (f.bind) return f.bind(o); // Use the bind method, if there is one
else return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
He illustrates the use of it with an example (which I have modified to change the 3rd line from f.bind(o)):
function f(y) { return this.x + y; } // This function needs to be bound
var o = { x : 1 }; // An object we'll bind to
var g = bind(f, o); // Calling g(x) invokes o.f(x)
g(2) // => 3
When I first saw this, I thought "Wouldn't arguments refer to the arguments variable within the bind function we're defining? But we want the arguments property of the function we eventually apply it to, like g in the example above..."
I verified that his example did indeed work and surmised that the line return f.apply(o, arguments) isn't evaluated until var g = bind(f, o) up above. That is, I thought, when you return a function, are you just returning the source code for that function, no? Until its evaluated? So I tested this theory by trying out a slightly different version of bind:
function mybind2(f, o) {
var arguments = 6;
return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
If it's simply returning tbe unevaluated function source, there's no way that it stores arguments = 6 when later evaluated, right? And after checking, I still got g(2) => 3. But then I realized -- if it's just returning unevaluated code, how is the o in return f.apply(o, arguments) getting passed?
So I decided that what must be happening is this:
The o and the arguments variables (even when arguments equals 6) are getting passed on to the function. It's just that when the function g is eventually called, the arguments variable is redefined by the interpreter to be the arguments of g (in g(2)) and hence the original value of arguments that I tried to pass on was replaced. But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
(Question 2) Earlier on the same page, he defines the following function which makes use the apply method to trace a function for debugging:
function trace(o, m) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
Question 1
For your first question, let's simplify the example so it's clear what being done:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
What happens here is that a closure is created that allows the access of the original function and the value of this that is passed. The anonymous function returned will keep the original function in its scope, which ends up being like the following:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
About your issue with arguments, that variable is implicitly defined in the scope of all functions created, so therefore the inner arguments will shadow the outer arguments, making it work as expected.
Question 2
Your problem is to your misunderstanding of the late binding of this -- this is one of the more confusing things about JavaScript to people used to more object-oriented languages that also have their own this keyword. The value of this is only set when it is called, and where it is called defines the value of this when it is called. It is simply the value of the parent object from where it is at the time the function is called, with the exception of cases where the this value is overridden.
For example, see this:
function a() {return this;};
a(); // global object;
var b = {};
b.a = a;
b.a(); // object b
If this was set when the function was defined, calling b.a would result in the global object, not the b object. Let's also simplify what happens with the second function given:
function trace(obj, property) {
var method = obj[property]; // Remember original method in the closure.
obj[property] = function () { // Now define the new method.
console.log(1); // Log message.
// Invoke original method and return its result
return original.apply(this, arguments);
};
}
What happens in this case is that the original method is stored in a closure. Assigning to the object that the method was originally in does not overwrite the method object. Just like a normal method assignment, the principles of the this value still work the same -- it will return the parent object, not the function that you've defined. If you do a simple assignment:
var obj = {};
obj.foo = function () { return this; };
obj.foo(); // obj
It does what was expected, returns the parent object at the time of calling. Placing your code in a nested function makes no difference in this regard.
Some good resources
If you'd like to learn more about writing code in JavaScript, I'd highly recommend taking a look at Fully Understanding the this Keyword by Cody Lindley -- it goes into much more detail about how the this keyword behaves in different contexts and the things you can do with it.
But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
No. this and arguments are just special variables which are implicitly set when a function is executed. They don't adhere to normal "closure rules". The function definition itself is still evaluated immediately and bind returns a function object.
You can easily verify this with:
var g = bind(f, o);
console.log(typeof g);
Here is a simpler example which doesn't involve higher order functions:
var arguments = 42;
function foo() {
console.log(arguments);
}
foo(1, 2);
I think you see that the definition of foo is evaluated like you'd expect. Yet, console.log(arguments) logs [1, 2] and not 42.
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
this never refers to the function itself (unless you explicitly set it so). The value of this is completely determined by how the function is called. That's why this is often called "the context". The MDN documentation provides extensive information about this.
Reading material:
MDN - this
MDN - arguments

Please explan this javascript function definition and their best use (Module Pattern)

What type of function is the following and which is their best use?
var f = function (){
var a = 0;
return {
f1 : function(){
},
f2 : function(param){
}
};
}();
I tried to convert it to:
var f = {
a : 0,
f1: function (){
},
f2: function (param){
}
}
But seems does not works the same way.
It's just a plain old function that is invoked immediately, and returns an object which is then referenced by f.
The functions referenced by object returned retain their ability to reference the a variable.
No code outside that immediately invoked function can reference a so it enjoys some protection since you control exactly what happens to a via the functions you exported.
This pattern is sometimes called a module pattern.
Regarding your updated question, it doesn't work the same because a is now a publicly available property of the object.
For the functions to reference it, they'll either do:
f.a;
or if the function will be called from the f object, they can do:
this.a;
Like this:
var f = {
a : 0,
f1: function (){
alert( this.a );
},
f2: function (param){
this.a = param;
}
}
f.f2( 123 );
f.f1(); // alerts 123
But the key thing is that a is publicly available. Any code that has access to f can access f.a and therefore make changes to it without using your f1 and f2 functions.
That's the beauty of the first code. You get to control exactly what happens to a.
Basically that creates a "class" - JS doesn't have classes so a class is basically a function such as your function f.
The interesting thing about the code you posted is that it creates a private variable a and two public functions f1 and f2. They are public because the constructor - the outer function - returns them.
This is a common pattern for organising and encapsulating JS code.
You can read more about it here
It's a simple function to create and return an object. It's immediately executed, and its result is saved to your variable f
It first declares a local (or private) variable a, visible only withing the scope of the function. Then it constructs an object which has members f1 and f2, both of which are functions. Since this return object is declared within the same scope that a is declared, both f1 and f2 will have access to a.
Your conversion simply creates a single object. Where before you had a function that would create endless objects, you now have a single object, and no more. I'm not sure exactly why it doesn't work, but one major difference is that a is now visible to the world, where before it was private to the return object.

Categories

Resources