I have a function localised to the main function and i want to use this to call it but it doesn't seem to work.
My code has:
function option(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity
transition_opacity(div_id,opacity,0,function(){this.load});
function load(){
console.log('test'); //does not happen
}
}
Have i misunderstood the use of this or is the scope lost when i use function(){} to call load?
From your code it is not obvious, what object this could refer to. It depends on how option is called. However, if you define the load function inside of the option function anyway, it is best to just reference it directly. You will have to move the declaration of test above the transition_opacity call though:
function option(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity;
function load() {
console.log('test');
}
transition_opacity(div_id,opacity,0,load);
}
As you can see, I just reference load directly. You could make another function which calls the load function inside (i.e. function() { load(); } – note the parentheses which calls the function) but that would give you no benefit but would just add another unneeded function to the stack. So just refer to the actual function itself.
For more information on the this keyword, check out this question. Spoiler: It’s more complicated than you would expect.
The scope of this is lost in this instance, probably pointing to the document. You can capture this to a variable in the outer scope to make this work as intended.
var context = this;
transition_opacity(div_id,opacity,0,function(){context.load();})
The above will not work however. This is because load does not exist on the context of this. You would need to define the load function as such:
context.load = function(){
console.log('test');
}
Both.
First, your load function is not a member/property of any this, the way you have it coded. Your load function is simply a nested function that exists within your option function, as has been sort of implicitly noted in other responses.
In your option function, if you want 'load' to become a member of 'this', you'd need to say so, like this:
function option(){
this.load = function(){}; // now load is actually a property of whatever this is
}
Second, you and the other poster are correct that 'this' is no longer the same 'this' by the time your anonymous function is called.
Whenever you call a function, a brand new 'this' is created and exists within the scope of that function. If you just call a function like this:
transition_opacity(args);
.. then within transition_opacity, 'this' just refers to the window object, or maybe window.document. For 'this' to refer to anything other than window or window.document, you need to (in effect) do one of the following:
myObject.transition_opacity(args);
transition_opacity.call(myObject, arg1, arg2, ..);
transition_opacity.apply(myObject, argArray);
or
var myObject = new transition_opacity(args);
In each of those cases, within transition_opacity, 'this' refers to myObject (or, well, in the last case, it refers to a new object that is being created and assigned to myObject).
Here is a way to do what it looks like you're trying to do:
var MyNamespace = {
option: function(room,slot){
var div_id = document.getElementById(room);
var opacity = window.getComputedStyle(div_id).opacity;
var _this = this;
transition_opacity(div_id,opacity,0,function(){
// Careful! Inside here, 'this' is just window or window.document,
// unless transition_opacity sets it to something using call or apply,
// in which case that 'this' is probably not the 'this' you want.
// So carefully refer to the saved instance of 'this':
_this.load();
});
},
load: function(){
console.log('test'); // now it should happen
}
}
.
.
MyNamespace.option(room, slot); // inside option, 'this' is MyNamespace.
Here's another way to do it:
function MyClass(){};
MyClass.prototype = {
// all the same stuff that is in MyNamespace above..
};
.
.
var myObject = new MyClass();
myObject.option(room, slot);
Clear as mud?
Just use
transition_opacity(div_id,opacity,0,load);
You have defined a 'load' within another function as an 'Function Declaration', so now it is only accessible within 'option' function and in other functions defined in this one by name 'load'. You can't access it by using 'this.load' no matter what 'this' is. If you want to access 'load' function as 'this.load' you can try this example to understand how 'this' keywoard works
// Function Declaration
function f1(callback){
callback();
};
// Function Declaration
function f2(){
// Function Expression
this.load = function(){
console.log("test");
};
f1(this.load);
};
var obj = new f2(); // test, this == obj, so obj.load() now exists
obj.load(); //test, this == obj
f2(); //test, this == window, so window.load() now exists
load(); //test, window is the global scope
Related
There's a little something about scope I just keep getting confused about:
this.init = function(){
var t = this;
setTimeout(function(){
// why is t still available here?
t.initgame();
// but not this?
this.initgame();
}, 500);
}
this.initgame = function() {
// yada yada
}
I get that inside an anonymous function, scope is different that outside of it.
But why, in the above example, is the variable "t" available inside the timeout function, while "this" is not working?
The problem is that setTimeout is called with window as scope.
Using a dedicated variable to store this (t) is a perfectly valid and usual solution.
On modern browsers, bind is sometimes convenient :
setTimeout((function(){
// use this
}).bind(this), 500);
When the anonymous function runs, it is no longer running as a member function of init, but rather a top-level function of window. As a result, this.initgame() has no meaning.
For example, running console.log(this) inside the timeout function returns as follows:
Window {top: Window, window: Window, location: Location, external:...
When you use var t = this, you assign reference to the current object, which works.
I'm confused as to what the problem is with context in a JS constructor. Within the ctor I have a function declared. Before the call to that function this is set to the context of the ctor. Inside the function the value of this is set to window. I don't understand why. In the HTML the ctor is called with 'new'.
function MyCtor() {
var myFunc = function() {
debugger; // #2
// code for myFunc
}
debugger; // #1
myFunc();
debugger; // #3
}
At debugger #1, this is set to MyCtor. At #2 this is window. And at #3 it is back to MyCtor.
I'm sure I'm missing something basic here, but I've read a lot on scope and context; obviously not enough.
The this object is one of the most annoyingly hard-to-understand concepts in Javascript. And that's quite a contest to win... First off, you have to understand that it will be specific to each function you call - the context in which you call myFunc won't set it how you want it. Here's one way you can do it:
function MyCtor() {
this.myFunc = function() {
debugger; // #2
// code for myFunc
}
debugger; // #1
this.myFunc();
debugger; // #3
}
Generally, there are only a few situations in which you can rely upon a function's this to be a particular value. All of them to my knowledge:
objectToBeThis.aFunction = function() { ... } // declare this function as
// an object property at any time -
objectToBeThis.aFunction();
Or, not used as often is:
aFunction.call(objectToBeThis, extraArgument1, extraArgument2);
When a named, but not "owned" function (ie, var functionName = function(), or function functionName()) is called, then it will have window as its this argument. This part I'm less sure of as a certainty, but I just wouldn't use this inside such a method.
As in the case of your code, there's also "new MyCtor" - in which a new object is created to be returned, and that object is set to this inside of the constructor method.
I'm trying to call a js function within another one, but use the argument to specify the function. ie depending on the argument passed, it will call a different function
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
check+n();
}
else
}
So, for example, if the argument 'Balloons' was passed as n, then it will call the function checkBalloons(). "check+n();" is not currently working here. Sorry for my lack of simple js syntax!
If the function is defined in the global scope (browser) you can do:
window["check"+n]();
or some tenants like Node.js you would access it from global object.
global["check"+n]();
if it is a part of some other object then you would do the same.
obj["check"+n]();
Functions and properties defined on an object can be accessed using [] convention as well. i.e obj["propFuncName"] will give you reference to it, so in case of methods you add () to invoke it.
If the function is global, you would do this:
window["check" + n]();
or, you could put your function in an object like so:
myNamespace = {};
myNamespace.checkSomething = function(){ /* ... */ }
// call it like this:
myNamespace["check" + n]();
The answers thus far are correct, but lack explanation.
In JavaScript, you cannot call a function by name when that name is a string. What you can do is retrieve a value from an object by name, and if that value happens to be a function, you can then call it. For example:
var myObject = {};
myObject.myFunction = function() { alert('test!'); };
// Get the property on `myObject` called `myFunction`
var theFunctionLookup = myObject['myFunction'];
// Since that property was a function, you can call it!
theFunctionLookup();
In the browser, functions that are defined in the global scope are attached to the window object. For example, this works:
function myFunction() { alert('test'); }
var theFunctionLookup = window['myFunction'];
theFunctionLookup();
You can shorten the last two lines into one:
function myFunction() { alert('test'); }
// Look up and call the function in one line.
window['myFunction']();
For the same reasons, you can use a dynamically-calculated string to look up functions.
function checkBalloon() {
alert('checking balloon');
}
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
window['check' + n]();
check+n();
}
}
toggle('Balloon');
if you do this way:
if (sessionStorage['toggle'+n]== 0){
window["check" + n]();
}
will work
I have been fiddling with code to call a function with the name of the value of a variable and then keep the this scope when called, but the this pointer seems to be in context of the element I have used jQuery's bind method on, rather than the object the function I might be calling is within. To clarify here´s some code to illustrate the problem:
classname.prototype = {
bindElementToFunction: function(element, functionToCall){
$(element).bind("click",
{realThis: this, functionToCall: functionToCall},
this.callFunction);
},
// I had hoped I could change the this pointer back to the object by running
// it through this function, I have tried using .apply and .call but I can't
// seem to get them to work with function pointers
callFunction: function(event){
var realThis = event.data.realThis;
var functionToCall = event.data.functionToCall;
functionToCall = realThis[functionToCall];
// I have tried .apply and .call in several different ways but can't seem
// to get them to work in this context
functionToCall();
},
abitraryFunction: function(){
this.test();
},
};
The problem here is then that everything works fine up until abitraryFunction where this is still referring to the element from the bind function. I have tried doing .apply() with the appropriate this pointers, but they do not seem to work.
So here's the question how do I change the context of the "this" pointer in combination with function pointers?
Feel free to scrap all the code I have written, as long as I am able to do a bind function to an element that then runs a method within a object where "this" is refferring to the object the method is within.
Thanks
I think the jQuery bind is making your code way more complicated than it needs to be. The JavaScript bind() function works perfectly:
http://jsfiddle.net/bQGWS/
By simply assigning a function to the onclick (or any other event hook) of an element, this is evaluated from the element's point of view and so points to the element itself.
When you use bind, you end up with a copy of the function where this is effectively replaced with the var you passed into bind().
classname = function(){}
classname.prototype = {
method: function(){
try {
alert( this.othermethod() );
} catch(e) {
// Method doesn't exist in scope
alert( 'Wrong scope :(');
}
},
othermethod: function(){
return 'hello desired scope!';
},
referenceToElement: function(elementId, functionname){
var el = document.getElementById(elementId);
// Just assigning the function as is
el.onclick = this[functionname];
},
bindToElement: function(elementId, functionname){
var el = document.getElementById(elementId);
// Using the bind function to create a copy in the
// scope of this (within the prototype)
el.onclick = this[functionname].bind(this);
}
}
var instance = new classname();
instance.referenceToElement('reference', 'method');
instance.bindToElement('bound', 'method');
I defined a global Javascript function:
function resizeDashBoardGridTable(gridID){
var table = document.getElementById('treegrid_'+gridID);
.....
}
After this function was used a few times, I want to remove(or undefined) this function because the Procedure code should be called again. if somebody try to call this method we need do nothing.
I don't way change this function right now.
so re-defined this function may be one way:
function resizeDashBoardGridTable(gridID){
empty,do nothing
}
Thanks. any better way?
Because you're declaring it globally, it's attached to the window object, so you just need to redefine the window function with that name.
window.resizeDashBoardGridTable = function() {
return false;
}
Alternately you could redefine it to any other value or even to null if you wanted, but at least by keeping it a function, it can still be "called" with no detriment.
Here's a live example of redefining the function. (thanks TJ)
An additional reason for pointing out that I'm redefining it on the window object is, for instance, if you have another object that has that function as one if its members, you could define it on the member in the same way:
var myObject = {};
myObject.myFunction = function(passed){ doSomething(passed); }
///
/// many lines of code later after using myObject.myFunction(values)
///
/// or defined in some other function _on_ myObject
///
myObject.myFunction = function(passed){}
It works the same either way, whether it's on the window object or some other object.
how about using a var?
// define it
var myFunction = function(a,b,c){
console.log('Version one: ' + [a,b,c].join(','));
}
myFunction('foo','bar','foobar'); // output: Version one: foo,bar,foobar
// remove it
myFunction = null;
try { myFunction(); console.log('myFunction exists'); }
catch (e) { console.log('myFunction does not exist'); }
// re-define it
myFunction = function(d,e,f){
console.log('Version two: ' + [d,e,f].join(','));
}
myFunction('foo','bar','foobar'); // output: Version two: foo,bar,foobar
OUTPUT:
[10:43:24.437] Version one: foo,bar,foobar
[10:43:24.439] myFunction does not exist
[10:43:24.440] Version two: foo,bar,foobar
The simplest approach is to set the function (treat it as a variable) to null. This works even if you don't declare it as a var. Verified this on IE.
resizeDashBoardGridTable = null
If the functions needs to be called 1 time you use an anonymous self invoking function like this:
(function test(){
console.log('yay i'm anonymous');
})();
If you have to call the function multiple times you store it into a var and set it to null when you're done.
Note: You don't have to name an anonymous function like I named it test. You can also use it like this:
(function(){
console.log('test');
})();
The reason I do name my anonymous functions is for extra readability.