Buggy JavaScript Code: The 10 Most Common Mistakes JavaScript Developers Make

View all articles

Today, JavaScript is at the core of virtually all modern web applications. The past several years in particular have witnessed the proliferation of a wide array of powerful JavaScript-based libraries and frameworks for single page application (SPA) development, graphics and animation, and even server-side JavaScript platforms. JavaScript has truly become ubiquitous in the world of web app development and is therefore an increasingly important skill to master.

At first blush, JavaScript may seem quite simple. And indeed, to build basic JavaScript functionality into a web page is a fairly straightforward task for any experienced software developer, even if they’re new to JavaScript. Yet the language is significantly more nuanced, powerful, and complex than one would initially be lead to believe. Indeed, many of JavaScript’s subtleties lead to a number of common problems that keep it from working – 10 of which we discuss here – that are important to be aware of and avoid in one’s quest to become a master JavaScript developer.

This developer's JavaScript is full of problems and mistakes.

Common Mistake #1: Incorrect references to this

I once heard a comedian say:

“I’m not really here, because what’s here, besides there, without the ‘t’?”

That joke in many ways characterizes the type of confusion that often exists for developers regarding JavaScript’s this keyword. I mean, is this really this, or is it something else entirely? Or is it undefined?

As JavaScript coding techniques and design patterns have become increasingly sophisticated over the years, there’s been a corresponding increase in the proliferation of self-referencing scopes within callbacks and closures, which are a fairly common source of “this/that confusion”.

Consider this example code snippet:

Game.prototype.restart = function () {
  this.clearLocalStorage();
  this.timer = setTimeout(function() {
    this.clearBoard();    // what is "this"?
  }, 0);
};

Executing the above code results in the following error:

Uncaught TypeError: undefined is not a function

Why?

It’s all about context. The reason you get the above error is because, when you invoke setTimeout(), you are actually invoking window.setTimeout(). As a result, the anonymous function being passed to setTimeout() is being defined in the context of the window object, which has no clearBoard() method.

A traditional, old-browser-compliant solution is to simply save your reference to this in a variable that can then be inherited by the closure; e.g.:

Game.prototype.restart = function () {
  this.clearLocalStorage();
  var self = this;   // save reference to 'this', while it's still this!
  this.timer = setTimeout(function(){
    self.clearBoard();    // oh OK, I do know who 'self' is!
  }, 0);
};

Alternatively, in newer browsers, you can use the bind() method to pass in the proper reference:

Game.prototype.restart = function () {
  this.clearLocalStorage();
  this.timer = setTimeout(this.reset.bind(this), 0);  // bind to 'this'
};

Game.prototype.reset = function(){
    this.clearBoard();    // ahhh, back in the context of the right 'this'!
};

Common Mistake #2: Thinking there is block-level scope

As discussed in our JavaScript Hiring Guide, a common source of confusion among JavaScript developers (and therefore a common source of bugs) is assuming that JavaScript creates a new scope for each code block. Although this is true in many other languages, it is not true in JavaScript. Consider, for example, the following code:

for (var i = 0; i < 10; i++) {
  /* ... */
}
console.log(i);  // what will this output?

If you guess that the console.log() call would either output undefined or throw an error, you guessed incorrectly. Believe it or not, it will output 10. Why?

In most other languages, the code above would lead to an error because the “life” (i.e., scope) of the variable i would be restricted to the for block. In JavaScript, though, this is not the case and the variable i remains in scope even after the for loop has completed, retaining its last value after exiting the loop. (This behavior is known, incidentally, as variable hoisting).

It is worth noting, though, that support for block-level scopes is making its way into JavaScript through the new let keyword. The let keyword is already available in JavaScript 1.7 and is slated to become an officially supported JavaScript keyword as of ECMAScript 6.

New to JavaScript? Read up on scopes, prototypes, and more.

Common Mistake #3: Creating memory leaks

Memory leaks are almost inevitable JavaScript problems if you’re not consciously coding to avoid them. There are numerous ways for them to occur, so we’ll just highlight a couple of their more common occurrences.

Memory Leak Example 1: Dangling references to defunct objects

Consider the following code:

var theThing = null;
var replaceThing = function () {
  var priorThing = theThing;  // hold on to the prior thing
  var unused = function () {
    // 'unused' is the only place where 'priorThing' is referenced,
    // but 'unused' never gets invoked
    if (priorThing) {
      console.log("hi");
    }
  };
  theThing = {
    longStr: new Array(1000000).join('*'),  // create a 1MB object
    someMethod: function () {
      console.log(someMessage);
    }
  };
};
setInterval(replaceThing, 1000);    // invoke `replaceThing' once every second

If you run the above code and monitor memory usage, you’ll find that you’ve got a massive memory leak, leaking a full megabyte per second! And even a manual GC doesn’t help. So it looks like we are leaking longStr every time replaceThing is called. But why?

Let’s examine things in more detail:

Each theThing object contains its own 1MB longStr object. Every second, when we call replaceThing, it holds on to a reference to the prior theThing object in priorThing. But we still wouldn’t think this would be a problem, since each time through, the previously referenced priorThing would be dereferenced (when priorThing is reset via priorThing = theThing;). And moreover, is only referenced in the main body of replaceThing and in the function unused which is, in fact, never used.

So again we’re left wondering why there is a memory leak here!?

To understand what’s going on, we need to better understand how things are working in JavaScript under the hood. The typical way that closures are implemented is that every function object has a link to a dictionary-style object representing its lexical scope. If both functions defined inside replaceThing actually used priorThing, it would be important that they both get the same object, even if priorThing gets assigned to over and over, so both functions share the same lexical environment. But as soon as a variable is used by any closure, it ends up in the lexical environment shared by all closures in that scope. And that little nuance is what leads to this gnarly memory leak. (More detail on this is available here.)

Memory Leak Example 2: Circular references

Consider this code fragment:

function addClickHandler(element) {
    element.click = function onClick(e) {
        alert("Clicked the " + element.nodeName)
    }
}

Here, onClick has a closure which keeps a reference to element (via element.nodeName). By also assigning onClick to element.click, the circular reference is created; i.e.: element -> onClick -> element -> onClick -> element

Interestingly, even if element is removed from the DOM, the circular self-reference above would prevent element and onClick from being collected, and hence, a memory leak.

Avoiding Memory Leaks: What you need to know

JavaScript’s memory management (and, in paticular, garbage collection) is largely based on the notion of object reachability.

The following objects are assumed to be reachable and are known as “roots”:

  • Objects referenced from anywhere in the current call stack (that is, all local variables and parameters in the functions currently being invoked, and all the variables in the closure scope)
  • All global variables

Objects are kept in memory at least as long as they are accessible from any of the roots through a reference, or a chain of references.

There is a Garbage Collector (GC) in the browser which cleans memory occupied by unreachable objects; i.e., objects will be removed from memory if and only if the GC believes that they are unreachable. Unfortunately, it’s fairly easy to end up with defunct “zombie” objects that are in fact no longer in use but that the GC still thinks are “reachable”.

Common Mistake #4: Confusion about equality

One of the conveniences in JavaScript is that it will automatically coerce any value being referenced in a boolean context to a boolean value. But there are cases where this can be as confusing as it is convenient. Some of the following, for example, have been known to bite many a JavaScript developer:

// All of these evaluate to 'true'!
console.log(false == '0');
console.log(null == undefined);
console.log(" \t\r\n" == 0);
console.log('' == 0);

// And these do too!
if ({}) // ...
if ([]) // ...

With regard to the last two, despite being empty (which might lead one to believe that they would evaluate to false), both {} and [] are in fact objects and any object will be coerced to a boolean value of true in JavaScript, consistent with the ECMA-262 specification.

As these examples demonstrate, the rules of type coercion can sometimes be clear as mud. Accordingly, unless type coercion is explicitly desired, it’s typically best to use === and !== (rather than == and !=), so as to avoid any unintended side-effects of type coercion. (== and != automatically perform type conversion when comparing two things, whereas === and !== do the same comparison without type conversion.)

And completely as a sidepoint – but since we’re talking about type coercion and comparisons – it’s worth mentioning that comparing NaN with anything (even NaN!) will always return false. You therefore cannot use the equality operators (==, ===, !=, !==) to determine whether a value is NaN or not. Instead, use the built-in global isNaN() function:

console.log(NaN == NaN);    // false
console.log(NaN === NaN);   // false
console.log(isNaN(NaN));    // true

