Created
October 7, 2016 19:07
-
-
Save AloofBuddha/7bb23890e25249a6ed110ee681c2e567 to your computer and use it in GitHub Desktop.
ES6 tutorial
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ES6 of the week: arrow functions and lexical scope | |
// https://github.com/lukehoban/es6features | |
// arrow functions are a shorthand for function syntax, | |
// which make them a lot more succint for functions that take functions | |
// (i.e. 'higher order functions') | |
var evens = [2,4,6,8,10]; | |
// traditional function | |
var odds = evens.map(function(val) { | |
return val + 1; | |
}); | |
// 'expression body' syntax, automaticall returns | |
var odds3 = evens.map(val => val + 1); | |
// with multiple arguments and 'statement body' syntax | |
var byIndex = even.map((val, index) => { | |
return { index: index, val: val}; | |
}); | |
/* LEXICAL THIS!!! */ | |
var traditional = { | |
name: "Ben", | |
siblings: ["Lauren", "Ben"], | |
printFriends: function () { | |
this.siblings.forEach(function(sibling) { | |
// this.name will not refer to "Ben" because | |
// this is rebound in the new function passed to forEach | |
console.log(this.name, "<3", sibling) | |
}); | |
} | |
} | |
var oldWay = { | |
name: "Ben", | |
siblings: ["Lauren", "Ben"], | |
printFriends: function () { | |
var that = this; | |
this.siblings.forEach(function(sibling) { | |
// this will work because we bound this to that | |
// when it had the relevant value | |
console.log(that.name, "<3", sibling) | |
}); | |
} | |
} | |
var es6way = { | |
name: "Ben", | |
siblings: ["Lauren", "Ben"], | |
printFriends: function () { | |
this.siblings.forEach(sibling => { | |
// this will work because arrow functions | |
// do not rebind this, so it still has the context | |
// of its parent function | |
console.log(this.name, "<3", sibling) | |
}); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// HOISTING, LET and VAR | |
// hoisting can give you unexpected, silent errors | |
function implicitHoisting(x) { | |
if (x) { | |
var y = 'hello' | |
} | |
console.log(y + ' world!'); | |
} | |
implicitHoisting(true); // outputs 'hello world!' | |
implicitHoisting(false); // no faliure, outputs 'undefined world!' | |
// Why? | |
// in Javascript, var is function scoped, | |
// meaning a declared variable exists for the entire scope of | |
// its containing function. | |
// It also has a behavior called 'hoisting', where all variable | |
// declerations are 'hoisted' to the top of the function | |
// so the compiler actually sees hoistingExample as | |
function explicitHoisting(x) { | |
var y; // new variables equal undefined by default | |
if (x) { | |
y = 'hello' | |
} | |
console.log(y + ' world!'); | |
} | |
explicitHoisting(true); // outputs 'hello world!' | |
explicitHoisting(false); // no faliure, outputs 'undefined world!' | |
// Now this behavior makes sense | |
// So how does 'let' help us? | |
// Let is 'lexically scoped', which means variables only exist | |
// within their containing braces | |
// function noHoistingWithLet(x) { | |
// if (x) { | |
// let y = 'hello' | |
// } | |
// console.log(y + ' world!'); | |
// } | |
// Trying to *create* this function throws | |
// 'ReferenceError: y is not defined' - that's good, I think! | |
// It is called 'lexical scoping' because we can know the scope | |
// of a variable lexically, i.e. just my reading the file. | |
// --------------------------- | |
// Remeber this? | |
function arrayOfFuncs(n) { | |
var functions = []; | |
for (var i = 0; i < n; i++) { | |
functions.push(function () { | |
return i; | |
}); | |
} | |
return functions; | |
} | |
var myFunctions = arrayOfFuncs(3); | |
myFunctions.forEach(function(fn) { | |
console.log(fn()); | |
}); | |
// outputs: 3 3 3 | |
// Why? Let's think about closures for a second | |
function arrayOfFuncsExplicit(n) { | |
var functions; | |
var i; | |
functions = []; | |
for (i = 0; i < n; i++) { | |
functions.push(function () { | |
return i; | |
}); | |
} | |
return functions; | |
} | |
// our pushed function references a variable | |
// i, but it isn't contained in it's scope. However, | |
// because of closures, it still can reference this varaible | |
// however this variable is shared for all of the functions! | |
// therefore, at the end of the containing function i = 3, and | |
// when out functions are called they will all be referencing this i | |
function arrayOfFuncsLet(n) { | |
let functions = []; | |
for (let i = 0; i < n; i++) { | |
functions.push(() => i); | |
} | |
return functions; | |
} | |
// what's different here? each i assignment only | |
// exists for the life of it's for loop iteration | |
// this means the i being referenced int he function closure | |
// is a *different* i for each. So it keep the value we would THINK it would have! | |
// In general, let should replace var, always! | |
// ---------- | |
// CONST | |
const x = 1; | |
// const is like let, but can only be assigned once, at declaration | |
// x = 2; // This is an error! | |
// be wary though, const only enforces reassignment, it still | |
// allows mutation | |
const arr = [1,2,3]; | |
// arr = arr.map(x => x * 2); // not allowed! | |
for (let i = 0; i < arr.length; i++) { | |
arr[i] *= 2; | |
} | |
console.log(arr); // [2, 4, 6] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DEFAULTS | |
// old way | |
function foo (a, b) { | |
b = b || 'bar'; // if b has a value, it equals that, if undefined, it equals 'bar' | |
return a + b; | |
} | |
// ES6 way | |
function foo2 (a, b='bar') { | |
return a + b; | |
} | |
// It's as simple as that! | |
// REST | |
// old way | |
function printAllArgs() { | |
var args = Array.prototype.slice.call(arguments); | |
args.forEach(function (arg) { | |
console.log(arg) | |
}) | |
} | |
// ES6 way | |
function printAllArgs(...args) { | |
args.forEach(arg => console.log(arg)); | |
} | |
// ... is the rest operator. When put in front of a variable inside a parameter | |
// it means 'collect all unbound comma seperated arguments into an array' | |
function printAllArgs(first, second, ...rest) { | |
console.log(first) | |
console.log(second) | |
console.log(rest) | |
} | |
printAllArgs(1) // 1 undefined [] | |
printAllArgs(1, 2) // 1 2 [] | |
printAllArgs(1, 2, 3, 4) // 1 2 [3, 4] | |
// SPREAD | |
// spread is like the inverse of rest - it takes an array and 'spreads' it | |
// out into a bunch of comma seperated values | |
function add3(x, y, z) { | |
return x + y + z; | |
} | |
let nums = [1, 2, 3]; | |
add3(...nums); // same as foo.apply(foo, arr); | |
// spread can be used very effectively for copying arrays | |
let arr1 = [1,2,3]; | |
let arr2 = [...arr1]; | |
// or pushing a lot of elements to an array | |
let arr3 = [4,5,6]; | |
arr3.push(...arr1); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment