change scope of 'this' in esquire JS - javascript

I am trying to use enquire.js to trigger a reload of my bxslider when the screen size is small, to show fewer images.
I have registered a screen width as below.
enquire.register("screen and (max-width:900px)", {
match: this.ChangeSliderDown,
unmatch:this.ChangeSliderUp
});
Now as part of the transition i need to do a calculation based on a variable that is associated with the Prototype of the current class.
ChildCarousel.prototype = {
...
ChangeSliderUp: function()
{
var maxSlides = (this.ourCarouselCollection.length < 3) ? 1 : 3;
...
}
}
in all my other functions referring to this allows me to access variables such as the ourCarouselCollection in the instance of enguire js i get the object that is a result of the register call.
why is this happening and is it possible to change it?

adding the bind(this method solved the problem
enquire.register("screen and (max-width:900px)", {
match: this.ChangeSliderDown.bind(this),
unmatch:this.ChangeSliderUp.bind(this)
});

The value of this has nothing to do with scope, it is resolved within an execution context and is set by the call or with bind. Also, it is convention that only functions that are intended to be called as constructors have names that start with a capital letter (so ChangeSliderUp should be changeSliderUp).
The ChangeSliderUp method is expecting to be called with this referencing an instance of ChildCarousel as its this. When you assign a reference to the function like:
match: this.ChangeSliderDown
then the function will be called without this being set to the instance and will default to the global object or be undefined in strict mode.
You can use bind per Bluephlame's answer, or use a closure something like:
// Assuming that this referenes an instance of ChildCarousel
// where this code is running
var carousel = this;
enquire.register("screen and (max-width:900px)", {
match: function() {carousel.ChangeSliderDown();},
unmatch: function() {carousel.ChangeSliderUp();}
});
but I can't test that. It should ensure that the function is called as a method of an instance, hence setting this to the instance.

Related

Changing the current closure?

I am trying to get some old code to work properly with minimal modification. The code was written on the assumption that it would run from a particular context. I have the context object.
Original code:
function oldExample(){
console.log(window); //New Error: window is undefined
console.log(gBrowser); //New Error: gBrowser is undefined
}
New, working code:
function fixedExample(){
console.log(this.window);
console.log(this.gBrowser);
}
//Elsewhere
function loadData(context) {
fixedExample.call(context);
}
Notes:
1. loadData and oldExample are defined in separate files.
2. context has other children besides window and gBrowser; This is an example
Is there a way to transition my oldExample code to work properly without needing to stuff this. everywhere? I.e., how can I run oldExample in a different context?
The only way I know how to do this is to define the properties as variables of the current context:
var object = {gBrowser: 'test'};
function oldExample(){
console.log(gBrowser);
}
var gBrowser = object.gBrowser;
oldExample();
This example outputs 'test'
But all this does is move the property access outside of the function definition, doesn't save you anything.
You can use bind method in javascript.
fixedExample.bind (context);
Now you need not use 'this' inside fixedExample and can use window directly.

Javascript and prototyping procedure

I am trying to write a script that does a slide show. I can do it with functions, but I want to use the prototype method. What I am having a hard time figuring out is the procedure. Here is what I have tried to do
var displayVars = {
slide: '',
thumb: ''
}
//setup display
display = function(slide,thumb) {
displayVars.slide = $(slide);
displayVars.thumb = $(thumb);
// set slider width
}
display.prototype.play = function() {
// move slide to this location
display.hightlight();
}
display.prototype.hightlight = function() {
// add border to element
}
$(function() {
newdis = new display('.show-slide','.window-thumbs');
displayVars.timer = setTimeout(newdis.play,500);
});
If you notice in the play function I want to call the highlight method. What I really want is to run the highlight function every time the play function is called. I can't get my head to see how this can be done because "display" or "this" will not let me access the highlight function.
The problem is not with the innards of your prototype functions, but rather with the way you set up the timeout handler.
displayVars.timer = setTimeout(function() { newdis.play(); }, 500);
Then you'll be able to use this in the "play" function:
display.prototype.play = function() {
// move slide to this location
this.hightlight();
}
There's no intrinsic "membership" relationship between a function and an object of any sort. Object properties can refer to functions, but the only time that means anything is when a function call is made via the object property reference. Since you weren't calling the function, but just grabbing a reference to it to pass to "setTimeout()", there was nothing to set the value of this. By wrapping it in an anonymous function that explicitly calls "play" via the object reference, you set up this correctly.
Another way to do this is with the "bind()" function available in newer browsers:
displayVars.tinmer = setTimeout(newdis.play.bind(newdis), 500);
That will have more-or-less the same effect as the anonymous function (with some extra subtleties that don't make much difference most of the time).

Calling jQuery document.ready handler with apply method?

Below is the code I am using in a project with some complex dependencies. After I have made sure that all the dependencies have been loaded I fire the onReadyCallback() also given below. I have two questions :
Is it correct to use, anonymousHandler.apply(MyNameSpace), the apply method on an anonymous Handler being called for Document.ready
From what I understand, because I am using the apply method the anonymous function will fire immediately irregardless of document's ready state. Then how can I pass in the context of MyNameSpace to the anonymousHandler so that "this" inside the function refers to MyNameSpace
var onReadyCallback = function(){
jQuery(document).ready(function(){
if(!this.loggedIn()){
return;
}
...Lots of Code referring to MyNameSpace using "this"
}.apply(MyNameSpace));
};
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
onReadyCallback.apply(window);
});
});
How about this, using an anonymous function and call?
jQuery(document).ready(function() {
(function() {
// this == MyNamespace
}).call(MyNamespace);
});
Normally, the ready event jQuery function is called like this
$(function() { /* ... */ });
// or
jQuery(function() { /* ... */ });
// or
jQuery(document).ready(function() { /* ... */ });
Bottom line, the function is not given a particular context; the actual context given by jQuery to the function is the HTMLDocument element, regardless of the argument (in the last example, document). Why is this so is another subject.
Generally, each of these functions are called later, after everything has been loaded, but not necessarily. In your case, there is a reference to MyNameSpace before the ready event happens. Even if Javascript is a LALR-type language, and it will find the symbol declared later, this is not a good practice. What if MyNameSpace would be set to something else later on, before jQuery triggers the ready callback functions? Your ready callback would not get that new reference. Unless intentional, the reference should be made inside the ready callback, when everything is.... ready.
Then, inside the ready callback, there are other techniques to assign a context to a function. lonesomeday have pretty much given the correct way to accomplish what you are trying to do.
(function() {
// this == MyNamespace
}).call(MyNamespace);
The above code executes an anonymous function right away, where this == MyNameSpace
note : the difference between apply and call is decribed here
Now, comes the bottom part of the code you provided :
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
onReadyCallback.apply(window);
});
});
This is problematic, and unnecessary. Is the function onReadyCallback only needed there, or will it be called several times? If it needs to be called only once, spare the global namespace, and simply do :
//load the additional files that are needed and fire onReadyCallback
MyNameSpace.Util.loadFiles(defaultJsFiles,function(){
MyNameSpace.Util.require(['My.App','My.Theme','My.DomHandler'], function(){
// if everything is done loading, the function will be executed, otherwise
// it's execution will be postponed later
jQuery(function() {
// create our nicely wrapped anonymous function now
(function() {
if(!this.loggedIn()){
return;
}
// ...Lots of Code referring to MyNameSpace using "this"
})(MyNameSpace); // grab our most recent reference of `MyNameSpace`
});
});
});
If you don't like the indentation (it's merely a developer's taste), replace everything in the ready callback with (something like) :
initMyNameSpace.apply(MyNameSpace);
and create your function outside, on the global space :
function initMyNameSpace() {
if(!this.loggedIn()){
return;
}
// ...Lots of Code referring to MyNameSpace using "this"
};
But I would recommand, at least, to put it in the require callback function so it...
...does not pollute the global namespace with a run-once function
...is not accessible from anywhere (keep it private)
...can be found quickly when editing the source code
etc.
note : usually, apply and call are used to avoid repeatedly accessing objects like some.thing.pretty.deep = value; or when one function needs to be applied to many but not all objects, and thus extending the object's prototype is just not a good idea.
This is my opinion anyway, and how I would do things, without any more knowledge of your code or what you are doing.

