Nov 2016
Not exclusive to JavaScript by any means, the ternary operator (also refered to as the conditional operator) is a neat way to replace simple if ... else
statements.
const doIt = false;
let result;
if(doIt){
result = "Yes, I did it!";
}else{
result = "No, I didn't";
}
Can be replaced with:
const doIt = false;
let result = doIt ? "Yes, I did it!" : "No, I didn't";
If the bit before the question mark is truthy, then the expression evaluates to the first statement, if not then it evaluates to the second statement.
When you write a logical statement in JavaScript, if you use boolean operands (true
, false
) then the statement will always return a boolean. However, if you're not using a boolean operands (e.g. {a:1, b:2}
, [1,2,3,{...}]
then the value that returned the outcome gets returned. This means that you can replace:
let defaultObj = {a:1, b:2};
if(!myObject){
myObject = defaultObj;
}
with this:
let defaultObj = {a:1, b:2};
myObject = myObject || defaultObj;
If myObject
is truthy then it gets assigned to itself. If it's falsy then assign defaultObj
to it.
Javascript allows you to specify what this
is bound to no matter how or where a function is called.
The call
method allows you to call a function with a specific value of this
. It allows you to call a function by providing it an object to bind this
to. The first argument is what you want this
to be and the remaing arguments become the arguments to the function you are calling:
"use strict";
const fastCar = {make:"Ferrari"};
const slowCar = {make:"Skoda"};
function car(){
return `This car is a ${this.make}`;
}
car(); // Cannot read property 'make' of undefined
car.call(fastCar); // This car is a Ferrari
car.call(slowCar); // This car is a Skoda
function coloredCar(color){
return `This ${color} car is a ${this.make}`;
}
coloredCar.call(fastCar, "red"); // This red car is a Ferrari
function updateCar(color, topSpeed){
this.color = color;
this.topSpeed = topSpeed;
}
updateCar.call(fastCar, "Black", 210); // fastCar is now: { make: 'Ferrari', color: 'Black', topSpeed: 210 }
updateCar.apply(slowCar, ["Yellow", 95]); // slowCar is now: { make: 'Skoda', color: 'Yellow', topSpeed: 95 }
const updateFastCar = updateCar.bind(fastCar);
// the updateCar function has already been bound to fastCar. What happens if we call it on slowCar?
updateFastCar.call(slowCar, "Green", 50);
console.log(slowCar); // { make: 'Skoda', color: 'Yellow', topSpeed: 95 } Nothing happened to the Skoda. It's the same as before
console.log(fastCar); // { make: 'Ferrari', color: 'Green', topSpeed: 50 } This, however, updated. All because of the .bind method
// you can also bind arguments
const updateReallyFastCar = updateCar.bind(fastCar, "Midnight blue");
updateReallyFastCar.call(slowCar, 10);
console.log(slowCar); // { make: 'Skoda', color: 'Yellow', topSpeed: 95 }
console.log(fastCar); // { make: 'Ferrari', color: 'Midnight blue', topSpeed: 10 }
There are already some neat array operations baked-in to JavaScript, which I'll discuss here. If you want more functionality for manipulating data then check out lodash for general manipulation and crossfilter for powerful map/reduce functionality.
I'm sure you know about this one already, for some reason I always forget it's there andend up calling .indexOf
, so that I can go and pull the correct element out of an array, like some sort of mug. .find
willreturn you an object or null
if it doesn't exist:
const arr = [{id:1, product: 'Macbook Pro'}, {id:2, product: 'Macbook Air'}];
arr.find(o=> o.id === 1); // returns object {id:1, product: 'Macbook Pro'}
Note that you can also pass in the index of the element to your function. So to ignore anything before the 10th element you would write myArray.find((x,i)=> i>=10)
]
This is a seriously handy function and I use it daily. The naive approach would be to
loop through your array and pull out the items you want, storing them in another array. However the.filter
function makes light work of this common task:
const arr = [{id:1, product: 'Macbook Pro'}, {id:2, product: 'Macbook Air'}, {id:3, product: 'iPhone 7'}];
arr.filter(o=> o.id > 1); // returns [{id:2, product: 'Macbook Air'}, {id:3, product: 'iPhone 7'}]
Another common scenario is wanting to take an array of objects and transform (map) them to something different.So if we just wanted a list of products, from the arr
array in the previous example, we could map that field like so:
arr.map(o=> o.product); // returns ['Macbook Pro', 'Macbook Air', 'iPhone 7']
If this was a weapon in Call of Duty it would be regarded as overpowered. reduce
is capable of doing a map, a filter, or pretty much anyarray manipulation that you can think of. With most other array callback, the first element passed into the callback is the current array element. With reduce
, however,the first value is an accumulator, which is what the array is being reduced to. The rest of the arguments are what you'd expect: the current element, index, and the array itself.
const nums = [1,2,3,4,5];
const sum = nums.reduce((a,x)=> a+=x, 0);
Here we see that the function passed into reduce
takes 2 params: the accumulator and the current array element. Also note that we initialise the accumulator as zero.
Finally, here's a more involved example. Donald Knuth's variance algorithm:
const data = [1,2,3,4,5,10,20,30];
const stats = data.reduce((a,x)=>{
a.N++;
let delta = x = a.mean;
a.mean += delta/a.N;
a.M2 += delta*(x-a.mean);
return a;
}, {N:0, mean:0, M2:0});
if(stats.N>2){
stats.variance = stats.M2/(stats.N-1);
stats.stdev = Math.sqrt(stats.variance);
}