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.
Related
I ask because I'm writing an Angular directive requiring me to reference the parent and grandparent element. This means I end up with long names for something like the 'grand parents' innerheight. Something like:
var grandParentInnerHeight = $grandParent.innerHeight();
A friend suggested using nth to name these, but using numbers also seems wrong when it comes to naming variables.
And I know some people might suggest to restructure my code so I don't need the grand parent, but in this case its necessary.
Any ideas?
I've seen people use abbreviations like
var gpInnerHeight = foo;
or
var grandPInnerHeight = foo;
But personally, I find no problem in writing the full name of a variable. It makes it clear to understand, but just takes a couple more ms to write it.
Also, for JQuery, I've seen some people who want to distinguish between JavaScript variables and JQuery variables by putting a $ in front of them like this.
var $grandParentInnerHeight = foo.innerHeight();
Here's a website that goes over some naming conventions that I see as useful.
Click me
I'm looking at Addy Osmani's gist for a publication/subscription pattern here:
https://github.com/addyosmani/pubsubz/blob/master/pubsubz.js
He surfaces his object as a global like this:
;(function ( window, doc, undef ) {
var topics = {},
subUid = -1,
pubsubz ={};
....
getPubSubz = function(){
return pubsubz;
};
window.pubsubz = getPubSubz();
What is the value of creating that getPubSubz function? Wouldn't it be more straightforward to simply write:
window.pubsubz = pubsubz;
Yes, in this case, because getPubSubz is only called in one place, immediately after declaring it, it could safely be inlined.
It's hard to say exactly what the author had in mind, but in a growing code base there may be some value to having a "getter" function which could be modified if the act of getting the pubsubz object required more advanced logic.
It absolutely would be.
There are only two potential reasons why a getter would be used in this case:
There was previously some additional code inside the getter (logging, perhaps)
Addy Osmani's just following good practice*, and including a getter—even adding the opportunity to add additonal code in the future.
Through the power of GitHub, we can actually eliminate option one, as the getter was added in its current state—so I think we can conclusively say that it's just a matter of good practice here.
*as jantimon alludes to in the comments below, this isn't particularly advantageous in most cases (including this one) and this code does not necessarily need to followed as an example.
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"
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!
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");