Rechkunov Denis
Knowledge of JavaScript programming language is becoming more necessary due to the development of web technologies. AJAX technology, template engines on the client, development of HTML5 standard with new API for JavaScript, appearance of node.js as a server platform on JavaScript – all this contributes to JavaScript promotion in the software development industry. Although there are many languages that could be compiled in JavaScript, the most part of developers still prefer to use JavaScript itself because of the simplicity in debugging and external similarity to the already known to them programming languages.
JavaScript programming language was created in a hurry and therefore some things in it can be considered not entirely thought-out or even wrong, for example, there are many articles with examples of unexpected problems with dynamic typing. External similarity of the language with other languages such as Java can play some evil trick with beginning JavaScript developer and increase barrier to entry into the language, if the beginner won’t be instructed on time about known problems and features of the language. As an example of such instruction in this article a review of typical errors is given using JavaScript language.
Scope
The first and, probably, the main difference of JavaScript language from others is a scope of variables, which is defined here by function, not a block of code. Hence there is a classic error with redefining of the variable in the cycle.
Typical error with variable of the cycleThe example shows: first key variable is defined and assigned some value. Then in the cycle variable with the same name is defined, but the cycle doesn’t define its scope of variables and overlaps defined earlier key variable, and when developer will decide to use key value after the cycle, he will receive a name of the last property of obj object.
Also another important problem is global variables. As in any other programming language, in JavaScript using of global variables is strictly not recommended due to obvious reasons, and when you define variables, not putting them into any function, they will always be global, that is they will become properties in your host object (in browser this is window, in node.js this is process and etc.). Another way to define a global variable by chance is to declare it without the keyword “var”, so be very careful that all you variables have been defined using “var”.
How to avoid global variables? The answer is simple, you should put your module into the function, for which there is a known approach – using of “Immediate Function”.
Using of Immediate FunctionThe approach itself means defining of function with the code of your module and its call after defining. In this case all that you need to pass from global scope is better to pass by call parameters in order to avoid creating of extra closures, which bring overhead costs, also passing in parameters “value” data types such as numbers and strings in JavaScript occurs with copying that will protect from unnecessary data changes by other libraries or modules.
Undeclared and Undefined
In JavaScript there is one nuance in accessing undefined variables and object properties. Often beginning developers see that reading of undefined object’s property only returns undefined and doesn’t cause any errors and appears a misconception that this also happens with undefined local variables that is not true at all. If you will try to access non-existent variable, then you will get ReferenceError exception as shown in the example below.
Difference between Undeclared and Undefined
Hoisting
Hoisting or variable raising effect is one of the most unobvious features of the language, it works the following way: no matter where you defined a variable inside the function, even before return, it will be defined as if you have done this at the very beginning of the function, however, first it will have undefined value until later in the code it won’t be assigned a value. The example shows a typical error caused by hoisting effect.
Error is caused by variable raising effectThere is a practice that helps to avoid such problems – to define variables at the beginning of the function independently that hoisting will become obvious that shows an example below. However, it is believed that this is contrary to the rule which states that variables should be defined as close as possible to their point of using. Here you will have to decide by yourself what you think is more important in this situation.
Example for avoiding problems with Hoisting
Insidious “this” link
Perhaps the most common source of errors for JavaScript developers is “this”. The fact is that “this” in JavaScript despite the same name as in Java or other languages executes quite another function. “This” link points to the object, in which at the current moment the code is executed and not the one in which you will write this keyword. So if you use “this” in callback passed in the object method, then it will point to the object that owns the method, not the one where you defined callback. The same applies to the event handlers in browser (onclick, onload and etc.), in them this will point to DOM element, in which the event occurred. Hence there is another common mistake – using of “this” in callbacks or event handlers. The example below illustrates the problem.
Problem with “this” in callbackTo solve this problem there are two common approaches. The first one works even in the oldest browsers without additional means – this is saving of “this” value in variable and using of this variable in callback via closure as shows an example below.
Solution using “this” savingThe second approach works in rather new browsers without additional means, and in old it can be implemented by defining of one function, how to do this you can read here https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind. In new JavaScript versions there is already built-in solution of the problem, this is bind() method for each function, in which you can pass the object, in the context of which you want to call the function in the future. Additionally you can then list the parameters, which will always come before passed parameters when calling, so to get so-called mechanism of partial application. You should keep in mind that bind() doesn’t change the function itself, but returns a wrapper over it for calling in the object context.
Using of bind()
Asynchronous calls in cycles
Cycle variable in JavaScript is just a variable, in which at each iteration the next value of object property is assigned. Based on this using of it inside cycle iteration in asynchronous calls is unsafe. When your asynchronous call will work, the cycle variable will already have a value equal to the name of the last object property, not the one that was when calling in iteration.
Example of error with asynchronous call in cycleIf you have a compelling need to use a value of cycle variable asynchronously, you can solve this task using Immediate Function, as shown in the example below.
How you can use cycle variable asynchronouslyAs was mentioned, in JavaScript “value” type variables are passed with copying of value, therefore by creating scope and passing there cycle variable you will get its value in scope and not a reference to variable.
Cycles
In JavaScript the cycles are not so simple. The fact is that JavaScript code, which is written by developer, is executed in one thread (except WebWorkers). And in browser all the activity of the page is stopped if it can’t execute event handler of some element, for example, pressing the button or scrolling of the page. It follows that long cycle will stop all your application, because the functions in the queue for execution won’t be executed in the event cycle of JavaScript virtual machine. Therefore you can use cycles in JavaScript only for a strictly limited and small number of iterations. If you need to do a long cycle, for example, drawing of frames in HTML5 game or mathematical calculations on node.js web service, then you should plan iterations via setTimeout function, as shown in the example below.
Planning of iterationsUsing of such approach means that the next cycle iteration is put to the common queue of functions for execution and gives an opportunity to execute another functions also put in this queue, including callbacks and event handlers. This begs the question, why not just use setInterval, why such difficulties? Unfortunately setInterval function doesn’t wait for the completion of its callback and puts it in the queue of functions execution after certain interval again, which can obviously lead to the queue overflow in case of long work of code in callback.
Data structures
In JavaScript any object is represented by hash table and each object property including method name is a key of hash table, therefore an access to the properties occurs rather fast. But if you need to store a sequential data set not based on keys, then use arrays, because the speed of sequential search of elements in it is significantly higher, if you need two access methods to the objects (by key and sequentially), then it is not prohibited to add one and the same object in hash table and array. Almost for all operations with arrays can be used splice() method, I strongly recommend to read the documentation for this method, as it allows to delete a specified range of elements, insert instead of specified range another array, add array to the beginning or ending of the other and etc. In addition, arrays in JavaScript have built-in realization of stack and queue that also can be useful.
There is one common misconception that array elements can be deleted by “delete” operator, this is absolutely wrong. When using this operator an array element is not deleted, but its value just becomes “undefined” that forms a kind of “holes” in the arrays and may cause some errors in the array processing.
Prototype and inheritance model
Among other things in JavaScript there is rather unusual inheritance model – prototype. Every object in JavaScript has a prototype (which is also an object and can be found by the property __proto__), and if you ask the object to provide any property or method, and the object doesn’t have one, this property will be requested from its prototype, next if necessary from its prototype and etc. As a result the inheritance hierarchy can be represented as Linked List consisting of hash tables, which is checked by interpreter, whether there is a specified key in the next hash table, and if it has found the one – returns, otherwise – returns undefined. At the end of the prototypes chain is always an empty object, which will mean the end of the search. The figure below shows a scheme of object inheritance in JavaScript.
Diagram of prototype inheritanceExcept the prototypes there is also a concept of constructor, this is a function, which creates a new object specifying for it a prototype, constructor, from which the object was created and if necessary initializes object properties, and the first two actions are done automatically at the language level using “new” operator. Below there is an example of defining constructor and prototype, which it will assign to its objects.
Example of constructorUsually in the prototype values by default are specified for object properties, but here you should be careful too, because if you will specify as value objects or arrays, then their changes in one object, created with this prototype, will be affected on all the rest of objects, created with this prototype. If you want to avoid this, initialize objects and arrays in the constructor itself, not in the prototype.
Of course if you will assign to the object a value by property with the name, which is similar with the name in prototype, then this won’t change a prototype and just will create the same property in the object itself that is like it will override the prototype value in the object itself. In the example below is represented an object, created with this constructor.
Structure of the object created by constructorAlso there is a way of creating a chain of prototypes or multilevel prototype inheritance, for this there is a known realization of inheritance function, shown below.
Function of building a chain of prototypesIt is worth noting that you should use this function before defining of ctor.prototype properties, otherwise this function will clear them. This way of building a chain of prototypes is absolutely correct and allows using instanceof operator with created objects. Here is a short example of function and object using, which was obtained when using resulting constructor.
Using of inherits function
Received object using received constructor
Guideline
In JavaScript as in Java it is common to use Camel Casing for variables, Upper Casing for constants and Pascal Casing for constructors. Also rather important moment is using of so-called Egyptian brackets when formatting code blocks or objects, an example below shows rather serious error when using an opening brace on the new line as it, for example, C# developers used to do.
Example of error when not using Egyptian bracketsIn this case, JavaScript interpreter will decide that you missed a semicolon after “return” word, will neutralize this error, and your method will return undefined.
For comments and documentation of the code there is similar to JavaDoc tool, JSDoc, which has the same format and includes additional tags specific for JavaScript. Using this tool there is an opportunity to generate documentation in HTML format using templates or in another necessary form. Very important assistant of JavaScript developer is JSLint – this is an analyzer of possible semantic errors and coding style, which is included in some IDE, such as WebStorm. All of the illustrations for this article made with WebStorm, have highlighted problem areas of code that JSLint provides and gives detailed diagnostic about solving of problems. Also there is an online version of validator for those who prefer IDE not supporting JSLint.
Useful literature and materials
Conclusion
Despite the pitfalls in JavaScript language and some complexities of perception now it is rather common and more and more new developers start to use it with the development of web technologies, both client and server. Formal resemblance with famous for developer languages can cause a false sense that there is no need to go deep into the language when writing the code, but as this short review shows, this need still exists.
This entry was posted on Monday, June 3rd, 2013 at 7:27 am and is filed under JavaScript.