Common Mistake #5: Inefficient DOM manipulation

JavaScript makes it relatively easy to manipulate the DOM (i.e., add, modify, and remove elements), but does nothing to promote doing so efficiently.

A common example is code that adds a series of DOM Elements one at a time. Adding a DOM element is an expensive operation. Code that adds multiple DOM elements consecutively is inefficient and likely not to work well.

One effective alternative when multiple DOM elements need to be added is to use document fragments instead, thereby improving both efficiency and performance.

For example:

var div = document.getElementsByTagName("my_div");

var fragment = document.createDocumentFragment();

for (var e = 0; e < elems.length; e++) {  // elems previously set to list of elements
    fragment.appendChild(elems[e]);
}
div.appendChild(fragment.cloneNode(true));

In addition to the inherently improved efficiency of this approach, creating attached DOM elements is expensive, whereas creating and modifying them while detached and then attaching them yields much better performance.

Common Mistake #6: Incorrect use of function definitions inside for loops

Consider this code:

var elements = document.getElementsByTagName('input');
var n = elements.length;    // assume we have 10 elements for this example
for (var i = 0; i < n; i++) {
    elements[i].onclick = function() {
        console.log("This is element #" + i);
    };
}

Based on the above code, if there were 10 input elements, clicking any of them would display “This is element #10”! This is because, by the time onclick is invoked for any of the elements, the above for loop will have completed and the value of i will already be 10 (for all of them).

Here’s how we can correct the above code problems, though, to achieve the desired behavior:

var elements = document.getElementsByTagName('input');
var n = elements.length;    // assume we have 10 elements for this example
var makeHandler = function(num) {  // outer function
     return function() {   // inner function
         console.log("This is element #" + num);
     };
};
for (var i = 0; i < n; i++) {
    elements[i].onclick = makeHandler(i+1);
}

In this revised version of the code, makeHandler is immediately executed each time we pass through the loop, each time receiving the then-current value of i+1 and binding it to a scoped num variable. The outer function returns the inner function (which also uses this scoped num variable) and the element’s onclick is set to that inner function. This ensures that each onclick receives and uses the proper i value (via the scoped num variable).

Common Mistake #7: Failure to properly leverage prototypal inheritance

A surprisingly high percentage of JavaScript developers fail to fully understand, and therefore to fully leverage, the features of prototypal inheritance.

Here’s a simple example. Consider this code:

BaseObject = function(name) {
    if(typeof name !== "undefined") {
        this.name = name;
    } else {
        this.name = 'default'
    }
};

Seems fairly straightforward. If you provide a name, use it, otherwise set the name to ‘default’; e.g.:

var firstObj = new BaseObject();
var secondObj = new BaseObject('unique');

console.log(firstObj.name);  // -> Results in 'default'
console.log(secondObj.name); // -> Results in 'unique'

But what if we were to do this:

delete secondObj.name;

We’d then get:

console.log(secondObj.name); // -> Results in 'undefined'

But wouldn’t it be nicer for this to revert to ‘default’? This can easily be done, if we modify the original code to leverage prototypal inheritance, as follows:

BaseObject = function (name) {
    if(typeof name !== "undefined") {
        this.name = name;
    }
};

BaseObject.prototype.name = 'default';

With this version, BaseObject inherits the name property from its prototype object, where it is set (by default) to 'default'. Thus, if the constructor is called without a name, the name will default to default. And similarly, if the name property is removed from an instance of BaseObject, the prototype chain will then be searched and the name property will be retrieved from the prototype object where its value is still 'default'. So now we get:

var thirdObj = new BaseObject('unique');
console.log(thirdObj.name);  // -> Results in 'unique'

delete thirdObj.name;
console.log(thirdObj.name);  // -> Results in 'default'

Common Mistake #8: Creating incorrect references to instance methods

Let’s define a simple object, and create and instance of it, as follows:

var MyObject = function() {}

MyObject.prototype.whoAmI = function() {
    console.log(this === window ? "window" : "MyObj");
};

var obj = new MyObject();

Now, for convenience, let’s create a reference to the whoAmI method, presumably so we can access it merely by whoAmI() rather than the longer obj.whoAmI():

var whoAmI = obj.whoAmI;

And just to be sure everything looks copacetic, let’s print out the value of our new whoAmI variable:

console.log(whoAmI);

Outputs:

function () {
    console.log(this === window ? "window" : "MyObj");
}

OK, cool. Looks fine.

But now, look at the difference when we invoke obj.whoAmI() vs. our convenience reference whoAmI():

obj.whoAmI();  // outputs "MyObj" (as expected)
whoAmI();      // outputs "window" (uh-oh!)

What went wrong?

The headfake here is that, when we did the assignment var whoAmI = obj.whoAmI;, the new variable whoAmI was being defined in the global namespace. As a result, its value of this is window, not the obj instance of MyObject!

Thus, if we really need to create a reference to an existing method of an object, we need to be sure to do it within that object’s namespace, to preserve the value of this. One way of doing this would be, for example, as follows:

var MyObject = function() {}

MyObject.prototype.whoAmI = function() {
    console.log(this === window ? "window" : "MyObj");
};

var obj = new MyObject();
obj.w = obj.whoAmI;   // still in the obj namespace

obj.whoAmI();  // outputs "MyObj" (as expected)
obj.w();       // outputs "MyObj" (as expected)

Common Mistake #9: Providing a string as the first argument to setTimeout or setInterval

For starters, let’s be clear on something here: Providing a string as the first argument to setTimeout or setInterval is not itself a mistake per se. It is perfectly legitimate JavaScript code. The issue here is more one of performance and efficiency. What is rarely explained is that, under the hood, if you pass in a string as the first argument to setTimeout or setInterval, it will be passed to the function constructor to be converted into a new function. This process can be slow and inefficient, and is rarely necessary.

The alternative to passing a string as the first argument to these methods is to instead pass in a function. Let’s take a look at an example.

Here, then, would be a fairly typical use of setInterval and setTimeout, passing a string as the first parameter:

setInterval("logTime()", 1000);
setTimeout("logMessage('" + msgValue + "')", 1000);

The better choice would be to pass in a function as the initial argument; e.g.:

setInterval(logTime, 1000);   // passing the logTime function to setInterval

setTimeout(function() {       // passing an anonymous function to setTimeout
    logMessage(msgValue);     // (msgValue is still accessible in this scope)
  }, 1000);

Common Mistake #10: Failure to use “strict mode”

As explained in our JavaScript Hiring Guide, “strict mode” (i.e., including 'use strict'; at the beginning of your JavaScript source files) is a way to voluntarily enforce stricter parsing and error handling on your JavaScript code at runtime, as well as making it more secure.

While, admittedly, failing to use strict mode is not a “mistake” per se, its use is increasingly being encouraged and its omission is increasingly becoming considered bad form.

Here are some key benefits of strict mode:

  • Makes debugging easier. Code errors that would otherwise have been ignored or would have failed silently will now generate errors or throw exceptions, alerting you sooner to problems in your code and directing you more quickly to their source.
  • Prevents accidental globals. Without strict mode, assigning a value to an undeclared variable automatically creates a global variable with that name. This is one of the most common errors in JavaScript. In strict mode, attempting to do so throws an error.
  • Eliminates this coercion. Without strict mode, a reference to a this value of null or undefined is automatically coerced to the global. This can cause many headfakes and pull-out-your-hair kind of bugs. In strict mode, referencing a a this value of null or undefined throws an error.
  • Disallows duplicate property names or parameter values. Strict mode throws an error when it detects a duplicate named property in an object (e.g., var object = {foo: "bar", foo: "baz"};) or a duplicate named argument for a function (e.g., function foo(val1, val2, val1){}), thereby catching what is almost certainly a bug in your code that you might otherwise have wasted lots of time tracking down.
  • Makes eval() safer. There are some differences in the way eval() behaves in strict mode and in non-strict mode. Most significantly, in strict mode, variables and functions declared inside of an eval() statement are not created in the containing scope (they are created in the containing scope in non-strict mode, which can also be a common source of problems).
  • Throws error on invalid usage of delete. The delete operator (used to remove properties from objects) cannot be used on non-configurable properties of the object. Non-strict code will fail silently when an attempt is made to delete a non-configurable property, whereas strict mode will throw an error in such a case.

Wrap-up

As is true with any technology, the better you understand why and how JavaScript works and doesn’t work, the more solid your code will be and the more you’ll be able to effectively harness to true power of the language. Conversely, lack of proper understanding of JavaScript paradigms and concepts is indeed where many JavaScript problems lie.

Thoroughly familiarizing yourself with the language’s nuances and subtleties is the most effective strategy for improving your proficiency and increasing your productivity. Avoiding many common JavaScript mistakes will help when your JavaScript is not working.

About the author

Ryan J. Peterson, United States
member since June 18, 2013
Ryan is a top architect, entrepreneur, and developer. He boasts a proven competency in building cloud-scalable, extensible software and systems. He writes code that can be maintained and expanded over time as business systems and requirements adapt to market demands or pivots in core business direction. [click to continue...]
Hiring? Meet the Top 10 Freelance JavaScript Developers for Hire in August 2016

Comments

boriscy
Great article #7 was the best.
saitodisse
Good post. Alternatively, on mistake #8, you can use: var whoAmI = obj.whoAmI.bind(obj); whoAmI(); // outputs "MyObj" (as expected)
hasanyasin
Great article. I will make a few little additions, mostly considering people who are relatively new at JavaScript. For #2, example 2, it may be useful mentioning to avoid use of `element` inside the function, they can access the element using function arguments and `this` instead. For #6: IMHO, it is not a good practice to create closures for elements this way. This is given as an example so many times online that I guess, anybody trying to learn JavaScript will pick this up as a pattern. I do this on a set of elements which I am sure that will be very limited in numbers. In other cases, I prefer adding attributes to DOM objects themselves and then reaching it from inside the event handler.. For #8: I guess at the end of the section, it would be useful to add use of `bind` to do this. Given example shows only the problem; but not really guides us how to do things: I already have obj.method and it really doesn't matter if I have obj.method_shortcut. I saw many developers trying to have a shortcut for console.log and then quitting when they see that; `log = console.log` doesn't work as they expected. It is easy to have a shortcut for console.log, though: `log = console.log.bind(console)` Then you can use log() as a shortcut. This is just nice especially when dirty-debugging using console instead of debuggers. Another place where you want a shortcut is using `hasOwnProperty` method of `Object` prototype. You can have your shortcut, let's say `hasprop` like this; ``` hasprop = Function.call.bind(Object.prototype.hasOwnProperty) ``` I love `bind`. It makes me feel like I am almost in Haskel :p //partial application. Haskel: ``` add a b = a + b add5 = add 5 ``` JavaScript: ``` function add(a,b) { return a+b } var add5 = add.bind(null, 5); ``` Awesome, isn't it? Just to keep in mind that first parameter to bind is `this` inside the function body so second parameter to `bind` becomes the first parameter to your function. If you give `null` as the first argument to `bind` then it won't set `this` for the function. As a side note, `this` was used to refer to global object (`window` in browser) when a function is called with `null` for `this`; but in strict mode, this behavior has changed and `this` will be `null` if you call it with `null` using bind/call/apply functions.
ajaniashish
Really nice article and mistakes you mentioned in this post are often made by programmers, but most common mistakes in my view are #1 and #3, often when I review the code of my team members I see these two mistakes made and they are completely unaware of it. Thank you for sharing such nice article.
Tamm
Cool article!
sebastianteres
Great Post! I would recommend going through Mozilla's Javascript guide (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/About) It covers most of the topics discussed here. Its a great starting point for javascript developers.
brianm101
Nice article - just missing the Common mistake # 0 Using javascript in the first place! If you wanted a language that would make for horrible code, difficult maintenance and ease of bug creation javascript has it all! JavaScript was never meant to do what it does today, every new feature just makes the language worse and more complicated to use. Unfortunately it's something every successful language suffers from c++ has similar problems. Everything has to be backwards compatible, so things never get simpler only more complicated. As javascript is used in sites that might never be maintained it ain't never going to go away. Articles like this are great but they only scratch the surface of the things done in the name of JavaScript!
Melad Dabbous
Good article. I learned a lot from it.
Ryan J. Peterson
I agree that #6 should have been something that wasn't a DOM element. I think the reason it is used online so much is `onclick` is one of the functions that people are first introduced too. My focus was more on the closure not being inside of the loop than it being on the DOM event. I had in one draft of this mentioned bind but edited it out for sake of readability, this post really could be extended even more than it is but then what would be left to discuss in the comments. Thanks for adding value here in the comments though, hopefully learners will read the comments as well.
Ryan J. Peterson
This is a great recommendation, I reference this guide often when looking up something I can't remember or want to make sure I am correct on.
Ryan J. Peterson
It is the same situation with comments that don't add value to exercises in learning. Frankly, JavaScript isn't going to go away anytime soon. With the ECMA 6 and v8 revolution, it is at least being improved upon. To say "JavaScript was never meant to do what it does today..." ignores that by breaking the intent of technology, we have seen advancements such as the internet, which has broken out of the intent for better communication into a multitude of possibilities. While I value your opinion, I still feel like blanket flame comments about JavaScript, Ruby, PHP or any other language creates an unnecessary division between what is a subjective decision of programming language and environment typically not made by us writing the code. In the future, I would appreciate comments aiming to be constructive. Thank you.
brianm101
Sorry you didn't get the light hearted nature of the comment or the point being made! JavaScript is one of my working languages as is C++ so it's hardly going to be a flame on those languages. The comment is constructive and appropriate on an article regarding common mistakes, if the language was better then the problems would be fewer! What would be great is a ' use superstrict' that brings in strict type checking and real oops programming, removes some of the less desirable features, perhaps for a future version - I can dream!
Ryan J. Peterson
My bad. I have been dealing with negative log trolls lately and the humor was lost on me. Yes, a future version is where we can rest our hopes and dreams.
Sushil Kumar
Really a nice article.. These are the common mistakes novice programmers, like me, make. Specially the #1 and #2
Mobile Pundits
Most of the time when the project deadline is near and due to this In the hurry of development and releasing most of the people don't pay attention over all these java script mistakes. You shared a nice and informative post. I recommended. <a href="http://www.mobilepundits.com/PhoneGap_Development.html">Phonegap mobile app development</a>
Vladimir Grichina
Equality in JS is so confusing that you also have made a mistake when describing mistake #4 :) <code>isNaN</code> won't really check if value is NaN, some examples: <pre><code> isNaN("foo") == true // this string cannot be converted to number isNaN("123") == false // string can be converted to number isNaN([1, 2])) == false isNaN([1, 2]) == true </code></pre> To check if value <code>x</code> is NaN you have to compare it to itself, i.e.: <pre><code> function isReallyNaN(x) { return x != x; } isReallyNaN(1) == false isReallyNaN(NaN) == true </code></pre>
Sergey Batishchev
Great article. Can you clarify though exact extent of the problem here: "Interestingly, even if element is removed from the DOM, the circular self-reference above would prevent element and onClick from being collected, and hence, a memory leak." I was under impression that DOM-JS type circular references leaks were only an issues for IE7 and below (due to the separate handling of GC for DOM and JS object if I recall it right). Because, really, circular references are not an issue for GC, as long as objects in a "loop" are not reachable from the outside. Or I am missing something in your example that in fact holds one of the objects from the outside?
Kostas
An alternative for #6 using IIFE... var elements = document.getElementsByTagName('input'); var n = elements.length; for (var i = 0; i < n; i++) { ( function( num ){ elements[i].onclick = function() { console.log( "This is element #" + ( num+1 ) ); }; }( i ) ); }
Guest
Memory Leak Example #1 seems to be not valid. There is no memory leak there. Each time function replaceThing() is executed priorThing set to undefined first and then get ref to theThing so it take 1mb of memory each time and no mem leaks.
iknowbest
Just came across this one today: var x = 12; var y=10; var out = (y==10 && x); console.log(out) // outputs '12' and not true or false; would love an explanation if anyone has one.
Anon
JavaScript has more than "true" and "false" truthy/falsy values, and will return the "last value" for |, ||, &, and && operators. http://en.wikipedia.org/wiki/Short-circuit_evaluation JavaScript developers may use this to their advantage: // without using last value function(name) { if (name) { return name; } return "Candy"; } // using last value function(name) { return name || "Candy"; // if name is "truthy", we stop evaluation and return it. //Otherwise we evaluate RHS and return "candy" }
cintalauraramarimari
JavaScript is very important for modern web applications, let's say <a href="http://obatkeputihanonline.com/">obat keputihan gatal berbau</a> to the health of women
Ben Randles-Dunkley
You mean AS3? ;)
Terry Marr
Great post! Beginners need concrete examples of good and bad code to learn from. You did this nicely, especially with #3 memory leak example 1. However, in example 2, the circular reference example, it would be nice to see the fixed version of the code. Can you edit to provide that too?
Ali
Will never understand one thing. If its such an illogical language(which it is) with so many blunders then why are people still using it?
javinievas
You forgot to mention the trailing comma issue. I've seen it a lot. dict = {"a":1, "b":2, }
Robert Jackson
TOPAL... has a person send me an email asking me to set up a time for interview. Times offered were between 2 am and 8 am. I send an email back saying that is insane. I get told I will hear from someone else who can be in my time zone. I never hear back.. Where the hell is toptal located????????????????????? Thanks for a new idea for a new website. How about trying to have people in the country who are awake at the time of interviews and calls before pretending to be a real company??????????????????????
Norbert
No need for IIFE here, use a Array Prototype method like .forEach. Saves many keystrokes and make the code easier to reason about and read. Converting the nodeList to an Array first is important though, but that's easy too! Array.from(document.getElementsByTagName('input')).forEach(function (item, index) { item.addEventListener('click', function (event) { console.log("This is element #" + index); }); }); As you can see, there's no need for variables, that just hang around and cannot be GC'd. Working example: http://jsbin.com/bexohageje/edit?html,js,console
Kostas
Neat! Although, I think for the time being, Array.prototype.from needs a polyfill to work across all browsers.
Norbert
Correct, but polyfills are A-OK with me. <pre><code> Polyfill is super easy too: Array.from = Array.from || function (thing) { return [].splice.call(thing); }; </code></pre> working example: http://jsbin.com/nuxucirudo/edit?html,js,console
Norbert
> It's implemented in every browser in use. > All computers come with browsers by default. > Browsers are pretty much required for doing anything online. > It's actually a very dynamic expressive and powerful language. > No other programming language is enabled in browser by default. But fear not! If you don't like javascript, you don't have to use it! You can transpile/compile to javascript from many languages you might like. TypeScript, Ruby, C, Scala just to name a few. With asm.js support, the code these tools generate can actually be really fast. Just hope they come with a good debugger, because otherwise you're &^*%ed.
Norbert
I'm very confused by this as well, So this is broken, because of reasons the article explains: <pre><code> function addClickHandler(element) { element.click = function onClick(e) { alert("Clicked the " + element.nodeName) } } </code></pre> Perhaps we can try to do away with the 'element' reference like this: <pre><code> var addClickHandler = function (element) { element.addEventListener('click', function (event) { alert("Clicked the " + event.currentTarget.nodeName) }); }; </code></pre> Working example: http://jsbin.com/becamexive/edit?html,js,output NOTE: I had to edit the authors code, because it wasn't working/doing anything/the thing that was intended.
Norbert
<pre><code> var out = (doThis && doThat && returnThisThing) </code></pre> doThis is attempted, if it returns a truthy value the next thing it attempted, etc. until the last thing in the sequence and that is whatever is actually returned from the expression. Javascript considers 0, null, undefined, '' as falsy and everything else is considered truthy. I personally would have liked an empty array to have been falsy, but Ey, can't have it all I guess.
Norbert
You may investigate transpiling/compiling to javascript from whatever language you DO like. You can write stinky code in any language though, but it's easier in some then in others. Yes it's very easy to make errors in Javascript, doesn't mean there's absolutely no beauty there and we should get rid of all of it, though. Personally I don't agree that another 'mode' in javascript would be an improvement. TC39 seems to be in agreement on that most of the time. Exactly what additions in ES5 and ES6 (besides classes) do you actually think make the language worse? I genuinely am curious why you think the language is evolving in a bad way. Kind regards, no flame intended
brianm101
Strangely enough think a lot of the new features actually make JavaScript better (!), go strict and it gets even better. The trouble is the larger you grow a languages surface area then the harder it becomes to learn and use correctly, more the chance for errors and undefined behaviour. A language that needs '===' as well as '==' really has a problem! You are definitely correct in that transpiling/compiling to JavaScript would be a way to go. Compilers don't have fragility (or egos!) of us human programers. So maybe a compiled sub set of the language which is 'modern' that removes all the ambiguities and baggage of JavaScript is the way to go?
bdiscus
forEach is a great solution to many things, but it has it's drawbacks. It's very slow compared to a simple cached for loop, as it constitutes a function call for each iteration which is pretty expensive. So if you were going to process a big deal of elements you should use a simple cached for loop, if not then forEach would be ok. Performance comparisons here (forEach 73% slower for me, Chrome): https://jsperf.com/for-vs-foreach/37
BeGe1
#8 is incorrect. It states that the reason is that the variable declaration pointing to the function is <strong>created</strong> in the global scope. This is incorrect. The "this" keyword is a matter of dynamic scope, not lexical. It's <em>not</em> about where the variable pointing to the function is declared, <strong>it's about how it's called</strong>. The reason the first one outputs "MyObj" is because it's called as an object property, so that object becomes the "this" keyword. The second one is called <em>not</em> as an object property, so its "this" keyword is whatever the default "this" is (in this case the global object window since it's not in strict mode). Proof of that is this code, add it to the end of the code you were doing: <pre>(function myFunc(){ var whoAmI2 = whoAmI; whoAmI2(); // outputs "window", even though was "declared" in a function })();</pre> Why does it do that? Again...because it's about how it's called, not where it's declared. Just like <code>whoAmI</code>, <code>whoAmI2</code> is called NOT as a property on an object, so (not in strict mode) it ends up with the "this" keyword meaning the global object (i.e. window). So they give the same answer even though the variables referencing the function were declared in 2 different scopes.
James Edward Lewis
NaN is also falsy, and curiously, the first versions of JavaScript had new Boolean(false) being falsy too.
James Edward Lewis
I also understand that old versions of IE (again, IE7-) used reference-counting rather than mark-and-sweep, so that reference cycles that were not actually reachable from global code or the current call stack would not be freed, even if only native JS objects were involved.
James Edward Lewis
That just might become a reality with the 'use strong' proposal, now implemented in V8.
James Edward Lewis
The example at the end of #1 should be rewritten to get at the heart of the matter: Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(this.reset.bind(this), 0); // bind to 'this' }; Game.prototype.reset = function(){ this.clearBoard(); // ahhh, back in the context of the right 'this'! }; This could be rewritten as Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(this.clearBoard.bind(this), 0); // bind to 'this' }; It would still show an example where bind would help, because this.clearBoard by itself, when passed as an argument to a function, is resolved before invocation, and when invoked has the same context as an ordinary function, which is a problem if Game.prototype.clearBoard also refers to this inside its own code. The difference is that in the example as written, leaving off bind would lead to a known error, that window.clearBoard is not a function, while in my rewritten example, this.clearBoard might not throw an error but would instead create and affect global variables, rather than members of the instance you extracted the method from.
Sergey Batishchev
Nope. Luckily this leak only applied to DOM-JS circular links (which were at the time modelled with COM): https://msdn.microsoft.com/en-us/library/dd361842%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
brianm101
Hopefully! :)
MikeL
Like the others have said, logical operators in Javascript takes advantage of the fact that JS has the concept of truthy and falsy to return the actual values (since they're all either truthy or falsy) rather than an actual boolean. That's why it's so common to see expressions like: !!x (double negation) which converts any value into an actual boolean. It's frequently used because developers like real booleans even though it's rarely necessary in JS.
MikeL
On #9, I think you (almost) left out the most significant problem with passing a string to the setTimeout function: If you pass a function, that function will be invoked in the scope it was defined in (the same as the call to setTimeout if it's an anonymous function as in your example) but if you pass a string at will be parsed into a function and invoked in the global scope. You hint at this problem with the msgValue variable but I think it's the main argument against passing a function body as a string. Doing that wouldn't even be possible if msgValue was anything non-serializable.
englishextra
Very nice. Especially on strict mode.
Michael Simkin
Yeh! I was surprised too.
Michel H.
Good post! Thanks!
rameramwe
i love you .. you're awesome this line saved my life var self = this ;
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering and design posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant technologies
About the author
Ryan J. Peterson
Ruby Developer
Ryan is a top architect, entrepreneur, and developer. He boasts a proven competency in building cloud-scalable, extensible software and systems. He writes code that can be maintained and expanded over time as business systems and requirements adapt to market demands or pivots in core business direction.