Is it possible to define multiple variables with a single jQuery chain?
var sectionTable = jQuery("#sectionsTable");
var sectionTableRows = sectionTable.find("tr");
var sectionTableColumns = sectionTableRows.find("td");
I don't know what the syntax would be if it is possible but if you took the 3 variables above how could you chain them and would it be considered good practice?
Many thanks
Chris
EDIT: Wow, thanks for all the comments. Sorry for being vague, what I was after was a better way (if one exists) of defining child variables from a parent variable. That's why I thought of using the chain and wondered if a way existed. Thanks for the great advice.
If you really want to, anything is possible :
Of the top of my head, you could try to do something like this :
var sectionTable,
sectionTableRows,
sectionTableColumns = $('td', (sectionTableRows = $('tr',(sectionTable = $('#sectionsTable')))));
Another ideea would be to build a mini-plugin that assigns the current jquery object to a certain field of an object :
jQuery.fn.assignTo = function(variableName,namespace){
var ns = namespace || window;
ns[variableName] = this;
return this;
}
With this peace of code you could do the following :
var sections = {};
jQuery("#sectionsTable")
.assignTo('sectionTable',sections)
.find("tr")
.assignTo('sectionTableRows',sections)
.find("td")
.assignTo('sectionTableColumns',sections);
console.log(sections.sectionTable);
console.log(sections.sectionTableRows);
console.log(sections.sectionTableColumns);
Of course, if you do not specify any namespace, the variables will be global (will be attached to the window object);
Any way, I do not encourage you to use these examples, because it doesn't make very much sense to worsen your code's readability in favour of fewer equal signs and var declarations.
I maybe don't really understand what you want or need, but you can chain any function for a jQuery wrapped set and "end" it and therefor "go back" to the previous set. For instance:
jQuery("#sectionsTable").css('background-color', 'red')
.find('tr').css('background-color', 'yellow')
.find('td').css('background-color', 'black')
.end() // back to 'tr'
.doSomething()
.end() // back to '#sectionsTable'
.doSomething();
However, this would imply that you only need to access those elements once. If you need to access them later in your code, you always should store the results references in variables for several performance reasons.
You could rewrite it as follows:
var $sectionTable = $('#sectionsTable'),
$sectionTableRows = $('tr', $sectionTable),
$sectionTableColumns = $('td', $sectionTableRows);
But of course, that’s only useful if you’re actually gonna use all three of those variables.
The only thing comes to my mind is one-var declaration, like:
var sectionTable = jQuery("#sectionsTable"),
sectionTableRows = sectionTable.find("tr"),
sectionTableColumns = sectionTableRows.find("td");
Why would you want to?
What's wrong with defining the three variables?
(No, you can't).
If you didn't need the sectionTable or sectionTableRows variables at all, you could of course do;
var sectionTableColumns = jQuery("#sectionsTable").find("tr").find("td");
Which, using the descendant selector, could be shortened to just;
var sectionTableColumns = jQuery("#sectionsTable tr td");
Related
I'm new to javascript and have picked up an application developed by another team recently.
In this program in one place where they declare several variables at once there is a missing comma like:
var me = this,
missing = this.missingComma
grid = something.Something;
What if any are the consequences of there not being a comma after the second entry. The relevant bit appears to work when just running it. The code has no tests and since it's javascript I cant compile it, also I dont really know what its supposed to do so unfortunately 'not falling over' is currently my best guess at 'does what its supposed to do'!
Why does it work? Isn't this a syntax error?
In JavaScript the semi-colons aren't required to indicate the end of a line. A linebreak is sufficient to indicate that the next line is a separate statement rather than a continuation of the previous line of code (as is the case when you use the comma to indicate multiple variables).
Your code is essentially the same as this:
var me = this, missing = this.missingComma;
grid = something.Something;
Since that declares the grid variable without the var keyword, you'd end up with grid being created in the global, rather than the current, scope. That's generally something you want to avoid but it's not going to be the end of the world if it does happen - in this case it may even be intended (though I'd guess not).
Javascript is ubiguitous with a a lot of freedom ;)
Maybe it helps you to understand some peculiarity of JS if you read some additional info about semicolons, commas and newlines in Javascript:
http://www.codecademy.com/blog/78-your-guide-to-semicolons-in-javascript
For the sake of readability, I would suggest you to use the classic approach, anyway.
var me = this;
var you = that;
or at least
var me = this, you = that;
For the rest, I think that Anthony Grist has brought it to the point.
Well even though in javascript the semicolon is not required it is a must now a days, because if you want your JavaScript to get minimized, it must have all semicolons. Minimization puts your complete JavaScript in one line... replacing long variable names with short ones, etc.
On the other hand... back to you question.
If you declare your var inside a JavaScript "namespace" (actually an object) then all the variables are "private" and you could choose to make the ones "public" by using the reveal pattern.
This is a good practice, else all you variables are declared on the windows scope... which actually can then be overwritten by any other part of your page that uses the same variable name, even if you thought it was completely independent.
So you could actually do something like this :
var MyNamespace || {}
// this delcares an object MyNamespace only if it doesn't exists yet
MyNamespace.Logic = function(){
var self = this,
myPrivateVariable = "Hello",
self.myPublicVariable = "World",
self.printHello = function(){
alert(myPrivateVariable +' ' +self.myPublicVariable );
};//this semicolon closes the var statement
};
Now you can use somehwer on you page folowing logic
var newInstanceOnMyLogic = new MyNamespace.Logic()
This is equivalent of writing
var newInstanceOnMyLogic = new window.MyNamespace.Logic();
But your variables myPrivateVariable and myPublicVariable are no longer on the windows context and can't be overwritten
Now if you write something like
alert(newInstanceOnMyLogic.myPublicVariable);
you'll get a "World"
But
alert(newInstanceOnMyLogic.myPrivateVariable );
you'll get an undefined
and
newInstanceOnMyLogic.printHello();
will get an alert of "Hello World"
Considering this:
var getToDaChoppa = false;
var warIsHell = function() {
// Write your do/while loop here!
do {
console.log("I can't my legs omg my LEGS");
} while (getToDaChoppa);
};
warIsHell();
and this
var getToDaChoppa = function() {
var getToDaChoppa = false;
do {
console.log("I can't my legs omg my LEGS");
} while (getToDaChoppa);
};
getToDaChoppa();
I really like to know which piece of code is better from a technical standpoint. (Lower memory usage, garbage generation, etc). I'm pretty n00b to js, but I want to make sure I'm writting the best possible code.
From my limited experience the second snippet will generate double garbage than the first one, but in the other hand, the first one uses double the memory than the second one, so I was wondering what is the best approach here. Ofc if you need to swing around variable values, ¿I understand first one is more versatile?, but I cannot fully comprenhend the pros / cons of both methods.
Any little explanation will be of great help o:)
The main difference I see between your two functions is that the first one uses a global (or at least external) variable while the second one use a local variable.
Then the rule is simple : don't declare a variable in an external scope if you don't use it in that scope. Always declare your variables in the most internal scope. This makes the code more readable and limits the risks of collision. Trying to reduce the garbaging by making it external is terrible practice and useless unless, in a very specific case, you proved by profiling you have a problem and it is solved that way (then... I won't probably trust you...).
A second rule would be : don't shadow variables if possible. Shadowing the name of the function with a boolean variable is very confusing.
Here's a "fixed" code :
var getToDaChoppa = function() {
var finished = false;
do {
// some code, which hopefully will at some point set finished to true
} while (!finished); // you wanted a !, here, no ?
};
getToDaChoppa();
I would say that the second approach is better simply because you're keeping the condition variable inside the function scope, thus not polluting the global scope.
Also, don't name the variable with the same name as the function.
I'm looking for the standard way to calculate a variable once, then access it within the scope of every execution of a function, without relying on global variables.
This seems like a standard use of prototype properties (variables) - but every example I can find on JS prototypes is based on prototype methods (functions). The only thing I can find about setting properties / variables in a prototype is a question from someone who also couldn't find any information about these, asking if it's good or bad practice (tldr: it's fine, but remember it's rarely worth sacrificing readability for tiny performance gains).
I've got a way to set and get prototype properties that works, but feels clunky as it depends on a reference to the function (essentially var prop = thisfunctionname.prototype.someprop). Since I found it through trial and error, I'd like to ask if there's a cleaner, more standard way to get these prototype properties from within the function, without going back up to the scope around the function and getting the function from there?
Here's a simplified light-hearted example: an imaginary jQuery plugin that adds a number to another number then returns it in a sentence with the user's name. We want to ask the user their name only once, then store that name for re-use within scope:
(function($) {
var sum = function( num1,num2 ) {
var result = num1 + num2;
// This works, but seems clunky since it depends on the variable `sum`
// from the scope around this function - is there a better way?
var name = sum.prototype.name;
$(this).text( num1+' plus '+num2+' is '+result+', '+name+'.');
return $(this);
};
var name = prompt('Please enter your name','');
// Is there a better way to set this default variable to be accessible
// in all calls to this function?
sum.prototype.name = name;
$.fn.basicArithmetic = sum;
})(jQuery);
// end of plugin. Example usage...
$('<p/>').basicArithmetic(1,5).appendTo('body');
$('<p/>').basicArithmetic(2,2).appendTo('body');
$('<p/>').basicArithmetic(25,30).appendTo('body');
$('<p/>').basicArithmetic(92.3,15.17).appendTo('body');
Live jsbin example. More realistic real-life use cases would be when the calculation for the property is expensive in memory usage, or destructive (e.g. requires changing the DOM during calculation).
Two different answers, really:
The usual way is to use a variable within a scoping function (you already have one handy in your example); no prototypes involved at all.
(function($) {
var name;
name = prompt('Please enter your name','');
function sum( num1,num2 ) {
var result = num1 + num2;
$(this).text( num1+' plus '+num2+' is '+result+', '+name+'.');
return $(this);
}
$.fn.basicArithmetic = sum;
})(jQuery);
Updated JSBin Example | Source
(Side note: I also changed your anonymous function expression into a named function declaration, but it doesn't really matter in this case.)
The usual way in a jQuery plug-in is to store the data on the element(s) the plug-in is being applied to. That doesn't work for the example you gave, which requires that the data be global to the plug-in, but normally (not always, just normally) plug-ins keep only instance-specific information, which you'd normally store on elements (probably via the data function).
Due to performance and other issues, I want to split my code into seperate functions as before it was just one big ".ready" function.
I am new to javaScript/jquery but I thought I would give it a go myself. I have done exactly the way I thought it was done but my console is telling me things are undefined so I am guessing I have got things out of scope. I have read up on it in more detail, but still have not got anywhere.
My code works OK at the moment but I want to get into the habbit of clean coding. Can someone point out where I am going wrong so I can carry on myself?
Here is an example of what I have so far
//Global variables
var randomWord = [];
var listOfWords = [];
var populationNumber = [];
var attemptNumber = [];
var completionNumber = [];
var gridSize = [];
generateGrid();
startMusic();
randomizeReward();
//Click event to start the game
$(".start-btn-wrapper").click(function () {
startplay();
});
//Click event to restart the game
$(".restart-btn").click(function () {
restartplay();
});
Thanks
Fiddle: http://jsfiddle.net/QYaGP/
Fiddle with HTML: http://jsfiddle.net/QYaGP/1/
You need to start passing some information into the functions you're defining. If your functions all have no arguments, then you will have to use globally defined variables, hardcoded references to jquery selections etc in order to get anything done.
So as an example, you have a function
function replaySound() {
$("#hintSound").attr('src', listOfWords[randomWord].hintSound);
hintSound.play();
}
This is actually going to play the sound detailed in listOfWords[randomWord] via the element #hintSound. You could do that via:
function playSound(selector, wordlistEntry) {
$(selector).attr('src', wordlistEntry.hintSound);
$(selector)[0].play();
}
And then instead of calling replaySound(), you'd call:
playSound('#hintSound', listOfWords[randomWord]);
This way the behaviour that you want is wrapped up in the function, but the specifics, i.e. the data you need for it, are passed in via the arguments. That allows you to reuse the function to play any sound using any selector, not just #hintSound.
You'll find as you do that that you need to start choosing what a function will act on in the code that calls it, rather than in the function. That's good, because the context of what you're trying to achieve is there in the calling code, not in the function. This is known as 'separation of concerns'; you try to keep logic about a given thing confined to one area, rather than spreading it about in lots of functions. But you still want functions to allow you to encapsulate behaviour. This allows you to change behaviour cleanly and easily, without having to rewrite everything every time some part of the logic changes.
The result should be that you find several functions actually did the same thing, but with different specifics, so you can just have one function instead and reuse it. That is the Don't Repeat Yourself principle, which is also important.
If you are concerned about performance, I would look into using an framework such as AngularJS. You can inject modularized code. Even better, with MVC your view is bound to your model so by changing the model the view automatically updates itself.
Also, stop using class selectors. Use ID selectors. They are much faster. You also want to preload selectors (even with class selectors). That way you are only searching the DOM once:
var ele = $('#elementId');
$(ele).doSomething();
This way, you have a reference to the DOM element. You can use a datastructure to store all of your references outside of the global scope:
var elementReferences = {}; //declaration
elementReferences.mainPage = {}; //use
elementReferences.mainPage.root = $('#mainPage'); //load the root div of a page segment
elementReferences.mainPage.title = $(elementReferences.mainPage.root).children('#title'); //load the title
elementReference.mainPage.form = $(elementReferences.mainPage.root).children('#form'); //load the form
Now you can do this:
$(elementReference.mainPage.form).whatever();
and it doesn't have to search the DOM for the element. This is especially useful for larger apps.
If you put a function within document.ready, as per your fiddle, you are only able to access that function within the scope of the document.ready call. You really want to be able to load/unload functions as needed dynamically within the scope that they are required in, which is where angularjs comes into play.
You also, for the most part, want to remove your functions and variables from the global scope and put them into containers that are sorted by their dependencies and use. This is Object Oriented Programming 101. Instead of having a bunch of arrays sitting within the global scope where they could be overwritten by mistake by another developer, you want to put them within a container:
var arrays = {}; //create the object
arrays.whatever1 = [];
arrays.whatever2 = [];
Obviously, you will probably want a more descriptive name than "arrays". Functions work the same manner:
var ajax = {}; //ajax object
var ajax.get = function(){
};
var ajax.post = function(){
};
var ajax.delete = function(){
};
This generally promotes cleaner code that is more reusable and easier to maintain. You want to spend a good portion of your time writing a spec that fully documents the overall architecture before actually beginning development. NEVER jump the gun if you can help it. Spend time thoroughly researching and planning out the big picture and how everything fits together rather than trying to wing it and figure it out as you go. You spend less time having to reinvent the wheel when you do it this way.
It's developed by google, so it should be around for quite a while. I'm not sure if you are the guy in charge of your system's architecture, but if performance/reusability is an issue at your company it is definitely worth taking a look at. I'd be more than happy to give you a walkthrough regarding most of what I know in terms of software architecture and engineering. Just MSG me if you are interested. Always happy to help!
At the start of the source code for underscore.js, you see this:
var root = this;
var previousUnderscore = root._;
So the question becomes why didnt the author just write:
var previousUnderscore = this._;
Two reasons,
Readability, it makes it clearer what the code is doing, what it is referencing. this is very opaque.
depending on context, this can refer to lots and lots and lots of differnt objects, root may be used in multiple place and will always refer to the correct object.