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, frameworks, 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-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 throwed. 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 of an object, you probably are doing something like this:
var myObject = {
name: '@tips_js'
};
if (typeof myObject['name'] !== 'undefined') { ... }
if (myObject['name']) { ... }
Thats 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 available both ways.
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 differs in the depth how check the properties, in other words hasOwnProperty
will only return true if key is available on that object directly, however in
operator doesn't discriminate between properties created on an object and properties inherited from the prototype chain.
Here 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 the live examples!
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
-
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 && colorObj.hasOwnProperty(color)) {
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!