How to best use 'this' when its unavailable - javascript

say I create someObj like this
var someObj = function(){
var self = this;
//use this normally
document.body.addEventListener('click',function(){
//use self because this is unavailable
},false)
}
new someObj();
In the event this is not the someObj which id like to use but in this case the body element. Is there a best practice way to get someObj or is declaring some self var like in the example considered any good?

Using self seems fine to me.
You might also want to check out using call or apply (see for example odetocode and specifically about this in this post)

In my experience, declaring something like 'self' is the easiest way to do it.
I would consider your code to be perfectly acceptable.

Related

Javascript call function with “this” on event [duplicate]

I have created a 'control' using jQuery and used jQuery.extend to assist in making it as OO as possible.
During the initialisation of my control I wire up various click events like so
jQuery('#available input',
this.controlDiv).bind('click', this, this.availableCategoryClick);
Notice that I am pasing 'this' as the data argument in the bind method. I do this so that I can get at data attached to the control instance rather from the element that fires the click event.
This works perfectly, however i suspect there is a better way
Having used Prototype in the past, I remember a bind syntax that allowed you to control what the value of 'this' was in the event.
What is the jQuery way?
You can use jQuery.proxy() with anonymous function, just a little awkward that 'context' is the second parameter.
$("#button").click($.proxy(function () {
//use original 'this'
},this));
I like your way, in fact use a similar construction:
$('#available_input').bind('click', {self:this}, this.onClick);
and the first line of this.onClick:
var self = event.data.self;
I like this way because then you get both the element clicked (as this) and the "this" object as self without having to use closures.
jQuery has the jQuery.proxy method (available since 1.4).
Example:
var Foo = {
name: "foo",
test: function() {
alert(this.name)
}
}
$("#test").click($.proxy(Foo.test, Foo))
// "foo" alerted
I don't think jQuery has a built-in feature for that. But you could use a helper construct like the following:
Function.prototype.createDelegate = function(scope) {
var fn = this;
return function() {
// Forward to the original function using 'scope' as 'this'.
return fn.apply(scope, arguments);
}
}
// Then:
$(...).bind(..., obj.method.createDelegate(obj));
This way, you can create dynamic 'wrapper functions' with createDelegate() that call the method with a given object as its 'this' scope.
Example:
function foo() {
alert(this);
}
var myfoo = foo.createDelegate("foobar");
myfoo(); // calls foo() with this = "foobar"
HTML 5-compliant browsers provide a bind method on Function.prototype which is, probably the cleanest syntax and is not framework-dependent, though it is not built into IE until IE 9. (There is a polyfill for browsers without it, though.)
Based on your example, you can use it like this:
jQuery('#available input',
this.controlDiv).bind('click', this.availableCategoryClick.bind(this));
(side note: the first bind in this statement is part of jQuery and has nothing to do with Function.prototype.bind)
Or to use slightly more concise and up-to-date jQuery (and eliminate confusion from two different kinds of binds):
$('#available input', this.controlDiv).click(this.availableCategoryClick.bind(this));
you can use the javascript bind method like this:
var coolFunction = function(){
// here whatever involving this
alert(this.coolValue);
}
var object = {coolValue: "bla"};
$("#bla").bind('click', coolFunction.bind(object));
jQuery does not support binds and the preferred way is to use functions.
Because in Javascript, this.availableCategoryClick does not mean calling the availableCategoryClick function on this object, jQuery advise to use this preferred syntax:
var self = this;
jQuery('#available input', self.controlDiv).bind('click', function(event)
{
self.availableCategoryClick(event);
});
OO concepts in Javascript are hard to understand, functionnal programming is often easier and more readable.
Seeing that functions changes scope, the most common way is to do it by hand, with something like var self = this.
var self = this
$('.some_selector').each(function(){
// refer to 'self' here
}

Javascript: making the global eval() behave like object.eval()

Ok- I have a very specific case for which I need to use eval(). Before people tell me that I shouldn't be using eval() at all, let me disclose that I'm aware of eval's performance issues, security issues and all that jazz. I'm using it in a very narrow case. The problem is this:
I seek a function which will write a variable to whatever scope is passed into it, allowing for code like this:
function mysteriousFunction(ctx) {
//do something mysterious in here to write
//"var myString = 'Oh, I'm afraid the deflector shield will be
//quite operational when your friends arrive.';"
}
mysteriousFunction(this);
alert(myString);
I've tried using global eval() to do this, faking the execution context with closures, the 'with' keyword etc. etc. I can't make it work. The only thing I've found that works is:
function mysteriousFunction(ctx) {
ctx.eval("var myString = 'Our cruisers cant repel firepower of that magnitude!';");
}
mysteriousFunction(this);
alert(myString); //alerts 'Our cruisers cant repel firepower of that magnitude!'
However, the above solution requires the object.eval() function, which is deprecated. It works but it makes me nervous. Anyone care to take a crack at this? Thanks for your time!
You can say something like this:
function mysteriousFunction(ctx) {
ctx.myString = "[value here]";
}
mysteriousFunction(this);
alert(myString); // catch here: if you're using it in a anonymous function, you need to refer to as this.myString (see comments)
Demo: http://jsfiddle.net/mrchief/HfFKJ/
You can also refactor it like this:
function mysteriousFunction() {
this.myString = "[value here]"; // we'll change the meaning of this when we call the function
}
And then call (pun intended) your function with different contexts like this:
var ctx = {};
mysteriousFunction.call(ctx);
alert(ctx.myString);
mysteriousFunction.call(this);
alert(myString);
Demo: http://jsfiddle.net/mrchief/HfFKJ/4/
jsFiddle
EDIT: As #Mathew so kindly pointed out my code MAKES NO SENSE! So a working example using strings:
function mysteriousFunction(ctx) {
eval(ctx + ".myString = 'Our cruisers cant repel firepower of that magnitude!';");
}
var obj = {};
mysteriousFunction("obj");
alert(obj.myString);
I'm fairly sure it's impossible to write to the function scope (i.e. simulate var) from another function, without eval.
Note that when you pass this, you're either passing the window, or an object. Neither identifies a function (the scope of a non-global var).

Javascript function change variables scope

I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Below is demonstrating what I'm talking about.
I just need to get rid of eval.
//Used to determine where the variable is being stored
var variableScope = "global";
(function(window){
var variableScope = 'insideFunction',
appearingToBeGlobalFunction = function(){
alert("This Function appears Global but really isn't");
};
window["addFunction"]=function(funName,fun){
//window[funName] = fun; Doesn't work
eval("window[funName]="+fun+";");
}
})(window);
addFunction("alertTest",function(){
alert(variableScope);
appearingToBeGlobalFunction();
});
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();
Edit: The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();​
You can't get rid of eval and still expect it to work. That's the only way to take a look at members of the scope after it's been "closed." I've messed around with something similar in the past, but I would never actually use it anywhere. Consider an alternate solution to whatever you're trying to accomplish.
eval("window[funName]="+fun+";");
Oh dear Lord.
The reason this “works” is that you are converting the function fun (alertTest) into a string to put it in the eval argument.
It happens that in most desktop browsers, a native JS function's toString() result will be a string that looks like a function expression containing the same code as the original declaration. You're turning a function back into a string and re-parsing that string in the context of the new enclosing function, so the new function value is the same code but with a different closure.
However, it is not required that Function#toString work like this, and in some cases it won't. It is not safe to rely on function decomposition; avoid.
You can certainly only do this kind of horrific hackery using eval, although there is no reason the window[funName]= part has to be inside the eval. window[funName]= eval('('+fun+')'); would work equally well (badly).
I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Whyever would you do something crazy like that?
you could force the variables to be in the global scope eg instead of var variableScope = 'insideFunction' you use window.variableScope = 'insideFunction'
The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();​

How can I keep the context of 'this' in jquery

I have something like this:
var Something = function(){
this.render = function(){};
$(window).resize(function(){
this.render();
});
}
The trouble is that inside the anonymous function 'this' refers to the window object. I know I could do something like:
var Something = function(){
this.render = function(){};
var tempThis = this;
$(window).resize(function(){
tempThis.render();
});
}
but is there a better way? This doesn't look very elegant.
The solution you found is the the one most people use. The common convention is to call your tempThis variable "that."
var Something = function(){
this.render = function(){};
var that = this;
$(window).resize(function(){
that.render();
});
};
That looks like your best option, I don't think there's a better way. (someone correct my if I'm wrong).
FYI the ability to control this is coming in the next version of JQuery
I've been doing it this way in many tight situations. It doesn't look elegant, but it never fails. Actually thats javascript closures in action.
jrh
That's exactly what I do. It's not specific to jQuery, either.
var Construct = function() {
var self = this; //preserve scope
this.materials = 2000;
this.build = function(){
self.materials -= 100;
};
};
Remember to use the var keyword in front of your new scope variable. Otherwise, you're creating a new global variable. As a local variable, it will still be accessible inside the inner function via a closure.
The best solution, to keep variables at a minimum would be to use the Function.prototype.bind() method.
var Something = function(){
this.render = function(){};
$(window).resize( this.render.bind( this ) );
}
The problem with this method that may cause future complications, which means you should choose to use it sparingly, is when you need to invoke $(this) to grab the element. So, I might suggest that it would be worthwhile to use Function.prototype.bind() in your resize method, but it would not be a good solution to use it in a click function that you might need to target the clicked element directly.
See this JSFiddle for a working example.
See the Mozilla Documentation on Function.prototype.bind() for more information
The other methods are usable, but creating a variable to maintain the context of this is the undesired effect according to your question.

Javascript equivalent of Python's locals()?

In Python one can get a dictionary of all local and global variables in the current scope with the built-in functions locals() and globals(). Is there some equivalent way of doing this in Javascript? For instance, I would like to do something like the following:
var foo = function(){ alert('foo'); };
var bar = function(){ alert('bar'); };
var s = 'foo';
locals()[s](); // alerts 'foo'
Is this at all possible, or should I just be using a local object for the lookup?
locals() - No.
globals() - Yes.
window is a reference to the global scope, like globals() in python.
globals()["foo"]
is the same as:
window["foo"]
Well, I don't think that there is something like that in js. You can always use eval instead of locals(). Like this:
eval(s+"()");
You just have to know that actually function foo exists.
Edit:
Don't use eval:) Use:
var functionName="myFunctionName";
window[functionName]();
I seem to remember Brendan Eich commented on this in a recent podcast; if i recall correctly, it's not being considered, as it adds unreasonable restrictions to optimization. He compared it to the arguments local in that, while useful for varargs, its very existence removes the ability to guess at what a function will touch just by looking at its definition.
BTW: i believe JS did have support for accessing locals through the arguments local at one time - a quick search shows this has been deprecated though.
#e-bartek, I think that window[functionName] won't work if you in some closure, and the function name is local to that closure. For example:
function foo() {
var bar = function () {
alert('hello world');
};
var s = 'bar';
window[s](); // this won't work
}
In this case, s is 'bar', but the function 'bar' only exists inside the scope of the function 'foo'. It is not defined in the window scope.
Of course, this doesn't really answer the original question, I just wanted to chime in on this response. I don't believe there is a way to do what the original question asked.
#pkaeding
Yes, you're right. window[functionName]() doesn't work in this case, but eval does. If I needed something like this, I'd create my own object to keep those functions together.
var func = {};
func.bar = ...;
var s = "bar";
func[s]();
AFAIK, no. If you just want to check the existence of a given variable, you can do it by testing for it, something like this:
if (foo) foo();

Categories

Resources