Using KineticJS I figured out how to pass a function as the Gameboard function but all the this's inside the Gameboard function think's its now the object that got the function :(.
function Gameboard(){
//.... creates placeholders for stage layers and all objects
this.dice_layer=new Kinetic.Layer();
this.rolldice=function(){
alert(this.toString());
//..alter images
this.dice_layer.draw();//<~~ thinks this is circle once passed through setUpGameBoard says dice_layer is undefined. alert(this.toString()); shows this to be circle.
};
this.setUpGameBoard=function(){
// ...draws board pawns creates a circle object
var obj=this;//<~~ are there memory issues with this? Is there a better way?
circle.on("click",**obj**.rolldice.**bind**(obj);//** == ANSWER!!!!
};
};
The problem is this line:
this.doSomething=function(fnction){
You are declaring doSomething as a function with a single parameter, fnction but when you call it, you are passing two - a string and a function.
this.doSomething=function(str, fnction){
will behave as you expect it.
jsFiddle demo
Based on your "solution" to the second problem, it looks like you want to use ES5's bind. It allows to you specify the this for a particular function call since JavaScript really doesn't have "methods", you have to specify the object they operate on.
this.barfoo.doSomething(this.doBar.bind(this));
An example of malfunctioning code can be compared to the fix with bind.
Probably your simplification doesn't show up the real issue. I guess something like the following would be more similar to your problem:
function foo(){
this.doSomething = function(fnction){
fnction();
};
}
function bar(){
this.myField = "Buzz"
this.barfoo = new foo();
this.doBar = function(){
alert(this.myField);
};
this.barfoo.doSomething(this.doBar); // tried this
//this.barfoo.doSomething(this.doBar()); also tried this
//this.barfoo.doSomething(bar.doBar); also tried this
//this.barfoo.doSomething(bar.doBar()); also tried this
}
Where you can notice issues in accessing this-related properties.
If this is actually the problem, then you should be able to solve it by using either call or apply in foo's doSomething method:
function foo() {
this.doSomething = function (obj, fn) {
fn.call(obj);
};
}
And this is how you will use it in bar:
function bar() {
this.myField = "Buzz";
this.barfoo = new foo();
this.doBar = function () {
alert(this.myField);
};
this.barfoo.doSomething(this, this.doBar);
}
var myBar = new bar();
Check the jsFiddle.
Related
Background
I want a function keeping track of its own state:
var myObject = {
myFunction: function () {
var myself = this.myFunction;
var firstTime = Boolean(!myself.lastRetry);
if (firstTime) {
myself.lastRetry = Date.now();
return true;
}
// some more code
}
}
The problem with the above code is that the value of this will depend on the site of the function call. I want the function to be able to refer to itself without using:
myObject.myFunction
.bind()
.apply()
.call()
Question
Is it possible to give a function this kind of self awareness independent of its call site and without any help from external references to it?
If you want to store that state on the function instance, give the function a name, and use that name within it:
var myObject = {
myFunction: function theFunctionName() {
// ^^^^^^^^^^^^^^^--------------------- name
var firstTime = Boolean(!theFunctionName.lastRetry);
// ^--------------------------- using it
if (firstTime) {
theFunctionName.lastRetry = Date.now();
// ^------------------------------------------------ using it
return true;
}
// some more code
}
};
You'd do that whenever you want to use a function recursively as well. When you give a name to a function that way (putting the name after function and before (), that name is in-scope within the function's own code. (It's not in-scope for the code containing the function if it's a function expression, but it is if it's a function declaration. Yours is an expression.)
That's a named function expression (where previously you had an anonymous function expression). You may hear warnings about NFEs, but the issues various JavaScript implementations had with them are essentially in the past. (IE8 still handles them incorrectly, though: More in this post on my blog.)
You might consider keeping that state somewhere private, though, via an IIFE:
var myObject = (function(){
var lastRetry = null;
return {
myFunction: function() {
var firstTime = Boolean(!lastRetry);
if (firstTime) {
lastRetry = Date.now();
return true;
}
// some more code
}
};
})();
Now, nothing outside that outer anonymous function can see lastRetry at all. (And you don't have to worry about IE8, if you're supporting stubborn XP users. :-) )
Side note: The unary ! operator always returns a boolean, so your
var firstTime = Boolean(!theFunctionName.lastRetry);
...is exactly equivalent to:
var firstTime = !theFunctionName.lastRetry;
...but with an extra unnecessary function call. (Not that it hurts anything.)
Of course you can, simply give your function an internal named representation and it can refer to itself from there. For example...
var obj = {
doThings:function doThingsInternal(arg1, arg2) {
console.log(arg1, arg2);
for (var arg in doThingsInternal.arguments) {
console.log(arg);
}
}
};
obj.doThings('John', 'Doe');
You could use a simple Closure, if you are not too bent on keeping state existence knowledge within the function. But I guess you don't want that. Another way to do this could be changing the function itself on the first call. Benefits, no/less state variables needed and no costly checks on subsequent calls! -
var myObject = {
myFunction: function () {
// Whatever you wanna do on the first call...
// ...
// And then...
this.myFunction = function(){
// Change the definition to whatever it should do
// in the subsequent calls.
}
// return the first call value.
}
};
You can extend this model to any states by changing the function definition per your state.
I have an object, lets call it myObject, and a named function myFunction.
Can I create a method in myObject, lets call it myMethod, so that whenever I call myObject.myMethod I'll actually call myFunction.
I know i can create a new function for myMethod, and probably could make it be a wrappeI for myFunction, but is there a better way? or am I doing this all wrong
If I understand your question correctly, this is all you need to :
var myObject = {};
var myFunction = function() {/* code goes here*/};
myObject.myMethod = myFunction;
Because of how JavaScript works, though, this wouldn't become an object-specific function this way, so you couldn't track state with it. It would be similar to a static function in Java.
i think you are confusing your words. methods of an object are generally functions. like so-:
var myObject = {
x:0,
y:0,
getX: function () {
return this.x;
},
getY: function () {
return this.y;
}
};
you can add any number of methods/functions.
I'm working on building a collection of prototype helper methods inside a wrapper. However for ease of use, I'd like to be able to call the object as both a new instance and single global instance under the same call.
For example, with jQuery, you can call both "$" and "$()" which can be used differently http://learn.jquery.com/using-jquery-core/dollar-object-vs-function/:
So given the bellow as simple example, how could I do something similar?
(function () {
var myWrapper = function (foo) {
return new helper(foo);
};
var helper = function (foo) {
this[0] = foo;
return this;
}
helper.prototype = {
putVar: function(foo) {
this[0] = foo;
}
}
if(!window.$) {
window.$ = myWrapper;
}
})();
// create an new instace;
var instance = $("bar");
console.log(instance);
// call a prototype method
instance.putVar("foo");
console.log(instance);
// call a prototype method using the same call without new instance
// this doesnt work :(
$.putVar("foo");
// however this will work
window.myLib = $("foo");
myLib.putVar("bar");
http://jsfiddle.net/2ywsunb4/
If you want to call $.putVar, you should define putVar like this:
myWrapper.putVar = function (foo) {
console.log('Work');
}
In your code, the instance and myLib are the same thing, they are both instances created by you.
If you want to call both $.putVar and $(...).putVar, you should add the code I show you above. That means you have to define two putVar functions, one is used like a 'instance' method, while the other one is used like a 'static' method.
If you search through jQuery source code, you will see two each functions defined. That's why you can all both $.each(...) and $(...).each for different usages.
Is it possible to create an alternate of Array.forEach that automatically sets the context "this" to be the same context as when the method was invoked?
For example (not working, not sure why):
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
this.myVar = 'myVar';
[1,2,3].each(function() {
console.log(this.myVar); // logs 'myVar'
});
}
Array.forEach already takes a context argument as the optional last parameter,
(function() {
this.myvar = "myvar";
[1,2,3,4].forEach(function(v) {
console.log("v:"+v);
console.log("myvar="+this.myvar);
}, this);
})();
See MDN forEach
Also, the above examples (if we're not dealing with methods on instances regarding this) work without using bind or the optional context argument for forEach, the following also works correctly:
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
});
}
myFunction();
Because javascript is functionally scoped, so the anonymous function can access the parent function's scope using this and it logs correctly. this only really becomes problematic as a context when dealing with instance methods.
The answer is no, a JavaScript function cannot determine the value of this in the caller.
You can bind the function passed with the current object, like this
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
}.bind(this));
}
In ECMA Script 6, you can use an Arrow function, like this
[1,2,3].forEach(() => {
console.log(this.myVar); // logs 'myVar'
});
An alternative to messing with the this variable when passing around callbacks, you could always just assign this to a new variable so child scoped functions can access it:
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
var me = this;
me.myVar = 'myVar';
[1,2,3].each(function() {
console.log(me.myVar); // logs 'myVar'
});
}
now you don't have to remember to pass this as a second parameter
Firstly, it must be pointed out that myFunction is a constructor. Yet, the first letter in the identifier is not capitalized. Please call it MyFunction.
If a constructor is called without the new operator, this is bound to the global object, i.e. window in browsers. This makes the capitalization convention our only way of spotting such mishaps.
The following lines of code demonstrate this:
// After the original code...
myFunction();
console.log(window.myVar); // logs "myVar"
Secondly, to be able to apply functions on any array, instead of changing Array.prototype, consider the following:
var utils = {array: {}}; // utils.array is a container for array utilities.
utils.array.each = function (array, func) {
var i;
for (i = 0; i < array.length; i += 1) { func(array[i]); }
};
utils.write = function (s) {
console.log(s); // Alternatively, document.write(s);
};
utils.array.each([1, 2, 3], utils.write); // prints 1 2 and 3 (on separate lines)
Notice that we didn't use this and new. They make JavaScript look like Java, apart from that, they rarely serve a useful purpose.
While libraries may modify Object.prototype and Array.prototype, end-developers shouldn't.
Also, we should (ideally) be able to do something like:
utils.array.each([1, 2, 3], console.log); or
utils.array.each([1, 2, 3], document.write);.
But most browsers won't allow it.
Hope this helped.
If I understand your requirement correctly, then you are trying to override the "this".
I think this can help you.
Here's a sample of a simple Javascript class with a public and private method (fiddle: http://jsfiddle.net/gY4mh/).
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction();
}
}
ex = new Example;
ex.publicFunction();
Calling the private function from the public one results in "this" being the window object. How should I ensure my private methods are called with the class context and not window? Would this be undesirable?
Using closure. Basically any variable declared in function, remains available to functions inside that function :
var Example = (function() {
function Example() {
var self = this; // variable in function Example
function privateFunction() {
// The variable self is available to this function even after Example returns.
console.log(self);
}
self.publicFunction = function() {
privateFunction();
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Another approach is to use "apply" to explicitly set what the methods "this" should be bound to.
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo
Yet another approach is to use "call":
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo
both "apply" and "call" take the object that you want to bind "this" to as the first argument and an array of arguments to pass in to the method you are calling as the second arg.
It is worth understanding how the value of this in javascript is determined in addition to just having someone tell you a code fix. In javascript, this is determined the following ways:
If you call a function via an object property as in object.method(), then this will be set to the object inside the method.
If you call a function directly without any object reference such as function(), then this will be set to either the global object (window in a browser) or in strict mode, it will be set to undefined.
If you create a new object with the new operator, then the constructor function for that object will be called with the value of this set to the newly created object instance. You can think of this as the same as item 1 above, the object is created and then the constructor method on it is called.
If you call a function with .call() or .apply() as in function.call(xxx), then you can determine exactly what this is set to by what argument you pass to .call() or .apply(). You can read more about .call() here and .apply() here on MDN.
If you use function.bind(xxx) this creates a small stub function that makes sure your function is called with the desired value of this. Internally, this likely just uses .apply(), but it's a shortcut for when you want a single callback function that will have the right value of this when it's called (when you aren't the direct caller of the function).
In a callback function, the caller of the callback function is responsible for determining the desired value of this. For example, in an event handler callback function, the browser generally sets this to be the DOM object that is handling the event.
There's a nice summary of these various methods here on MDN.
So, in your case, you are making a normal function call when you call privateFunction(). So, as expected the value of this is set as in option 2 above.
If you want to explictly set it to the current value of this in your method, then you can do so like this:
var Example = (function() {
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction.call(this);
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Other methods such as using a closure and defined var that = this are best used for the case of callback functions when you are not the caller of the function and thus can't use 1-4. There is no reason to do it that way in your particular case. I would say that using .call() is a better practice. Then, your function can actually use this and can behave like a private method which appears to be the behavior you seek.
I guess most used way to get this done is by simply caching (storing) the value of this in a local context variable
function Example() {
var that = this;
// ...
function privateFunction() {
console.log(that);
}
this.publicFunction = function() {
privateFunction();
}
}
a more convenient way is to invoke Function.prototype.bind to bind a context to a function (forever). However, the only restriction here is that this requires a ES5-ready browser and bound functions are slightly slower.
var privateFunction = function() {
console.log(this);
}.bind(this);
I would say the proper way is to use prototyping since it was after all how Javascript was designed. So:
var Example = function(){
this.prop = 'whatever';
}
Example.prototype.fn_1 = function(){
console.log(this.prop);
return this
}
Example.prototype.fn_2 = function(){
this.prop = 'not whatever';
return this
}
var e = new Example();
e.fn_1() //whatever
e.fn_2().fn_1() //not whatever
Here's a fiddle http://jsfiddle.net/BFm2V/
If you're not using EcmaScript5, I'd recommend using Underscore's (or LoDash's) bind function.
In addition to the other answers given here, if you don't have an ES5-ready browser, you can create your own "permanently-bound function" quite simply with code like so:
function boundFn(thisobj, fn) {
return function() {
fn.apply(thisobj, arguments);
};
}
Then use it like this:
var Example = (function() {
function Example() {
var privateFunction = boundFn(this, function() {
// "this" inside here is the same "this" that was passed to boundFn.
console.log(this);
});
this.publicFunction = function() {
privateFunction();
}
}
return Example;
}()); // I prefer this order of parentheses
VoilĂ -- this is magically the outer context's this instead of the inner one!
You can even get ES5-like functionality if it's missing in your browser like so (this does nothing if you already have it):
if (!Function.prototype.bind) {
Function.prototype.bind = function (thisobj) {
var that = this;
return function() {
that.apply(thisobj, arguments);
};
}:
}
Then use var yourFunction = function() {}.bind(thisobj); exactly the same way.
ES5-like code that is fully compliant (as possible), checking parameter types and so on, can be found at mozilla Function.prototype.bind. There are some differences that could trip you up if you're doing a few different advanced things with functions, so read up on it at the link if you want to go that route.
I would say assigning self to this is a common technique:
function Example() {
var self = this;
function privateFunction() {
console.log(self);
}
self.publicFunction = function() {
privateFunction();
};
}
Using apply (as others have suggested) also works, though it's a bit more complex in my opinion.
It might be beyond the scope of this question, but I would also recommend considering a different approach to JavaScript where you actually don't use the this keyword at all. A former colleague of mine at ThoughtWorks, Pete Hodgson, wrote a really helpful article, Class-less JavaScript, explaining one way to do this.