function F () {
var color = "red";
this.fun = function f () {
console.log(color);
};
};
var i = new F();
i.fun();
I'm a bit confused to what new F() / new F is.
Here's what I know about the new keyword:
i) It creates {} either in constructor function or somehow related to constructor function.
ii) this in constructor function references this empty object and
iii) makes constructor function return this object unless you specify constructor function to return something else instead. So my first thought is that in the code above, new F() returns { fun: [Function: f] }.
When you console.log(new F()); what comes is slightly different:
F { fun: [Function: f] }
It look like an object, however this behaviour makes it apparent it's more complicated:
i.fun() returns "red". A method of this object is able to access
variables inside the constructor function that made it. If it were
purely a basic object it wouldn't be able to do that.
Right now, my only idea is that new F() is an object that is able to see the scope of the constructor function that made it.
Disclaimer: I am aware of what closures are and I know how function f could see color in F. I thought what was going on was a copy of function f was being added as a value in a brand new object which is assigned to i. Therefore, how does function f, in this brand new object, see the color variable in a completely separate function, F?
For example:
function F (v) {
var v = v;
var color = "red";
this.fun = function f () {
console.log(color);
};
};
var i = {fun: function f() {console.log(color)}};
i.fun() //returns 'color' is not defined.
There's another step when new F() is used:
iv) It sets the prototype of the object to an object like {contructor: F}.
This is why the object is logged as F { fun: [Function f] } instead of just {fun: [Function f] }. Objects with a prototype other than the standard Object prototype are shown with the name of the constructor function as a prefix.
As far as access to the variable color is concerned, it's no different from any other nested function, is a closure that captures variables from the containing environment. It's no different from writing an ordinary function like this:
function F() {
var color = 'red';
let fun = function f() {
console.log(color);
};
return {
fun: fun
}
}
let i = F()
i.fun()
Using new has no effect on the way variables are captured in a closure.
When you assign this.fun = function f ... it just stores the closure in the fun property. JavaScript never makes copies of objects, functions, etc. unless you do so explicitly -- assignments always assign references to the object.
You can even copy the closure to another object, it will still retain its access to the original environment. Since the function doesn't refererence this, it doesn't care how it's called.
var foo = {};
foo.fun2 = i.fun;
foo.fun2() // will log "red"
When you call new F() the following steps are performed (from MDN):
Creates a blank, plain JavaScript object;
Links (sets the constructor of) this object to another object;
Passes the newly created object from Step 1 as the this context;
Returns this if the function doesn't return an object.
So when executing the code var i = new F(); you have the following steps:
Create a new object. {} The prototype of this new object is set to F.prototype.
Set the constructor of this object to the function F. This changes the display to F {}
Bind the function F to the object and execute F. That means this within the body of F() refers to the object F {} we are carrying from Step 2.
The new keyword causes the expression to return that object if the return type of F() is undefined (which it is, as there's no value returned).
During step 3, F is executed, with this as an empty object F {}.
The first line var color = "red"; is executed. It defines and assigns a variable, nothing special.
The second line is executed. this.fun = function f() { ... }; The function must be evaluated first before the assignment.
During the evaluation of the function, a closure is created around all variables in scope. A specific reference to this instance's declaration of the variable color is captured in scope. The function f, even when referenced outside of F, carries this closure with it. Anywhere it is executed, it carries the same closure which was captured during evaluation of this line. This closure has the variable color, so no matter where it's passed around and executed, it still knows what the variable color is. This is how closures work.
Hopefully that last paragraph clears up why this works the way it does for you.
To specifically address your last example:
var i = {fun: function f() {console.log(color)}};
The function f() in this context was not evaluated with color in its scope. The closure captured during the evaluation of this line of code does not include color, because color is a local variable only defined in the scope of a current execution of the function F().
Javascript has constructor functions, you can do:
class F {
constructor() { this.color = "red"; }
fun() {
console.log(this.color);
}
};
Then you have to call that with new F();
When not calling a constructor specifically you can call any function with new, which has the effect of making the this function inside the function apply to the function itself. You can call it with apply and set this to whatever you want.
For that reason a common convention in JS was to name functions that expected to be called with new with CapitalCase, and those that didn't with camelCase. So you could just call fooBar() however you wanted, but would expect bugs if you had new FooBar() without the new.
Therefore, how does function f, in this brand new object, see the color variable in a completely separate function, F?
It doesn't, f is inside F and sees the var color declared across that scope. Functions inherit the scope of anything they're declared inside. f can see the rest of F, but F can't see the closure inside f.
You are able to access color (value: red) beacuse of closure as you mentioned.
Since color variable was available at the time of function f / fun declaration. It saves it value as a closure variable.
If you want separate copies of color variable as well. Define it on this like following:
function F (color) {
this.color = color;
this.fun = function f () {
console.log(this.color);
};
};
var i1 = new F("green");
var i2 = new F("red");
i1.fun(); // green
i2.fun(); // red
In your second code snippet you are getting color as undefined because there is no color variable declared in same scope as function f (inside i object) or globally.
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 know that we can set a function property as below
function f(){}
f['a']=1;//setting function property from outside
alert(f.a)//alert 1
But is it possible to set a property of function as below or is there any other similar way of declaring properties inside a function,rather than from outside?
function f() {
a: 1
}
alert(f.a); //get 1 as output
EDIT:
Looking for some way which does not use any object creation from the function constructor or use prototypes
No, there is not. Inside the function goes only the body, i.e. the code that is executed when the function is called. A function literal / declaration is not an object literal, even if both use curly braces.
If you're looking for a more declarative way than assignment to put static properties on a function, use some kind of extend functionality:
var f = Object.assign(function f() {}, {
a: 1
});
(all of _.extend, $.extend, Object.assign will work for this purpose - otherwise just use f.a =)
The only way this can be done is if the function is invoked with the new keyword:
var f = function() {
this.a = 4;
}
var test = new f();
alert(test.a); // 4
I've published some more tests on this jsfiddle:
http://jsfiddle.net/j4svr90x/2/
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.
Consider the following code:
function A() {}
A.prototype.go = function() {
console.log(this); //A { go=function()}
var f = function() {
console.log(this); //Window
};
f();
}
var a = new A();
a.go();
Why does 'this' inside function 'f' refers to the global scope? Why it is not the scope of function 'A' ?
JavaScript has a different concept of what the special name this refers to
than most other programming languages do. There are exactly five different
ways in which the value of this can be bound in the language.
The Global Scope
this;
When using this in global scope, it will simply refer to the global object.
Calling a Function
foo();
Here, this will again refer to the global object.
ES5 Note: In strict mode, the global case no longer exists.
this will instead have the value of undefined in that case.
Calling a Method
test.foo();
In this example, this will refer to test.
Calling a Constructor
new foo();
A function call that is preceded by the new keyword acts as
a constructor. Inside the function, this will refer
to a newly created Object.
Explicit Setting of this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // array will expand to the below
foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
When using the call or apply methods of Function.prototype, the value of
this inside the called function gets explicitly set to the first argument
of the corresponding function call.
As a result, in the above example the method case does not apply, and this
inside of foo will be set to bar.
Note: this cannot be used to refer to the object inside of an Object
literal. So var obj = {me: this} will not result in me referring to
obj, since this only gets bound by one of the five listed cases.
Common Pitfalls
While most of these cases make sense, the first one is to be considered another
mis-design of the language because it never has any practical use.
Foo.method = function() {
function test() {
// this is set to the global object
}
test();
}
A common misconception is that this inside of test refers to Foo; while in
fact, it does not.
In order to gain access to Foo from within test, it is necessary to create a
local variable inside of method which refers to Foo.
Foo.method = function() {
var that = this;
function test() {
// Use that instead of this here
}
test();
}
that is just a normal variable name, but it is commonly used for the reference to an
outer this. In combination with closures, it can also
be used to pass this values around.
Assigning Methods
Another thing that does not work in JavaScript is function aliasing, which is
assigning a method to a variable.
var test = someObject.methodTest;
test();
Due to the first case, test now acts like a plain function call; therefore,
this inside it will no longer refer to someObject.
While the late binding of this might seem like a bad idea at first, in
fact, it is what makes prototypal inheritance work.
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
When method gets called on a instance of Bar, this will now refer to that
very instance.
Disclaimer: Shamelessy stolen from my own resources at http://bonsaiden.github.com/JavaScript-Garden/#function.this
The reason why is you are invoking f as a function and not a method. When invoked as a function this is set to window during the execution of the target
// Method invocation. Invoking a member (go) of an object (a). Hence
// inside "go" this === a
a.go();
// Function invocation. Invoking a function directly and not as a member
// of an object. Hence inside "f" this === window
f();
// Function invocation.
var example = a.go;
example();
The scope of all functions is window.
To circumvent that, you can do this:
function A() {}
A.prototype.go = function() {
var self = this;
console.log(self); //A { go=function()}
var f = function() {
console.log(self); //A { go=function()}
};
f();
}
Because function f() is not called without any object reference. Try,
f.apply(this);
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.