sorry for noobie question. Can you explain please, what is the difference between:
1. var a = [];
a['b'] = 1;
2. var a = {};
a['b'] = 1;
I could not find article in the internet so wrote here.
Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.
Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.
Lost your password? Please enter your email address. You will receive a link and will create a new password via email.
Please briefly explain why you feel this question should be reported.
Please briefly explain why you feel this answer should be reported.
Please briefly explain why you feel this user should be reported.
Literals
The
[]and{}are called the array and object literals respectively.var x = []is short forvar x = new Array();and
var y = {}is short forvar y = new Object();Arrays
Arrays are structures with a length property. You can access values via their numeric index.
And if you want to list all the properties you do:
Performance tricks and gotchas
1. Inner-caching the length property
The standard array iteration:
Little known fact: In the above scenario, the
arr.lengthproperty is read at every step of the for loop. Just like any function you call there:This decreases performance for no reason. Inner caching to the rescue:
Here’s proof of the above.
2. Don’t specify the Array length in the constructor.
Test cases for array definition are available here.
3. Avoid using Array.prototype.push(arr.push)
If you are dealing with large collections, direct assignment is faster than using the
Array.prototype.push();method.myArray[i] = 0;is faster thanmyArray.push(0);, according to jsPerf.com test cases.4. It is wrong to use arrays for associative assignments.
The only reason why it works is because
Arrayextends theObjectclass inside the core of the JS language. You can just as well use aDate();orRegEx();object for instance. It won’t make a difference.x['property'] = someValueMUST always be used with Objects.Arrays should only have numeric indexes. SEE THIS, the Google JS development guidelines! Avoid
for (x in arr)loops orarr['key'] = 5;.This can be easily backed up, look HERE for an example.
will output:
[object Array]This reveals the core language’s ‘class’ inheritance pattern.
will output
[object String].5. Getting the minimum and maximum from an array.
A little known, but really powerful trick:
, respectively:
Objects
With an object you can only do:
var y = {}orvar y = new Object();y['first'] = 'firstValue'is the same asy.first = 'firstValue', which you can’t do with an array. Objects are designed for associative access withStringkeys.And the iteration is something like this:
Performance tricks and gotchas
1. Checking if an object has a property.
Most people use
Object.prototype.hasOwnProperty. Unfortunately that often gives erroneous results leading to unexpected bugs.Here’s a good way to do it:
2. Replacing switch statements.
One of the simple but efficient JS tricks is
switchreplacement.In most JS engines the above is painfully slow. When you are looking at three possible outcomes, it doesn’t make a difference, but what if you had tens or hundreds?
The above can easily be replaced with an object. Don’t add the trailing
(), this is not executing the functions, but simply storing references to them:Instead of the
switch:3. Deep-cloning made easy.
HERE is the deep clone function in action.
Auto-boxing
As a dynamically typed language, JavaScript is limited in terms of native object types:
What’s the catch? There is a strong distinction between primitive and non-primitive objects.
They do the same thing, you can call all string methods on
sands2.Yet:
You may hear in JS everything is an
object. That’s not exactly true, although it’s a really easy mistake to make.In reality there are 2 types, primitives and objects, and when you call
s.indexOf("c"), the JS engine will automatically convertsto its non-primitive wrapper type, in this caseobject String, where all the methods are defined on theString.prototype.This is called
auto-boxing. TheObject.prototype.valueOf(obj)method is a way to force the cast from primitive to non-primitive. It’s the same behaviour a language like Java introduces for many of it’s own primitives, specifically the pairs:int– Integer,double– Double,float– Float, etc.Why should you care?
Simple:
So if
s2was created withvar s2 = new String("test")you are getting a false negative, even for an otherwise conceivably simple type check. More complex objects also bring with themselves a heavy performance penalty.A micro-optimization as some would say, but the results are truly remarkable, even for extremely simple things such as string initialisation. Let’s compare the following two in terms of performance:
and
You will probably expected matching performance across the board, but rather surprisingly the latter statement using
new Stringis 92% slower than the first one, as proven here.Functions
1. Default parameters
The
||operator is the simplest possible way of defaulting. Why does it work? Because of truthy and falsy values.When evaluated in a logical condition,
undefinedandnullvalues will autocast tofalse.A simple example(code HERE):
2. OO JS
The most important thing to understand is that the JavaScript
thisobject is not immutable. It is simply a reference that can be changed with great ease.In OO JS, we rely on the
newkeyword to guarantee implicit scope in all members of a JS Class. Even so, you can easily change the scope, viaFunction.prototype.callandFunction.prototype.apply.Another very important thing is the
Object.prototype. Non-primitive values nested on an objects prototype are shared, while primitive ones are not.Code with examples HERE.
A simple class definition:
A simple size class, with two members,
this.widthandthis.height.In a class definition, whatever has
thisin front of it, will create a new reference for every instance of Size.Adding methods to classes and why the “closure” pattern and other “fancy name pattern” are pure fiction
This is perhaps where the most malicious JavaScript anti-patterns are found.
We can add a method to our
Sizeclass in two ways.Or:
The
areamethod ofSize2is created for every instance.This is completely useless and slow, A LOT slower. 89% to be exact. Look HERE.
The above statement is valid for about 99% of all known “fancy name pattern”. Remember the single most important thing in JS, all those are nothing more than fiction.
There are strong architectural arguments that can be made, mostly revolved around data encapsulation and the usage of closures.
Such things are unfortunately absolutely worthless in JavaScript, the performance loss simply isn’t worth it. We are talking about 90% and above, it’s anything but negligible.
3. Limitations
Because
prototypedefinitions are shared among all instances of a class, you won’t be able to put a non-primitive settings object there.Why?
size.settingswill be the same for every single instance.So what’s with the primitives?
The point:
The average JS guy will write JS in the following way:
Which is fine (fine = poor quality, hard to maintain code), as long as you understand that is a
Singletonobject, and those functions should only be used in global scope without referencingthisinside them.But then it gets to absolutely terrible code:
You could have gotten away with:
var x = new Size(10, 5); var y = new Size(15, 5);.Takes longer to type, you need to type the same thing every time. And again, it’s A LOT SLOWER. Look HERE.
Poor standards throughout
This can be seen almost anywhere:
Again with the alternative:
The point: USE CLASSES WHEREVER APPROPRIATE!!
Why? Example 1 is 93% Slower. Look HERE.
The examples here are trivial, but they illustrate something being ignored in JS, OO.
It’s a solid rule of thumb not to employ people who think JS doesn’t have classes and to get jobs from recruiters talking about “Object Orientated” JS.
Closures
A lot of people prefer them to the above because it gives them a sense of data encapsulation. Besides the drastic 90% performance drop, here’s something equally easy to overlook. Memory leaks.
You’ve just created a closure for
someParam. Why is this bad? First, it forces you to define class methods as instance properties, resulting in the big performance drop.Second, it eats up memory, because a closure will never get dereferenced. Look here for proof. Sure, you do get some fake data encapsulation, but you use three times the memory with a 90% performance drop.
Or you can add
@privateand get a way with an underscore function name.Other very common ways of generating closures:
paramis now a closure! How do you get rid of it? There are various tricks, some found here. The best possible approach, albeit more rigorous is to avoid using anonymous functions all-together, but this would require a way to specify scopes for event callbacks.Such a mechanism is only available in Google Closure, as far as I know.
The singleton pattern
Ok, so what do I do for singletons? I don’t want to store random references. Here’s a wonderful idea shamelessly stolen from Google Closure’s base.js
It’s Java-esque, but it’s a simple and powerful trick. You can now do:
How is this useful? Simple. In all other files, every time you need to reference
project.some.namespace.StateManager, you can write:project.some.namespace.StateManager.getInstance(). This is more awesome than it looks.You can have global state with the benefits of a class definition (inheritance, stateful members, etc.) and without polluting the global namespace.
The single instance pattern
You may now be tempted to do this:
That is another big no-no in JavaScript. Remember, the
thisobject is only guaranteed to be immutable when thenewkeyword is used. The magic behind the above code is interesting.thisis actually the global scope, so without meaning to you are adding methods to the global object. And you guessed it, those things never get garbage collected.There is nothing telling JavaScript to use something else. A
functionon it’s own doesn’t have a scope. Be really careful what you do withstaticproperties. To reproduce a quote I once read, the JavaScript global object is like a public toilet. Sometimes you have no choice but to go there, yet try and minimise contact with the surfaces as much as possible.Either stick to the above
Singletonpattern or use a settings object nested under a namespace.Garbage collection in JavaScript
JavaScript is a garbage collected language, but JavaScript GC is often rather poorly understood. The point is again speed. This is perhaps all too familiar.
That is bad, poor performance code. The reason is simple. JS will garbage collect a variable and free up the heap memory it holds only when that variable gets de-scoped, e.g. there are no references to it anywhere in the memory.
For example:
Three things:
Why?
Because they no longer belong to the “current” scope. They are created, used, and destroyed. There are no closures either, so all the memory you’ve used is freed up through garbage collection.
For that reason, you should never, your JS files should never look like this, as global scope will just keep polluting memory.
Alright, now what?
Namespaces.
JS doesn’t have namespaces per say, so this isn’t exactly a Java equivalent, yet from a codebase administration perspective you get what you want.
Beautiful. One global variable. Proper project structure.
With a build phase, you can split your project across files, and get a proper dev environment.
There’s no limit to what you can achieve from here.
Count your libraries
Having had the pleasure of working on countless codebases, the last and most important argument is to be very mindful of your code dependencies. I’ve seen programmers casually adding jQuery into the mix of the stack for a simple animation effect and so forth.
Dependency and package management is something the JavaScript world hadn’t addresses for the longest time, until the creation of tools like Bower. Browsers are still somewhat slow, and even when they’re fast, internet connections are slow.
In the world of Google for instance, they go through the lengths of writing entire compilers just to save bytes, and that approach is in many ways the right mentality to have in web programming. And I uphold Google in very high regard as their JS library powers apps like Google Maps, which are not only insanely complex, but also work everywhere.
Arguably JavaScript has an immense variety of tools available, given its popularity, accessibility, and to some extent very low quality bar the ecosystem as a whole is willing to accept.
For Hacker News subscribers, a day doesn’t go by without a new JS library out there, and they are certainly useful but one cannot ignore the fact that many of them re-implement the exact same concerns without any strong notion of novelty or any killer ideas and improvements.
It’s a strong rule of thumb to resist the urge of mixing in all the new toys before they have the time to prove their novelty and usefulness to the entire ecosystem and to strongly distinguish between Sunday coding fun and production deployments.
If your
<head></head>tag is longer than this post, you’re doing it all wrong.Testing your knowledge of JavaScript
A few “perfectionist” level tests:
http://perfectionkills.com/javascript-quiz/, thanks to Kangax.
http://javascript-puzzlers.herokuapp.com/