Javascript scope help

I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}

jQuery Function Implementation and Function Call?

What is the difference of calling function like:
testCall: function() and function testCall() in jQuery ?
Update:
Questions: Does usage of one over the another have some performance issues related to it OR it really does not matter which one you are using ?
Update 2
Also other thing that I noticed that whenn I am defining function using testCall: function() and I call it using this.testCall() it works fine and am able to call it in any other function.
But when I am using function testCall() and I try to call it using testCall() in another function than I am getting errors and am not able to call it. Is this possible or there could be some other reason for the errors ?
In this example:
testCall: function()
testCall is now a function available on the object you're in, like this: object.testCall() It can access other functions, properties, etc inside this object if it needs to.
In this version:
function testCall()
testCall is just a globally available method, not scoped to the object or plugin, whatever you're dealing with, you can call it from anywhere, like this: testCall()
This is really a question about Javascript syntax (and semantics), not jQuery.
Both of those constructions define functions. This:
var x = {
// ...
name: function() { /* ... */ },
// ...
};
defines a function (an anonymous function) and assigns it as the value of the property called "name" in the object being assigned to the variable "x".
This:
function name() {
/* ... */
}
defines a function with the name "name". The effect is similar to:
var name = function() { /* ... */ };
but definitely different. However, for most purposes it's safe to think about them as being almost the same. The effect is that "name" is bound to the function in the lexically-enclosing scope. If you do that definition outside of any other function, then "name" becomes a property of the "window" object, and the function is therefore globally available. If that declaration is inside another function, then "name" is only available inside that function.
Usually you see the first form when you're doing something like setting up callbacks for some jQuery facility, like a UI plugin or $.ajax. You're giving jQuery a function that it should call upon something happening — an AJAX call finishing, or a use action like a mouse click, or completion of some sort of animation.
edit oh, and finally here's another note. If you define a function the second way, well then you can refer to that function by name and use it in an object definition (like the first example):
function globalFunction() {
function localFunction() { /* ... */ };
jQuery.something({
x: 100, y: 100,
callback: localFunction,
// ...
});
}
Many more such things are possible - functions are values in Javascript and can be tossed around as easily as numbers and strings.
The first (testCall: function()) is object literal notation for defining a function and assigning it to a property on an object (not shown). The function itself is anonymous; the property it is bound to has a name, but the function does not.
The second (function testCall()) is a named function.
Named functions have several advantages over anonymous ones, and so though you see the first format quite a lot, I would recommend using it sparingly if at all. Named functions can be reported usefully by your tools (debuggers and the like), whereas anonymous functions just show up as ? or (anonymous). More here.
For that reason, rather than this:
function doSomeNiftyAjaxyThing(foo) {
$.ajax({
url: "blah",
success: function() {
// Do something involving the successful result and `foo`
foo.bar();
}
});
}
I would typically do this instead:
function doSomeNiftyAjaxyThing(foo) {
$.ajax({
url: "blah",
success: niftySuccess
});
function niftySuccess() {
// Do something involving the successful result and `foo`
foo.bar();
}
}
Not only does this keep my code a bit cleaner (er, to my mind), but it means that if something goes wrong inside niftySuccess, I've given the function a name my tools can report to me. Note that other than the fact that the function has a name, they're identical – both functions are closures over the foo argument and anything else inside doSomeNiftyAjaxyThing.
You might be tempted to give the function a name inline, like so:
function doSomeNiftyAjaxyThing(foo) {
$.ajax({
url: "blah",
success: function niftySuccess() { // <== change here, PROBLEMATIC
// Do something involving the successful result and `foo`
foo.bar();
}
});
}
There you're declaring a function with a name as an expression, and assigning the result of the expression to a property. Arguably you should be able to do that, but there are a series of implementation...anomalies in the various Javascript engines out there that prevent your being able to do that. (More in the article linked above, and in this article.)

Categories

Resources