function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = john.says;
func();
I tried this example when I do this I get the following message undefined rocks! instead of Ruby rocks!.
can u explain why is that.
Function Execution Context and the this Keyword
JavaScript functions have an execution context at invocation time such that the this keyword is bound to the object they are invoked from. If you call john.says() the execution context of the function would have a this keyword that points to john. If you instead assign a global variable func to the method says found on the object john you have changed the execution context to the global object. When you invoke the func function, this dereferences to window (or undefined*) and since window.skill is undefined, says will coerce that value into a string to concatenate it with the string ' rocks!'.
How to guarantee execution context using bind
You can instead bind a copy of the function to an object (effectively locking it's context reference):
var func = john.says.bind(john);
How to guarantee execution context using a closure
Alternately you can close over the relevant bits by using a closure in your constructor:
function Developer(skill){
var _this = this; // we keep a reference here
this.skill = skill;
this.says = function(){
alert(_this.skill + ' rocks!');
// when invoked _this refers to the context at construction
}
return this;
}
How to guarantee a value using a closure
You could just reference the skill value directly from the method and so not need the context at all:
function Developer(skill){
// because skill is defined in this context, says will refer to this context
// to get the value of the skill variable.
this.says = function(){
alert(skill + ' rocks!');
}
}
How to guarantee an execution context at invocation time using call and apply
The final options are to to invoke the method with the context you want at invocation time:
func.call(john /*, optional arguments... */);
func.apply(john /*, optional arguments as an array */);
How to use prototypes to allow the dynamic execution context to set the right this
If we want to reuse a method between object instances or types but have the right execution context when invoked we can use the prototype property.
function Developer(skill){
this.skill = skill;
this.says();
}
Developer.prototype.says = function(){
alert(this.skill + ' rocks!');
}
var john = new Developer("Ruby"); // alert("Ruby rocks!")
var tony = new Developer("JavaScript"); // alert("JavaScript rocks!")
More reading:
Specification for execution contexts: http://ecma-international.org/ecma-262/5.1/#sec-10.3
MDN Docs about this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Fthis
* "use strict" activates a special strict mode representing the future of JavaScript. This special strict executing environment will not resolve to the global object when a context has not been set, instead resolving this to the appropriately scoped value undefined.
Let's illustrate what is happening, by actually returning the object:
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
return this; //this is basically { skill: skill, says: function() {} }
}
var john = new Developer('Ruby');
var func = john.says; // all it knows is the function() part, has no knowledge of skill
func(); //undefined rocks!
Ok, so why are we getting undefined? Well, once we rip out the function, it no longer has context - it doesn't know what this is. If we were to do:
func.apply(john);
Then we are passing in John as the this parameter. A workaround, it to pass the value in to the function when we create it:
function Developer(skill) {
this.skill = skill;
this.says = function(skill) { //<--calling this function
return function() { //<--returning this function
alert(skill + ' rocks!');
};
}(this.skill); //<--passing in the value here
return this;
}
When you call a function, this will refer to the object on which the function was called.
When you say
var func = john.says;
you are just getting the function object (it doesn't remember the object on which it is defined).
When you invoke the function, like this
func();
there is no current object, on which func is invoked. So, by default, JavaScript assigns the global object(window object in browser) as this. Since, skill is not defined in the global object, undefined is returned.
Note: In Strict mode, this will be undefined, if there is no current object.
That is why we have to explicitly bind the object to the function, like this
func.bind(john)();
Function.prototype.bind will return a new function, which is bound to john. So, when you invoke this this will refer john.
Because func() only has the function and not any other related info.(this.skill)
The context is lost. this referred to the john when the says() is called.
But now, when you call func() this refers to the window. Therefore this.skills will return undefined unless you have a global variable of the same name.
the fastest way to keep the above pattern is to bind this direct to the method this.says = function () { ... }.bind(this);:
function Developer(skill) {
this.skill = skill;
this.says = function () {
alert(this.skill + ' rocks!');
}.bind(this);
}
var john = new Developer('Ruby');
var func = john.says;
func(); // Ruby rocks!
try this
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
john.says();
working demo
http://jsfiddle.net/ZENtL/
Related
I've a program with functions as Person, greet, specificCall and objects as kumar and chandra.
var fullName=""
function greet() {
console.log("Welcome "+ this.fullName);
}
var Person=function (name) {
this.fullName=name
console.log(this.fullName)
}
var chandra=new Person("chandrakumar")
var kumar=new Person("kumar")
var specificCall=function(){
console.log("Dude "+ this.fullName);
}
var newGreeting=Person.call.bind(specificCall)// I don't understand the meaning here
newGreeting()// logs Dude
newGreeting(kumar)//logs Dude kumar How is this happening
I think Person.call is a function as I have checked typeof Person.call and specificCall is a function again. How can I bind a function to a function?
Though I wrote this code accidentally I don't understand the logic?
Person.call fires the constructor function whereas newGreeting fires the specificCall function. if you look closely newGreeting(kumar) is equivalent to specificCall.apply(kumar). Here the not only context of the scope is changed but the whole function itself. Its like specificCall is bound to Person.call?
Call allows you to set the scope for a functions exection, defaulting to window, while activating it.
//Set global variable to fallback to
var fullname = "Window";
//Set local variable
var person = {
fullname: "Bob"
};
//Definer caller object
function logObject() {
//"this" references current scope
console.log(this.fullname);
}
//Call with nothing, defaulting to global
logObject.call();
//Call with specific object as scope
logObject.call(person);
Bind sets the scope for a function, but doesn't activate it.
//Set global variable to fallback to
var fullname = "Window";
//Set local variable
var person = {
fullname: "Bob"
};
//Definer caller object
function logObject() {
//"this" references current scope
console.log(this.fullname);
}
//Bind with nothing, defaulting to global
var logger1 = logObject.bind();
//Execute
logger1();
//bind with specific object as scope
var logger2 = logObject.bind(person);
//Execute
logger2();
As far as i can tell, you bind specificCall to a call on Person, meaning that firing newGreeting is the same as running Person.call but with specificCall as the bound scope.
It's not pretty code and i would personally recommend a more readable structure:
var fullName = "window";
var Person = function (name) {
this.fullName = name;
};
var chandra = new Person("chandrakumar");
var kumar = new Person("kumar");
function specificCall(scope) {
if (scope === void 0) { scope = window; }
console.log("Dude " + scope.fullName);
}
specificCall(); // logs Dude window
specificCall(kumar); //logs Dude kumar
Here I have copied code snippet from MDN : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.declare = function() {
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
};
var flower = new LateBloomer();
flower.bloom();
// after 1 second, triggers the 'declare' method
The most confusing part is : window.setTimeout(this.declare.bind(this), 1000);
I understand how this works and this inside settimeout is always bound to global object.I know there can be var self or var that inside bloom function.
There are two this in that line but which this refers to what and how that works is totally confusing.
How works?
First of all read this article, which offers a very nice explanation about how this works.
.bind(this, args) just helps you to pass your this context inside your function (because inside it in your example by default this is undefined or refers to window).
Also bind is a nice alternative to this:
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
var self = this;
window.setTimeout(self.declare, 1000);
};
And as the last point in es6 you can do it in this way:
window.setTimeout(() => {
//do some stuff
}, 1000);
instead of
window.setTimeout(function () {
//do some stuff
}.bind(this), 1000);
this allow you to not think about this.
MSDN defines Function.prototype.bind() as,
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
By using .bind(this) we are passing this to the function declare
See this snippet.
function LateBloomer() {
console.log(this.constructor);
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.undefinedbloom = function() {
window.setTimeout(this.declare, 1000);
};
LateBloomer.prototype.declare = function() {
console.log(this.constructor);
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
};
var flower = new LateBloomer();
flower.bloom();
flower.undefinedbloom();
In the function undefinedbloom we are just calling the declare function. So the object will be the window object. It doesn't have property petalCount so its undefined.
In the function bloom we are binding the this of LateBloomer to the declare function by which we will have access to the LateBloomer's object petalCount.
this in JavaScript is a very difficult to fathom at first.
MDN Link: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this
function LateBloomer() {
this.name = 'triven'; //simplified property
}
// Some thoughts we discuss main requirement.
LateBloomer.prototype.bloom = function() {
window.setTimeout(function() {console.log(this);}, 1000); //Logs window: We all know that keyword this INSIDE CALLBACK
//function refers to Window [Comment 1]
//window.setTimeout(console.log(this), 1000); /Attentions: Here it is very easy to MISUNDERSTAND
//that keyword this is inside setTimeout and it should refer to window.
//Please note that here keyword this is not INSIDE CALLBACK function so here
//keyword this will refer to object on which its wrapper function is
//executed(in our case flower). [Comment 2]
};
//The requirement: We need to call .bloom and it should log name after 1 second.
LateBloomer.prototype.bloom = function() {
//here keyword this refers to object
//window.setTimeout(function() {console.log(this);}, 1000); //But inside callback keyword this refers to window.
};
//We need some way to access object inside call back function so that its name can be accessed after 1 sec.
//step 1; Taking out anonymous function and adding it as a prototype property
LateBloomer.prototype.bloom = function() {
//window.setTimeout(this.callback, 1000); //Note: Keyword this is not inside callback so
//it is referring to object (not window). We can access newly
//defined function on the object. Also keyword this placed inside callback
//function(below) will still refer to window.
};
LateBloomer.prototype.callback = function() {console.log(this.name);}
//step 2; bringing .bind into picture.
//Definition of .bind as per MDN : The bind() method creates a new function
//that, when called, has its this keyword set to the provided value
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.callback.bind(this), 1000); // Okay now we are now invoking .callback method on the object and
//passing the same object to bind.
// The keyword this inside newly return function (as a result of bind) will now refer to object
// we passed as argument to bind and we should not be able to access name property of our object.
// Note : Here both this keywords refers to same object ie on which which are calling .bloom.
//Note : we are no longer using passing callback function defined below. Instead we are now passing
// and exact copy of it but configuring it in such a way that keyword this start refering to object we passed.
};
LateBloomer.prototype.callback = function() {console.log(this.name);}
I am reading a tutorial at so I can understand _.bind and _bindAll: http://blog.bigbinary.com/2011/08/18/understanding-bind-and-bindall-in-backbone.html
The website has the following code
function Developer(skill) {
this.skill = skill;
this.says = function(){
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
john.says(); //Ruby rocks!
vs
function Developer(skill) {
this.skill = skill;
this.says = function(){
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = john.says;
func();// undefined rocks!
Why does storing a reference to a function then calling the function cause this to have a context of window?
When you execute
a.b();
then a is the context of execution of b (this inside b) unless b is a bound function.
If you don't have a, that is if you have
b();
then it's the same as
window.b();
so window is the context of execution of b.
Note also that
a.b();
is the same as
b.call(a);
and
b();
is the same as
b.call(); // call replaces its first argument by the global object if it's null or undefined
If you want to bind the context, then you can do (on modern browsers)
var func = john.says.bind(john);
func();
or (more classically) use a closure :
var func = function(){john.says()};
func();
Because the "this" keyword is bound at call time, not definition time.
When you call john.says() it's like doing john.says.apply(john).
When you call func() it's like doing func.apply().
Yehuda Katz has a great explanation of "JavaScript function invocation and this".
I am trying to understand the way that javascript passes functions around and am having a bit of a problem groking why a prototype function can NOT access a var defined in a function constructor while a function defined in the constructor can access the var. Here is code that works:
var model = function model() {
this.state = 1;
this.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
}
var othermodel = function othermodel(mdl) {
this.GetStateFn = mdl.GetState;
}
othermodel.prototype.WriteState = function() {
console.log(this.GetStateFn.call());
};
var m = new model();
var o = new othermodel(m)
o.WriteState();
This works and makes sense - the GetState() function can access this.state.
However, if I create GetState as follows:
model.prototype.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
The result will be an error that scope is not defined.
I would prefer to have this work with the prototype method as I do not want a copy of the function in ever model, but it would seem that prototype can't work because it can't access the specific instance of the model.
So, can someone provide me with a good explanation of a) what I need to do to get this to work with prototype (assuming I can) and b) if I can't get it to work with prototype, what is the reason so I can understand better the underpinnings of the issue.
Why not simply write the function this way
model.prototype.GetState = function() { return this.state; }
var othermodel = function othermodel(mdl) {
this.GetStateFn = mdl.GetState.bind(mdl);
}
othermodel.prototype.WriteState = function() {
console.log(this.GetStateFn.call());
};
The above code will work, as in most cases you will execute code like m.GetState(). That is an example of invoking a function as an object method. In that case, this is guaranteed to point to the object m. You seem to know how the prototype chains work, so I won't go there.
When assigning the function reference to the other model, we use the .bind to ensure that within GetState, this points to mdl. Reference for bind: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Your original IIFE's were in effect your implementation of bind. The issue was the value of this was wrong. Currently, every time you need to assign models function to some other function, you will need to use bind at all those times. You have tagged your question as node.js, bind is available on the Function prototype in node.js and any ES5 compatible browser. If you need to run the above code on older browsers or environments that do not support bind, replace bind with your IIFE.
As for why your code isn't working,
model.prototype.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
Here, this doesn't refer to the eventual model object (m). this can refer to any one of 5 options in javascript. Refer: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
Lets assume the above code is in an html file inside some script tag. Then this will refer to the window object. window doesn't have any property called state, hence the undefined. If you were to console.log(this.m, this.o) at the end of you script, you would see the respective m and o objects.
When defined like this:
var model = function model() {
this.state = 1;
this.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
}
the anonymous function is declared and immediately executed. this is passed as a parameter to that self-executing function. As a result - a new function is returned, but this function has scope parameter in its closure - so that it is accessible after the scope has exited. As a result - the function, when invoked, can still access state property of that "enclosed" this (the one that became scope and was closed upon).
If you define it like this:
model.prototype.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
the mechanism is the same, it's just this is not. It is now the context of the scope you execute the above code in. Assuming it's done in global scope - it would be window object.
If you don't want to use bind because of its support with older browsers, you could try this:
http://jsfiddle.net/j7h97/1/
var model = function (state) {
this.state = state || new Date().getTime();
};
model.prototype.GetState = function () {
return this.state;
};
model.prototype.WriteState = function () {
console.log("model WriteState: " + this.GetState());
};
var othermodel = function othermodel (mdl) {
this.GetStateFn = function () {
return mdl.GetState.call(mdl);
};
};
othermodel.prototype.WriteState = function () {
console.log("othermodel WriteState: " + this.GetStateFn());
};
var model1 = new model();
model1.WriteState();
var othermodel1 = new othermodel(model1);
othermodel1.WriteState();
var model2 = new model();
model2.WriteState();
var othermodel2 = new othermodel(model2);
othermodel2.WriteState();
Seems to do what you want without bind. I created the model.prototype.WriteState for testing purposes.
It depends on where it is called. If it's in global scope, this will not refer the the model. If it's running in a browser it will refer to the global window object instead.
I was going through this article http://dev.opera.com/articles/view/objects-in-javascript/
where I read "'this' keyword doesn’t always refer to the object on which a method is defined, but instead can change based on specific contexts."
I couldn't find any example in which 'this' does not refer to the object on a method is defined....please gimme an example if possible
One example that you could realistically run into and not expect this result:
var obj = {
testFunc : function(){
alert("testFunc: " + this);
}
}
obj.testFunc(); // this is the object
setTimeout(obj.testFunc, 1000); // this is window
http://jsfiddle.net/t7ycd/
There are many way to change context. jsfiddle
using bind: (not supported by older IE browsers (IE < 9))
var obj = {};
function fun1(){};
obj2 = {};
obj2.fun1 = fun1.bind(obj);
obj2.fun1(); // context inside fun1 would be obj.
Using apply or call.
var obj = {};
function fun1(){};
obj2 = {};
obj2.fun1 = function(){
fun1.apply(obj, arguments);
//or fun1.call(obj, ar1, arg2,...);
};
obj2.fun1(); // context inside fun1 would be obj.
Here is one way
var a = {};
a.foo = function(){ console.log(this); }
a.foo(); // object a
a.foo.call(window); // window object
If you call a method in class B from class A, the 'this' will refer to the class that is calling the method - A, not the class that it is in.
Here is an example taken directly from the Mozilla documentation
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
So the function independent is defined in the global context, but is then attached to an object. When it is invoked on that object the context becomes the object on which the function is invoked rather than the object on which the function is defined.
You can achieve similar results using the javascript call and bind methods, and using anonymous functions.
like this
var MyObject = function()
{
this.initialize();
}
MyObject.prototype.SomeMethod = function()
{
//common fix is to use
//var self = this;
(function(){
//this has lost scope
//self will retain the this scope that was desired
})();
}