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);
}
}
Related
I'm a bit puzzled by this coding pattern I've run into even though I've been studying up on 'this.' The following (simplified) code shows the pattern:
var MyConstructor = function MyConstructor() {
this._handlers = {
action: this.handleAction.bind(this)
};
};
MyConstructor.prototype.start = function(someObj) {
this.someObj.on(’some event’, this._handlers.action); //<--here
}
MyConstructor.prototype.handleAction = function() {
//do stuff
}
module.exports = MyConstructor;
My question is, why is the private method in the constructor required? Is this pattern avoid some common problem? Could the line commented //<--here simply be:
this.someObj.on(’some event’, this.handleAction);
No, they are different. The difference is in context, which means the value of this within the function.
this.handleAction passes the function to on without any context. There is no value of this specified. The value will be determined when the function is executed. It is very likely that the value will not be the a MyConstructor object, so this.start, for instance, will not refer to the right object, or indeed perhaps any object at all.
The solution is to bind context. This sets the context forever, so this will always refer to the right value. You see this line of code:
action: this.handleAction.bind(this)
This means that, when the code later refers to this._handlers.action, it will be sending the function to on with the appropriate context, so this will always point to the correct value.
The difference between the following lines
this.someObj.on(’some event’, this.handleAction.bind(this));
this.someObj.on(’some event’, this.handleAction);
... is that the first handleAction will run with this being the instance of MyConstructor, while the second will run in whatever context the event handling mechanism decides. If it is something like this, it will run with this being the global object:
function on (a, callback) {
callback(); // callback is run with this as the global object
// UNLESS it was bound to something else
}
The 'private' _handlers property is just an object that holds references to callbacks bound to the instance. If you were to call bind twice, two functions would be created. The _handlers property makes it so that a single bound function is created which can be used as a handler for any number of events.
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.
function Apple(){
this.name="apple";
}
function Orange(){
this.name="orange";
this.apple = new Apple();
this.apple.onCalled=function(){
alert(this.name);
}
}
Orange.prototype.onCalled=function(){
this.apple.onCalled();
}
var orange = new Orange();
orange.onCalled();
Currently the code shows "apple". How can I modify the "this.apple.onCalled=function()" line so that it shows "orange"?
i.e. I want to pass a function to another object, but when that function is called, access variables of the object who passed the function, not the variables of the object who is executing the function. An obvious solution would be to use global variables (e.g. orange.name) but I'm looking for a better way because there are many objects and I don't want to global everything.
Use a closure.
function Orange(){
this.name="orange";
this.apple = new Apple();
var that = this;
this.apple.onCalled=function() {
alert(that.name);
}
}
Have a read how keyword this works in JS, it's a bit tricky but easy to grasp.
You could write:
Orange.prototype.onCalled=function(){
this.apple.onCalled.call(this);
}
It's hard to give a general answer. The thing to understand is that this is bound upon any function call. That can be explicitly controlled with the call or apply functions, or by the . operator when accessing a function as a property of an object.
The answer Kos gives about using a closure may also be relevant; it depends on the effect you want.
Orange.prototype.onCalled=function(){
this.apple.onCalled.call(this);
}
Example: http://jsfiddle.net/XrtZe/
Have a look at: Scope in JavaScript
I was fooling around with JS a bit, and I found this:
Anyone care to explain?
An anonymous function is one that doesn't have a name. For example, you can do:
(function(){ alert("Hello World!") })();
This creates a function with no name and immediately calls it. If the code caused an exception to be raised, the JavaScript runtime will report a failure in an anonymous function.
Also, functions are themselves objects with a class named Function. You can use this class to define a new function like this (instead of the built-in syntax):
(new Function("x", "y", "return x+y"))(1, 2);
This is pretty much the same as writing:
(function(x, y) { return x + y })(1, 2);
This gives you a peek into the object-oriented nature of JavaScript's functions.
When you call the Function() function (which is a constructor of Function objects) it returns you a function. Functions created dynamically in that way have no name, and so the name "anonymous" is given to it.
See: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function
It is a quirk in the way multiple browsers' implementations of Function.prototype.toString renders functions created via the Function constructor, but it is not significant and it does not appear in any version of the EcmaScript specification.
Normally a named function
function anonymous(x) {
if (x) {
alert('hi');
} else {
anonymous(!x);
}
}
will alert regardless of the value passed in, because the name of the function can be used to call it recursively (modulo IE bugs), but that is not the case with the anonymous created via new Function.
(new Function('x', 'if (x) alert("hi"); else anonymous(!x);'))(false)
fails with an error.
An anonymous function is a function with no name. They aren't specific to Javascript, see http://en.wikipedia.org/wiki/Anonymous_function
For JS, basically instead of this:
function myFunc() { }
you can do:
var myFunc = function() { }
I have run into this jquery plugin and i quite understand how this works:
$.functionone = function(){
function setOptions(newOptions){
...
}
this.setOptions = setOptions;
}
What i dont understand is what does this actually do? this.setOptions = setOptions can you call a function without parenthesis? What is the relationship between this.setOptions and setOptions by itself?
Functions in JavaScript are objects like (nearly) everything else. When you do this:
this.setOptions = setOptions;
you're not calling the setOptions function, you're just assigning a reference to the function to a property, exactly like setting a property to any other object, like this:
var dt;
dt = new Date();
this.today = dt;
With functions, you'd do this so you can later call the function via the property (which sets up the this value to be the object the property's on, which is handy). It's a bit clearer what's going on if you use a different name for the property than for the function:
function functionName() { ... } // Declares the function
this.propertyName = functionName; // Sets the property
functionName(); // Calls the function (with `this` = the global object ["window", on browsers])
this.propertyName(); // Also calls the function (but with `this` = the object the property's on)
The pattern you identified, declaring a function and then separately setting a reference to it on an object, is frequently used to make sure the resulting function has a name. You can create a function and bind it to a property like this:
this.setOptions = function() {
...
};
...but then the function doesn't have a name (the property does, but not the function), which can be an issue when you're trying to debug because debuggers show you the names of functions in various contexts (call stacks, for instance). If a lot of your functions don't have names, even though the properties referring to them do, it makes debugging difficult. More about anonymous vs. named functions here. (There's also a difference in terms of when the function is instantiated, but going into it here would just complicate things.)
You'd think you could combine things, like this:
this.setOptions = function setOptions() { // <=== DON'T DO THIS
...
};
...but although that mostly works, it triggers a bug in Internet Explorer / JScript (it creates two different functions for that code, which is at best a memory waste and at worst a very subtle and time-wasting problem, as it was in this question).
The function setOptions is only called if you add parenthesis: setOptions(). If you do not add parenthesis, you have a reference to a function. This is just like a normal variable, only it contains a function reference instead of some other value.
If you set this.setOptions = setOptions, you make a function setOptions on the this object, which points to the same function as setOptions. That is, if you call it using this.setOptions(), the referenced function will be called.