I was making a test case to show how 'bind' is necessary for a method to refer to its function in a callback.
But just when I thought I knew JS - the following code works fine - without requiring bind!
pretendThingConstructor = function (greeting) {
this.greeting = greeting;
this.sayHello = function() {
console.log(this.greeting);
};
}
var pretend_thing = new pretendThingConstructor('hello world');
pretend_thing.sayHello();
setTimeout(function() {
pretend_thing.sayHello()
}, 3000);
When I run it - via node, phantomjs, or another JS environment - it works. 'hello world' is printed twice.
I expected the second 'hello world' - the one ran after the timout - to fail, as 'this' would refer to the event, rather than the object. But it works. Why is this?
The this changes depending on how your call the function. If you specify a base object, it will refer to that instead:
pretend_thing.sayHello()
Here pretend_thing is that base object and therefore this still refers to that object. On the other hand, if you had:
var f = pretend_thing.sayHello;
f();
Here this should refer to window object instead.
You can confirm it by putting:
console.log (this instanceof pretendThingConstructor);
Inside your sayHello function. It will print true in both cases.
pretendThingConstructor = function (greeting) {
this.greeting = greeting;
this.sayHello = function() {
console.log(this.greeting);
console.log(this instanceof pretendThingConstructor);
};
}
var pretend_thing = new pretendThingConstructor('hello world');
////////////////////////////
pretend_thing.sayHello();
setTimeout(function() {
pretend_thing.sayHello();
}, 3000);
will output:
true
true
whereas:
var f = pretend_thing.sayHello;
f();
outputs:
false
In the scope of the function 'pretendThingConstructor', 'this' refers to the function itself. When the constructor is run (when you instantiate an object using the 'new' keyword), the sayHello method (which is an anonymous method) will be assigned to the property 'sayHello' on the instantiated object (in your case, pretend_thing).
Because you're calling the 'sayHello' method FROM an instance of the 'pretendThingConstructor' object (pretend_thing), 'this' refers to the object that you're calling the method from, not the context that you're executing in.
You can change the meaning of the 'this' keyword by using the .apply method:
function myHello(){
this.greeting = 'Hello';
this.method = function(){
this.greeting
}
}
function myGoodbye(){
this.greeting = 'Goodbye';
this.say = function(){
console.log( this.greeting );
}
}
var hello = new myHello();
var goodbye = new myGoodbye();
hello.say(); // Outputs 'Hello'
goodbye.say(); // Outputs 'Goodbye'
hello.say.apply( goodbye ); // Outputs 'Goodbye'
Yes in this case the this object of sayHello is pretend_thing because the function knows on which item it is called. The this only gets lost if you're trying to do this:
<-- language: lang-js -->
var say = pretend_thing.say_hello;
setTimeout(function () {
say(); // this is window or null
}, 15)
// You can do something like
function doThings() {
console.log(this.thing);
}
var test1 = { doThings: doThings, thing: 1 };
var test2 = { doThings: doThings, thing: 2 };
test1.doThings(); // <- 1
test2.doThings(); // <- 2
So the context depends on where the function is attached. But you can override this behavior with the bind-thing.
Related
[This is related to Bound function instead of closure to inject extra arguments, but that was neither clearly asked nor answered.]
I'm calling a function that expects a function as its argument. I want to pass a method from my class, bound to an instance of my class. To make it clear, assume my class looks like:
var MyClass = function() {}
MyClass.prototype.myMethod = function() { ... }
var my_instance = new MyClass();
Is there any substantive difference between using bind:
doSomething(my_instance.myMethod.bind(my_instance))
and wrapping the call in an anonymous function:
doSomething(function() { my_instance.myMethod(); })
?
If a prototype within your class needs to generate a callback, it may not know its instance's name. As a result, you'll need to use this, but the value of this depends on where the callback was executed.
Consider the following example:
var MyClass = function (x) { this.something = x; };
MyClass.prototype.makeCall = function () {
var myBadCallback = function() { console.log(this.something); };
var myGoodCallback = function() { console.log(this.something); }.bind(this);
// When called, the value of "this" points to... we don't know
callMeBack( myBadCallback );
// When called, the value of "this" points to this instance
callMeBack( myGoodCallback );
};
function callMeBack( callback ) { callback(); };
var foo = new MyClass('Hello World!');
var bar = new MyClass('Goodbye!');
// Probably prints "undefined", then prints "Hello World!"
foo.makeCall();
// Probably prints "undefined", then prints "Goodbye!"
bar.makeCall();
In the above example, the first output probably prints undefined because the context (what this refers to) has changed by the time the callback has executed.
This example may seem contrived, but these sort of situations do arise, a common case being AJAX callbacks.
Basically I want to do this:
someFunction() // do something
someFunction.somePropertyFunction()
someFunction() // Now someFunction is modified; it should now exhibit a different behaviour
Is this possible?
EDIT:
I'm not looking for what #Kolink was suggesting. Basically I want to augment a function's functionality by calling one of it's property function.
Specifically, I need to: 1. have access to the original function inside my property function (which is entirely doable using this), and 2. bind a new function to the original function's name (which I'm not sure if it's possible).
Just to be clear, I don't have access to the internal definition of the function that I want to augment. I want to attach a function to Function.prototype (so that it will be available as a property of the function that I want to augment), and then I will call func.augmentThis(), and then func should be augmented. But I'm not sure how, hence the question :P
Easily. Here's an example:
var derp = 123;
someFunction = function() {alert(derp);};
someFunction.somePropertyFunction = function() {derp = 456;};
someFunction(); // alerts 123
someFunction.somePropertyFunction();
someFunction(); // alerts 456
Okay, that's an oversimplified example, but yeah, it's entirely possible.
If your question is whether a function attached as a property to another function has a way to access the function to which it is attached, the answer is no. After all, the same function could be attached to any number of functions of objects.
So one alternative is to explicitly refer to the "mother" function within the function that is attached to it and intended to change its behavior:
function f (n) { alert (n + f.offset); }
f.offset = 0;
f.change_offset = function (i) { f.offset = i; };
f (1); //1
f.change_offset (100);
f (1); //101
Here, f is hard-wired into the definition of change_offset. If this bothers you, or you want something slightly more general, write a little routine to set a function as a property on another function, while binding its this to the function being attached to:
function set_func_as_func_prop ( propname, func_to_set, func_to_set_on ) {
func_to_set_on[propname] = func_to_set.bind(func_to_set_on);
}
Now you can write the function more generally
function change_offset (i) {
this.offset = i;
}
and set it on f or any other function.
set_func_as_func_prop ("change_offset", change_offset, f);
set_func_as_func_prop ("change_offset", change_offset, g);
Sort of:
function someFunction() {
return realFunction.apply(this, arguments);
}
function someFunctionA(name) {
return 'Hello, ' + name + '!';
}
function someFunctionB(name) {
return 'Goodbye, ' + name + '...';
}
var realFunction = someFunctionA;
someFunction.somePropertyFunction = function () {
realFunction = someFunctionB;
};
Sure it's possible. It's not recommended, but it's possible. For example:
function a() {
alert("a");
}
function b() {
alert("b");
}
function c() {
return c.f.apply(this, arguments);
}
c.f = a;
c.toggle = function () {
c.f = c.f === a ? b : a;
};
Now let's test it:
c(); // alerts "a"
c.toggle();
c(); // alerts "b"
See the demo: http://jsfiddle.net/LwKM3/
I want to attach a function to Function.prototype. Then I need to bind a new function to the original function's name (which I'm not sure if it's possible).
That indeed is impossible, you don't know what refers to the function. And you cannot change the internal representation of a function, which is immutable.
The only thing you can do is to create a new function and return that, to let the caller of your method use it somehow - specifically assigning it to the original variable:
somefunction = somefunction.augmentSomehow();
Your method for that will look like this:
Function.prototype.augmentSomehow = function() {
var origFn = this;
return function() {
// in here, do something special
// which might include invoking origFn() in a different way
};
};
Not sure if this helps, but I would implement described problem in following way:
// defined by somebody else - unknown to developer
var someFunction = function() {
alert("this is initial behavior");
}
someFunction(); // returns "this is initial behavior"
// defines parent object on which someFunction() is called
var parentObject = this; // returns window object (as called direclty in the
// browser)
// if you are calling someFunction from some object (object.someFunction())
// it would be:
// var parentObject = object;
// augumentThis definition
someFunction.augumentThis = function() {
var newFunction = function() {
alert("this is changed behavior");
};
parentObject.someFunction.somePropertyFunction = function() {
parentObject.someFunction = newFunction;
parentObject.someFunction();
};
};
someFunction.augumentThis(); // change function behavior
someFunction(); // "this is initial behavior"
someFunction.somePropertyFunction(); // "this is changed behavior"
someFunction(); // "this is changed behavior"
Is it possible to define a function in the scope of a parent function and bind an argument passed through the parent function as its scope before returning it?
Here is an example:
var myObject = {
foo: "bar"
};
var myFunction = (function() {
return function() {
return this.foo;
};
}).call(myObject);
myFunction.call(myObject); // I'd like to bind myObject as this does ...
myFunction(); // ... but I'd like to do it before invoking it, without .call() or .apply()
Or another complex example, that describes what I'm trying to do:
var createMyCopy = function(original, self) {
var copy;
eval("copy=" + original.toString());
console.log(copy()); // returns undefined
};
(function() {
var self = "Hello world",
myFunction = function() {
return self;
};
console.log(myFunction()); // returns "Hello world"
createMyCopy(myFunction);
})();
I'm trying to create a copy of a function, so that I can make changes to it without changing the original one, but I'd like to have the variables that are defined in the original one in the copy as well...
Do you mean like this?
var myObject = {
foo: "bar"
};
var myFunction = (function() {
var self = this;
return function() {
return self.foo;
};
}).call(myObject);
I think you're getting scope and context mixed up in your question.
I think you mean this:
var myFunction = (function(obj) {
return function() {
return obj.foo;
};
})(myObject);
The immediately invoked function expression is passed myObject and returns a new function in which that parameter is bound as the variable obj.
I'm not sure what you mean, but you can do this:
var myObject = {
foo: "bar"
};
function myFunction() {
return this.foo;
}
console.log(myFunction.apply(myObject)); // bar
The first argument of apply is the context (ie. what this refers to). The second argument of apply is an array of arguments (but I've omitted that here as there are no arguments).
I'm trying to wrap my head around building a custom JavaScript library. I've read a lot about the module pattern, and also read Crockford's articles on private and public members. I know what is an immediately invoked function expression and why we do stuff like
var myLib = (function() {
}())
However, I'm still a little lost in some cases regarding scope and closures in general. The concrete problem I have is:
Why does the following example alert DOMWindow, rather than the myLib object?
http://jsfiddle.net/slavo/xNJtW/1/
It would be great if you can explain what "this" refers to in all of the methods in that example and why.
Inside any function declared (anywhere) and invoked as follows this will be window object
function anyFunc(){
alert(this); // window object
}
anyFunc();
var anyFunc2 = function(){
alert(this); // window object
}
anyFunc2();
If you want to create private functions and access the instance of 'myObject' you can follow either of the following methods
One
module = (function () {
var privateFunc = function() {
alert(this);
}
var myObject = {
publicMethod: function() {
privateFunc.apply(this); // or privateFunc.call(this);
}
};
return myObject;
}());
module.publicMethod();
Two
module = (function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(_this);
}
var myObject = {
publicMethod: function() {
privateFunc();
}
};
_this = myObject;
return myObject;
}());
module.publicMethod();
These are solutions to your issue. I would recommend using prototype based objects.
EDIT:
You can use the first method.
In fact here myObject is in the same scope as privateFunc and you can directly use it inside the function
var privateFunc = function() {
alert(myObject);
}
The real scenario were you can use a proxy for this is shown below. You can use call also.
Module = function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(this + "," + _this);
}
this.publicMethod = function() {
privateFunc(); // alerts [object Window],[object Object]
privateFunc.call(this); // alerts [object Object],[object Object]
}
_this = this;
return this;
};
var module = new Module();
module.publicMethod();
You need to explicitly state that myPrivateMethod is a member of myLib:
function MyLib ()
{
this._myPrivateField = "private";
this._myPrivateMEthod = function ()
{
alert(this); // Alerts MyLib function;
}
}
var libObject = new MyLib();
Just remember that without using enclosure techniques, nothing in JavaScript is ever truly private!
A better way to do the above is like so:
function MyLib(instanceName)
{
this.name = instanceName;
}
MyLib.prototype.myPrivateFunction()
{
alert(this);
}
To call your method after that:
var libObject = new MyLib();
libObject.myPrivateMethod(); // Alerts info about libObject.
The thing to remember about the module pattern is that it runs once and completes. The methods that are still available to be called are the closures. At the time of creating module, "this" refered to the window and was replaced by its value.
In your linked fiddle, the "this" keyword is never changed by a "new" keyword or other context change, so it still refers to the global window object.
edit: clarification
I'm not sure where this points in JavaScript. And I give 2 examples.
Can you help me analyze them? Thank you very much.
//exmp1
function f1()
{
alert(this);
function f2()
{
alert(this);
}
f2();
}
f1();
//exmp2
var jsn =
{
name : "b",
func : function() // closure
{
alert(this);
return function()
{
return this;
}
}
}
alert(jsn.func()());
this is different in JavaScript than it is in some other languages like C++ or Java. The value of this in your first example will always be the global object (window, on browsers). this in your second example is the jsn object for the first alert, and window for the second. This is because this is determined entirely by how a function is called, not where it's defined.
If you don't do anything special when calling the function, this is the global object. When you call a function via an object property (jsn.func()), this is set to the object the property came from. (But don't get the wrong impression, func is in no way specially tied to jsn; JavaScript doesn't have methods, just functions; details.) f1 then returns a function, which is called within the final alert; since that call is not via an object property, this is set to the global object.
Some examples:
// Simple function
function foo() {
alert(this === window);
}
foo(); // true, within the call, `this` === `window`
// Object example, and twist at the end
var obj = {
func: function() {
alert(this === obj);
},
};
obj.func(); // true, within the call, `this` === `obj`
obj["func"](); // true, within the call, `this` === `obj`
var f = obj.func; // Not calling it, just getting a reference to the function
f(); // false, within the call `this` !== `obj` (`this` === `window`)
// Creating functions on the fly, returning them, and how that has
// nothing whatsoever to do with how `this` gets set:
var obj = {
func: function() {
return function() {
alert("I'm a generated function");
alert(this === obj);
};
}
};
obj.func()(); // alerts the "I'm a generated function", then false; `this` !== `obj`
obj.bar = obj.func();
obj.bar(); // alerts the "I'm a generated function", then true; `this` === `obj`
There's a second way to control what this is within a function: Use the .call or .apply features of JavaScript functions:
var obj = {
func: function() {
alert(this === obj);
}
};
function foo(a, b) {
alert(this === obj); // Yes, really obj; see below
alert(a);
alert(b);
}
foo(1, 2); // alerts false (`this` !== `obj`), then 1, then 2
obj.func(); // alerts true, `this` === `obj`
foo.call(obj, 3, 4); // alerts true (`this` === `obj`), then 3, then 4
foo.apply(obj, [5, 6]); // alerts true (`this` === `obj`), then 5, then 6
As you can see, the first argument to call or apply is the object to make this within the function call. The only difference between call and apply is how you specify arguments to pass into the target function: With call, you just supply them after the first argument; with apply, you supply them as an array.
And finally, there's a third way: The new keyword. JavaScript has the concept of constructor functions. The purpose of a constructor function is to create instances of objects initialized in a particular way. Here's an example:
function Foo(b) {
this.bar = b;
}
var f = new Foo();
Technically, any function can be used as a constructor function. The convention is to give functions meant to be used with new names starting with a capital letter, just to reinforce that we call them in a special way.
Calling a function via new creates a new object instance and makes that object the this value within the function call. So
function Foo(b) {
alert(this === window);
}
var f = new Foo(); // alerts false, `this` !== `window` (it points to the new object created for the call)
var f = Foo(); // alerts true, `this` === `window` because we didn't use `new`
As you can see, it's important to call a function in the correct way. If it's designed to be used with new, call it via new; if it's not, don't.
(new does more than just create a blank object; the object created has some other aspects set up in a certain way. I won't go into the details here, but I didn't want to leave you with the impression that all it did was create a new object instance.)
In your last example (the function inside json object), this refers to the json object that is holding the function.
In your first example, the first this is referring to the object that is holding f1, it happens to be the global window object. The second this in f2 is also referring to the global object and not to f1, and this is a known bug in javascript, when you have one function defined in another.
A common workaround is this (no pun intended):
function f1() {
alert (this);
var that = this;
function f2() {
alert (that);
}
f2();
}
Notice that if you define a function in a json object, it can still be "moved around" and the context of this will change. For example:
var car1 = {
color: "red",
f: function () { alert (this.color); }
}
car1.f(); // prints "red"
var car2 = {
color: "blue",
}
car2.f = car1.f;
car2.f(); // prints "blue"
In JavaScript "this" always refers to the object which "owns" the function, or rather, the object to which a function was bound via a property at the time it was called. Consider this example:
var f = function() { alert(this); }
f(); // Alerts the "DOM window" (global) object, which
// is implied if there is no explicit owner.
var o = {toString:function(){return "Foo!";}}
o.func = f;
o.func(); // Alerts the "Foo!" object (o) since the
// function then belongs to it as a member.
Now regarding your specific examples, here's what happens:
//exmp1
function f1() {
alert(this);
function f2() {
alert(this);
}
f2(); // Alerts "the global object", since f2
// is not bound to any object's property.
}
f1(); // Alerts "the global object" (probably DOM window)
// for same reason as above.
//exmp2
var jsn = {
name : "b",
func : function() {
alert(this); // Will alert the "jsn" object, since it
// owns the function in its "func" member.
return function() {
return this; // Returns whoever is calling it!
};
}
}
alert(jsn.func()()); // "jsn.func()" returns a function which gets
// called by the global "DOM window" object.
when you use a function as a constructor, this points to the object you are constructing.
function Test() {
this.test = true;
}
t = new Test();
alert(t.test);