New year, new project. A JS tip per day!
With great excitement, I introduce these short and useful daily JavaScript tips that will allow you to improve your code writing. With less than 2 minutes each day, you will be able to read about performance, conventions, hacks, interview questions and all the items that the future of this awesome language holds for us.
At midday, no matter if it is a weekend or a holiday, a tip will be posted and tweeted.
Please feel free to send us a PR with your own JavaScript tip to be published here. Any improvements or suggestions are more than welcome! Click to see the instructions
To get updates, watch the repo and follow the Twitter account, only one tweet will be sent per day. It is a deal!
Don't forget to Star the repo, as this will help to promote the project!
2016-01-20 by @WakeskaterX
When creating functions on an object in Object Oriented Javascript, returning the object in the function will enable you to chain functions together.
function Person(name) {
this.name = name;
this.sayName = function() {
console.log("Hello my name is: ", this.name);
return this;
};
this.changeName = function(name) {
this.name = name;
return this;
};
}
var person = new Person("John");
person.sayName().changeName("Timmy").sayName();
2016-01-19 by @gogainda
Suppose you have a couple of variables with unknown types and you want to concatenate them. To be sure that the arithmetical operation would not be applied during the concatenation:
var one = 1;
var two = 2;
var three = '3';
var result = ''.concat(one, two, three); //"123"
This way of concatenation does exactly what you expect. On the contrary, concatenation with pluses might lead to unexpected results:
var one = 1;
var two = 2;
var three = '3';
var result = one + two + three; //"33" instead of "123"
Speaking about performance, in comparison with join
type of concatenation, the speed of the concat
type is pretty much the same.
You can read more about concat
method on MDN page.
2016-01-18 by pklinger
Today's tip is about performance. [Ever came across the double tilde] (http://stackoverflow.com/questions/5971645/what-is-the-double-tilde-operator-in-javascript) ~~
operator? It is sometimes also called the double NOT bitwise operator. You can use it as a faster substitute for Math.floor()
. Why is that?
One bitwise shift ~
transforms the 32 bit converted input into -(input+1)
. The double bitwise shift therefore transforms the input into -(-(input + 1)+1)
making it a great tool to round towards 0. For numeric input, it therefore mimics the Math.ceil()
for negative and Math.floor()
for positive input. On failure, 0
is being returned, which might come in handy sometimes instead of Math.floor()
return value NaN
on failure.
// single ~
console.log(~1337) // -1338
// numeric input
console.log(~~47.11) // -> 47
console.log(~~-12.88) // -> -12
console.log(~~1.9999) // -> 1
console.log(~~3) // -> 3
// on failure
console.log(~~[]) // -> 0
console.log(~~NaN) // -> 0
console.log(~~null) // -> 0
// greater than 32 bit integer fails
console.log(~~(2147483647 + 1) === (2147483647 + 1)) // -> 0
Although ~~
may perform better, for the sake of readability please use Math.floor()
.
2016-01-17 by @odsdq
In node, you can tell your program to do two different things depending on whether the code is run from require('./something.js')
or node something.js
. This is useful if you want to interact with one of your modules independently.
if (!module.parent) {
// ran with `node something.js`
app.listen(8088, function() {
console.log('app listening on port 8088');
})
} else {
// used with `require('/.something.js')`
module.exports = app;
}
See the documentation for modules for more info.
2016-01-16 by @minhazav
By default you cannot pass arguments to a callback function. For example:
function callback() {
console.log('Hi human');
}
document.getElementById('someelem').addEventListener('click', callback);
You can take advantage of the closure scope in Javascript to pass arguments to callback functions. Check this example:
function callback(a, b) {
return function() {
console.log('sum = ', (a+b));
}
}
var x = 1, y = 2;
document.getElementById('someelem').addEventListener('click', callback(x, y));
What are closure? Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created. Check MDN Documentation to learn more.
So this way the arguments x
and y
are in scope of the callback function when it is called.
Another method to do this is using bind
method. For example:
var alertText = function(text) {
alert(text);
};
document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello'));
There is a very slight difference in performance of both methods, checkout jsperf.
2016-01-15 by @jhogoforbroke
JavaScript by default does not have a contains method. And for checking existence of a substring in string or item in array you may do this:
var someText = 'javascript rules';
if (someText.indexOf('javascript') !== -1) {
}
// or
if (someText.indexOf('javascript') >= 0) {
}
But let's look at these Expressjs code snippets.
for (var key in obj) {
// "reserved" exports
if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue;
exports.normalizeType = function(type){
return ~type.indexOf('/')
? acceptParams(type)
: { value: mime.lookup(type), params: {} };
};
// key is invalid
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
The gotcha is the bitwise operator ~, "Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values."
It transforms -1
into 0
, and 0
evaluates to false
in JavaScript:
var someText = 'text';
!!~someText.indexOf('tex'); // someText contains "tex" - true
!~someText.indexOf('tex'); // someText NOT contains "tex" - false
~someText.indexOf('asd'); // someText doesn't contain "asd" - false
~someText.indexOf('ext'); // someText contains "ext" - true
In ES6 was introduced the includes() method and you can use to determine whether or not a string includes another string:
'something'.includes('thing'); // true
With ECMAScript 2016 (ES7) is even possible uses with Arrays, like indexOf:
!!~[1, 2, 3].indexOf(1); // true
[1, 2, 3].includes(1); // true
Unfortunately, It's got support only in Chrome, Firefox, Safari 9 or above and Edge. Not IE11 or less. It's better to using in controlled environments.
2016-01-13 by @pklinger
Introduced as a new feature in ES6, fat arrow functions may come as a handy tool to write more code in less lines. The name comes from its syntax as =>
is a 'fat arrow' compared to a thin arrow ->
. Some programmers might already know this type of functions from different languages such as Haskell as 'lambda expressions' respectively 'anonymous functions'. It is called anonymous, as these arrow functions do not have a descriptive function name.
- Syntax: less LOC; no more typing
function
keyword over and over again - Semantics: capturing the keyword
this
from the surrounding context
Have a look at these two code snippets, which exactly do the same job. You will quickly understand what fat arrow functions do.
// general syntax for fat arrow functions
param => expression
// may also be written with parentheses
// parentheses are required on multiple params
(param1 [, param2]) => expression
// using functions
var arr = [5,3,2,9,1];
var arrFunc = arr.map(function(x) {
return x * x;
});
console.log(arr)
// using fat arrow
var arr = [5,3,2,9,1];
var arrFunc = arr.map((x) => x*x);
console.log(arr)
As you may see, the fat arrow function in this case may save you time typing out the parentheses as well as the function and return keywords. I would advice you to always write parentheses around the parameter inputs as the parentheses will be needed for multiple input parameters such as in (x,y) => x+y
anyways. It is just a way to cope with forgetting them in different use cases. But the code above would also work like this: x => x*x
. So far these are only syntactical improvements, which lead to less LOC and better readability.
There is another good reason to use fat arrow functions. There is the issue with the context of this
. With arrow functions, you will not worry about .bind(this)
or setting that = this
anymore, as fat arrow functions pick the context of this
from the lexical surrounding. Have a look at the next [example] (https://jsfiddle.net/pklinger/rw94oc11/):
// globally defined this.i
this.i = 100;
var counterA = new CounterA();
var counterB = new CounterB();
var counterC = new CounterC();
var counterD = new CounterD();
// bad example
function CounterA() {
// CounterA's `this` instance (!! gets ignored here)
this.i = 0;
setInterval(function () {
// `this` refers to global object, not to CounterA's `this`
// therefore starts counting with 100, not with 0 (local this.i)
this.i++;
document.getElementById("counterA").innerHTML = this.i;
}, 500);
}
// manually binding that = this
function CounterB() {
this.i = 0;
var that = this;
setInterval(function() {
that.i++;
document.getElementById("counterB").innerHTML = that.i;
}, 500);
}
// using .bind(this)
function CounterC() {
this.i = 0;
setInterval(function() {
this.i++;
document.getElementById("counterC").innerHTML = this.i;
}.bind(this), 500);
}
// fat arrow function
function CounterD() {
this.i = 0;
setInterval(() => {
this.i++;
document.getElementById("counterD").innerHTML = this.i;
}, 500);
}
Further information about fat arrow functions may be found at [MDN] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). To see different syntax options visit [this site] (http://jsrocks.org/2014/10/arrow-functions-and-their-scope/).
2016-01-13 by @manmadareddy
For quickly measuring performance of a javascript block, we can use the console functions like
console.time(label)
and console.timeEnd(label)
console.time("Array initialize");
var arr = new Array(100),
len = arr.length,
i;
for (i = 0; i < len; i++) {
arr[i] = new Object();
};
console.timeEnd("Array initialize"); // Outputs: Array initialize: 0.711ms
More info: Console object, Javascript benchmarking
Demo: jsfiddle - codepen (outputs in browser console)
2016-01-12 by Avraam Mavridis
In many programming languages the parameters of a function is by default mandatory and the developer has to explicitly define that a parameter is optional. In Javascript every parameter is optional, but we can enforce this behavior without messing the actual body of a function taking advantage of the [es6's default values for parameters] (http://exploringjs.com/es6/ch_parameter-handling.html#sec_parameter-default-values) feature.
const _err = function( message ){
throw new Error( message );
}
const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b
getSum( 10 ) // throws Error, b is not defined
getSum( undefined, 10 ) // throws Error, a is not defined
_err
is a function that immediately throws an Error. If no value is passed for one of the parameters, the default value is gonna be used, _err
will be called and an Error will be thrown. You can see more examples for the default parameters feature on Mozilla's Developer Network
2016-01-11 by @squizzleflip
Understanding hoisting will help you organize your function scope. Just remember, variable declaration and function definition are hoisted to the top. Variable definition is not, even if you declare and define a variable on the same line. Also, variable declaration is letting the system know that the variable exists while definition is assigning it a value.
function doTheThing() {
// ReferenceError: notDeclared is not defined
console.log(notDeclared);
// Outputs: undefined
console.log(definedLater);
var definedLater;
definedLater = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedLater)
// Outputs: undefined
console.log(definedSimulateneously);
var definedSimulateneously = 'I am defined!'
// Outputs: 'I am defined!'
console.log(definedSimulateneously)
// Outputs: 'I did it!'
doSomethingElse();
function doSomethingElse(){
console.log('I did it!');
}
// TypeError: undefined is not a function
functionVar();
var functionVar = function(){
console.log('I did it!');
}
}
To make things easier to read, declare all of your variables at the top of your function scope so it is clear which scope the variables are coming from. Define your variables before you need to use them. Define your functions at the bottom of your scope to keep them out of your way.
2016-01-10 by @loverajoel
When you have to check if a property is present on an object, you probably are doing something like this:
var myObject = {
name: '@tips_js'
};
if (myObject.name) { ... }
That's ok, but you have to know that there are two native ways for this kind of thing, the in
operator and Object.hasOwnProperty
, every object descended from Object
, has both ways available.
var myObject = {
name: '@tips_js'
};
myObject.hasOwnProperty('name'); // true
'name' in myObject; // true
myObject.hasOwnProperty('valueOf'); // false, valueOf is inherited from the prototype chain
'valueOf' in myObject; // true
Both differ in the depth that they check the properties, in other words hasOwnProperty
will only return true if key is available on that object directly, however the in
operator doesn't discriminate between properties created on an object and properties inherited from the prototype chain.
Here's another example
var myFunc = function() {
this.name = '@tips_js';
};
myFunc.prototype.age = '10 days';
var user = new myFunc();
user.hasOwnProperty('name'); // true
user.hasOwnProperty('age'); // false, because age is from the prototype chain
Check here for live examples!
I also recommend reading this discussion about common mistakes made when checking a properties' existence in objects.
2016-01-09 by @JakeRawr
As of ES6, JS now has template strings as an alternative to the classic end quotes strings.
Ex: Normal string
var firstName = 'Jake';
var lastName = 'Rawr';
console.log('My name is ' + firstName + ' ' + lastName);
// My name is Jake Rawr
Template String
var firstName = 'Jake';
var lastName = 'Rawr';
console.log(`My name is ${firstName} ${lastName}`);
// My name is Jake Rawr
You can do Multi-line strings without \n
and simple logic (ie 2+3) inside ${}
in Template String.
You are also able to to modify the output of template strings using a function; they are called [Tagged template strings] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings#Tagged_template_strings) for example usages of tagged template strings.
You may also want to read to understand template strings more
2016-01-08 by @Tevko
The querySelectorAll
method returns an array-like object called a node list. These data structures are referred to as "Array-like", because they appear as an array, but can not be used with array methods like map
and foreach
. Here's a quick, safe, and reusable way to convert a node list into an Array of DOM elements:
const nodelist = document.querySelectorAll('div');
const nodelistToArray = Array.apply(null, nodelist);
//later on ..
nodelistToArray.forEach(...);
nodelistToArray.map(...);
nodelistToArray.slice(...);
//etc...
The apply
method is used to pass an array of arguments to a function with a given this
value. MDN states that apply
will take an array like object, which is exactly what querySelectorAll
returns. Since we don't need to specify a value for this
in the context of the function, we pass in null
or 0
. The result is an actual array of DOM elements which contains all of the available array methods.
Or if you are using ES2015 you can use the spread operator ...
const nodelist = [...document.querySelectorAll('div')]; // returns a real Array
//later on ..
nodelist.forEach(...);
nodelist.map(...);
nodelist.slice(...);
//etc...
2016-01-07 by @nainslie
Strict-mode JavaScript makes it easier for the developer to write "secure" JavaScript.
By default, JavaScript allows the programmer to be pretty careless, for example, by not requiring us to declare our variables with "var" when we first introduce them. While this may seem like a convenience to the unseasoned developer, it's also the source of many errors when a variable name is misspelled or accidentally referred to out of its scope.
Programmers like to make the computer do the boring stuff for us, and automatically check our work for mistakes. That's what the JavaScript "use strict" directive allows us to do, by turning our mistakes into JavaScript errors.
We add this directive either by adding it at the top of a js file:
// Whole-script strict mode syntax
"use strict";
var v = "Hi! I'm a strict mode script!";
or inside a function:
function f()
{
// Function-level strict mode syntax
'use strict';
function nested() { return "And so am I!"; }
return "Hi! I'm a strict mode function! " + nested();
}
function f2() { return "I'm not strict."; }
By including this directive in a JavaScript file or function, we will direct the JavaScript engine to execute in strict mode which disables a bunch of behaviors that are usually undesirable in larger JavaScript projects. Among other things, strict mode changes the following behaviors:
- Variables can only be introduced when they are preceded with "var"
- Attempting to write to readonly properties generates a noisy error
- You have to call constructors with the "new" keyword
- "this" is not implicitly bound to the global object
- Very limited use of eval() allowed
- Protects you from using reserved words or future reserved words as variable names
Strict mode is great for new projects, but can be challenging to introduce into older projects that don't already use it in most places. It also can be problematic if your build chain concatenates all your js files into one big file, as this may cause all files to execute in strict mode.
It is not a statement, but a literal expression, ignored by earlier versions of JavaScript. Strict mode is supported in:
- Internet Explorer from version 10.
- Firefox from version 4.
- Chrome from version 13.
- Safari from version 5.1.
- Opera from version 12.
See MDN for a fuller description of strict mode.
2016-01-06 by @mattfxyz
Rather than writing separate methods to handle an array and a single element parameter, write your functions so they can handle both. This is similar to how some of jQuery's functions work (css
will modify everything matched by the selector).
You just have to concat everything into an array first. Array.concat
will accept an array or a single element.
function printUpperCase(words) {
var elements = [].concat(words);
for (var i = 0; i < elements.length; i++) {
console.log(elements[i].toUpperCase());
}
}
printUpperCase
is now ready to accept a single node or an array of nodes as its parameter.
printUpperCase("cactus");
// => CACTUS
printUpperCase(["cactus", "bear", "potato"]);
// => CACTUS
// BEAR
// POTATO
2016-01-05 by @loverajoel
-
undefined
means a variable has not been declared, or has been declared but has not yet been assigned a value -
null
is an assignment value that means "no value" -
Javascript sets unassigned variables with a default value of
undefined
-
Javascript never sets a value to
null
. It is used by programmers to indicate that avar
has no value. -
undefined
is not valid in JSON whilenull
is -
undefined
typeof isundefined
-
null
typeof is anobject
. Why? -
Both are primitives
-
Both are falsy (
Boolean(undefined) // false
,Boolean(null) // false
) -
You can know if a variable is undefined
typeof variable === "undefined"
- You can check if a variable is [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null)
```javascript
variable === null
-
The equality operator considers them equal, but the identity doesn't
null == undefined // true null === undefined // false
## #04 - Sorting strings with accented characters
> 2016-01-04 by [@loverajoel](https://twitter.com/loverajoel)
Javascript has a native method **[sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)** that allows sorting arrays. Doing a simple `array.sort()` will treat each array entry as a string and sort it alphabetically. Also you can provide your [own custom sorting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters) function.
```javascript
['Shanghai', 'New York', 'Mumbai', 'Buenos Aires'].sort();
// ["Buenos Aires", "Mumbai", "New York", "Shanghai"]
But when you try order an array of non ASCII characters like this ['é', 'a', 'ú', 'c']
, you will obtain a strange result ['c', 'e', 'á', 'ú']
. That happens because sort works only with english language.
See the next example:
// Spanish
['único','árbol', 'cosas', 'fútbol'].sort();
// ["cosas", "fútbol", "árbol", "único"] // bad order
// German
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort();
// ["Wann", "Woche", "wäre", "wöchentlich"] // bad order
Fortunately, there are two ways to overcome this behavior localeCompare and Intl.Collator provided by ECMAScript Internationalization API.
Both methods have their own custom parameters in order to configure it to work adequately.
['único','árbol', 'cosas', 'fútbol'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(function (a, b) {
return a.localeCompare(b);
});
// ["Wann", "wäre", "Woche", "wöchentlich"]
['único','árbol', 'cosas', 'fútbol'].sort(Intl.Collator().compare);
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'wöchentlich', 'wäre', 'Wann'].sort(Intl.Collator().compare);
// ["Wann", "wäre", "Woche", "wöchentlich"]
- For each method you can customize the location.
- According to Firefox Intl.Collator is faster when comparing large numbers of strings.
So when you are working with arrays of strings in a language other than English, remember to use this method to avoid unexpected sorting.
2016-01-03 by AlbertoFuente
How can we improve and make more efficient nested if
statement in javascript.
if (color) {
if (color === 'black') {
printBlackBackground();
} else if (color === 'red') {
printRedBackground();
} else if (color === 'blue') {
printBlueBackground();
} else if (color === 'green') {
printGreenBackground();
} else {
printYellowBackground();
}
}
One way to improve the nested if
statement would be using the switch
statement. Although it is less verbose and is more ordered, It's not recommended to use it because it's so difficult to debug errors, here's why.
switch(color) {
case 'black':
printBlackBackground();
break;
case 'red':
printRedBackground();
break;
case 'blue':
printBlueBackground();
break;
case 'green':
printGreenBackground();
break;
default:
printYellowBackground();
}
But what if we have a conditional with several checks in each statement? In this case, if we like to do less verbose and more ordered, we can use the conditional switch
.
If we pass true
as parameter to the switch
statement, It allows us to put a conditional in each case.
switch(true) {
case (typeof color === 'string' && color === 'black'):
printBlackBackground();
break;
case (typeof color === 'string' && color === 'red'):
printRedBackground();
break;
case (typeof color === 'string' && color === 'blue'):
printBlueBackground();
break;
case (typeof color === 'string' && color === 'green'):
printGreenBackground();
break;
case (typeof color === 'string' && color === 'yellow'):
printYellowBackground();
break;
}
But we must always avoid having several checks in every condition, avoiding use of switch
as far as possible and take into account that the most efficient way to do this is through an object
.
var colorObj = {
'black': printBlackBackground,
'red': printRedBackground,
'blue': printBlueBackground,
'green': printGreenBackground,
'yellow': printYellowBackground
};
if (color in colorObj) {
colorObj[color]();
}
Here you can find more information about this.
2016-01-02 by @loverajoel
The key is an attribute that you must pass to all components created dynamically from an array. It's unique and constant id that React use for identify each component in the DOM and know that it's a different component and not the same one. Using keys will ensure that the child component is preserved and not recreated and prevent that weird things happens.
Key is not really about performance, it's more about identity (which in turn leads to better performance). randomly assigned and changing values are not identity Paul O’Shannessy
-
Use an existing unique value of the object.
-
Define the keys in the parent components, not in child components
//bad ... render() { <div key={{item.key}}>{{item.name}}</div> } ... //good <MyComponent key={{item.key}}/>
-
random()
will not work//bad <MyComponent key={{Math.random()}}/>
-
You can create your own unique id, be sure that the method be fast and attach it to your object.
-
When the amount of child are big or involve expensive components, use keys has performance improvements.
-
You must provide the key attribute for all children of ReactCSSTransitionGroup.
2016-01-01 by @loverajoel
One of the most appreciated features of AngularJs is the two way data binding. In order to make this work AngularJs evaluates the changes between the model and the view through cycles($digest
). You need to understand this concept in order to understand how the framework works under the hood.
Angular evaluates each watcher whenever one event is fired, this is the known $digest
cycle.
Sometimes you have to force to run a new cycle manually and you must choose the correct option because this phase is one of the most influential in terms of performance.
This core method lets you to start the digestion cycle explicitly, that means that all watchers are checked, the entire application starts the $digest loop
. Internally after execute an optional function parameter, call internally to $rootScope.$digest();
.
In this case the $digest
method starts the $digest
cycle for the current scope and its children. You should notice that the parents scopes will not be checked
and not be affected.
-
Use
$apply
or$digest
only when browser DOM events have triggered outside of AngularJS. -
Pass a function expression to
$apply
, this have a error handling mechanism and allow integrate changes in the digest cycle$scope.$apply(() => { $scope.tip = 'Javascript Tip'; });
-
If only needs update the current scope or its children use
$digest
, and prevent a new digest cycle for the whole application. The performance benefit it's self evident -
$apply()
is hard process for the machine and can lead to performance issues when having a lot of binding. -
If you are using >AngularJS 1.2.X, use
$evalAsync
is a core method that will evaluate the expression during the current cycle or the next. This can improve your application's performance.
2015-12-29
Inserting an item into an existing array is a daily common task. You can add elements to the end of an array using push, to the beginning using unshift, or the middle using splice.
But those are known methods, doesn't mean there isn't a more performant way, here we go...
Adding an element at the end of the array is easy with push(), but there is a way more performant.
var arr = [1,2,3,4,5];
arr.push(6);
arr[arr.length] = 6; // 43% faster in Chrome 47.0.2526.106 on Mac OS X 10.11.1
Both methods modify the original array. Don't believe me? Check the jsperf
Now we are trying to add an item to the beginning of the array
var arr = [1,2,3,4,5];
arr.unshift(0);
[0].concat(arr); // 98% faster in Chrome 47.0.2526.106 on Mac OS X 10.11.1
Here is a little bit detail, unshift edits the original array, concat returns a new array. jsperf
Adding items at the middle of an array is easy with splice and is the most performant way to do it.
var items = ['one', 'two', 'three', 'four'];
items.splice(items.length / 2, 0, 'hello');
I tried to run these tests in various Browsers and OS and the results were similar. I hope these tips will be useful for you and encourage to perform your own tests!