symfonycasts course notes - JavaScript for PHP Geeks: ES6/ES2015 (New JavaScript)
1 - ECMAScript 2015 / ES6 / Harmony / Cookies
https://symfonycasts.com/screencast/javascript-es6/ecmascript-es6-harmony
JavaScript is not a language like PHP that has one core code. In reality, JavaScript is nothing more than a standard. When a new version of JavaScript is released, it simply means that the core group has said:
Here are some functions and language changes that we think would make JavaScript more hipster. Now, quick, everyone go and implement these!
And guess what? The language isn't even called JavaScript! It's called ECMAScript. And there is a group of smart people that work on new versions of ECMAScript. But unlike PHP, that doesn't mean they're writing code: they're simply deciding what should be included in the next version. Then, it's up to each browser and JavaScript engine to implement that. But as we will learn later... some smart people in the JS world have found a way around needing to wait for browser support...
2 - Arrow Functions
https://symfonycasts.com/screencast/javascript-es6/arrow-functions#play
You will see the first big feature or ES2015 used everywhere... and at first, it looks weird. Very simply, there is a new, shorter syntax for creating anonymous functions.
In ES2015, we can remove the word function, and add an "equal arrow" (=>) after the arguments:
$.ajax({
url: Routing.generate('rep_log_list'),
}).then(function(data) {
$.each(data.items, function(key, repLog) {
self._addRow(repLog);
});
})
equivalent:
$.ajax({
url: Routing.generate('rep_log_list'),
}).then((data) => {
$.each(data.items, function(key, repLog) {
self._addRow(repLog);
});
})
The Arrow Function's (Secret) Superpower (this)
It turns out, a classic anonymous function and the new arrow function do have one difference: when you use an arrow function, the this variable is preserved. That's awesome news, and it's why I now use the arrow function everywhere in my code.
We can finally remove this silly var = self thing. And instead, below, use this
Arrow Functions Everywhere!
Here, we're not using this, but I like to stay consistent and use the arrow function everywhere.
Arrow Function without a Body
In this case, the arrow function is nothing more than a single return statement. In this situation, to be extra fancy, you can remove the function body and return statement entirely:
swal({
preConfirm: () => {
return this._deleteRepLog($link);
}
equivalent to:
swal({
preConfirm: () => this._deleteRepLog($link)
});
When you don't have the curly braces, it means that this value will be returned. It looks weird at first, but it means the same thing that we had before. You will see this kind of stuff in code examples.
4 - var Versus let: Scope!
https://symfonycasts.com/screencast/javascript-es6/var-let-scope#play
And this is the difference between var and let. With var - just like with any variable in PHP - a variable's scope is the function it's inside of, plus any embedded functions.
But let is different: it's said to be "block-scoped". That means that anytime you have a new open curly brace ({) - like an if statement or for loop - you've entered a new scope for let. In this case, let is equal to 42, only inside of the if statement. Outside, it's a completely different variable, which is set to 10.
5 - var Versus let: Hoisting!
https://symfonycasts.com/screencast/javascript-es6/var-let-hoisting#play
When you use var to initialize a variable, when JavaScript executes, it basically finds all of your var variables, goes to the top of that variable's scope - usually the top of whatever function it's inside of, but in this case, it's the top of the file - and effectively does this: var aGreatNumber. That initializes the variable, but doesn't set it to any value. This is called variable hoisting: and it's the reason that we get undefined instead of an error when we try to use a variable that's declared with var... before it's declared.
But when we change this to let, we already saw that this does throw a ReferenceError. And that's kinda great! I mean, isn't that what we would expect to happen when we reference a variable that hasn't been created yet!
6 - const Versus let
https://symfonycasts.com/screencast/javascript-es6/const#play
As far as scope goes, const and let work the same. So really, const and let are identical... except that you can't modify a const variable.
Here's the truth: when you use const, it's not that the value of that variable can't change. The object can change. Instead, using const means that you cannot reassign the aGreatObject variable to something else in memory. It must be assigned only once, to this object. But after that, the object is free to change.
7 - Object Literals & Optional Args
https://symfonycasts.com/screencast/javascript-es6/object-literals-optional-args
Object Keys... without the Key
Well, in ES2015, if your key and your value are the same, you can just leave off the key:
$.ajax({
url: url,
method: 'POST',
data: JSON.stringify(data)
})
is equivalent to :
$.ajax({
url,
method: 'POST',
data: JSON.stringify(data)
})
Short Method Syntax
loadRepLogs: function() {
},
is equivalent to :
loadRepLogs() {
},
Optional Args
getTotalWeightString(maxWeight = 500)
8 - Legit JavaScript Classes
https://symfonycasts.com/screencast/javascript-es6/class-syntax#play
class Helper {
constructor($wrapper) {
this.$wrapper = $wrapper;
}
calculateTotalWeight() {
let totalWeight = 0;
this.$wrapper.find('tbody tr').each((index, element) => {
totalWeight += $(element).data('weight');
});
return totalWeight;
}
}
9 - Static Class Methods
https://symfonycasts.com/screencast/javascript-es6/static-class-methods#play
declare a static method:
static _calculateWeights($elements) {
}
call it referencing the class name:
Helper._calculateWeights(this.$wrapper.find('tbody tr'));
10 - Class Inheritance and super Calls
https://symfonycasts.com/screencast/javascript-es6/extends-super-calls#play
class AGreatClass {
constructor(greatNumber) {
this.greatNumber = greatNumber;
}
returnGreatThings() {
return this.greatNumber;
}
}
class AnotherGreatClass extends AGreatClass{
constructor(greatNumber, greatWord) {
super(greatNumber); //call parent constructor
this.greatWord = greatWord;
}
returnGreatThings() {
let greatNumber = super.returnGreatThings();
return [greatNumber, this.greatWord];
}
}
const aGreatObject = new AnotherGreatClass(42, 'adventure');
console.log(
aGreatObject.returnGreatThings()
);
11 - Destructuring
https://symfonycasts.com/screencast/javascript-es6/destructuring
let {id, itemLabel, reps} = repLog;
Yep, this weird line is actually going to create three new variables - id, itemLabel, and reps - set to the values of the id, itemLabel and reps keys in repLog.
12 - The... Spread Operator
https://symfonycasts.com/screencast/javascript-es6/spread-operator#play
let printThreeThings = function(thing1, thing2, thing3) {
console.log(thing1, thing2, thing3);
};
let yummyThings = ['pizza', 'gelato', 'sushi'];
printThreeThings(...yummyThings)
Spread Operator as an Array Merge
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
Spread Operator for Creating a new Array
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
let copyOfGreatThings = greatThings;
copyOfGreatThings.push('summer');
console.log(greatThings);
console.log(copyOfGreatThings);
Here's the question: we know summer now lives in copyOfGreatThings(). But does it also now live inside of greatThings? Try it! It does! Summer lives in both arrays! And this makes sense: arrays are objects in JavaScript, and just like in PHP, objects are passed by reference. In reality, greatThings and copyOfGreatThings are identical: they both point to the same array in memory.
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
let copyOfGreatThings = [...greatThings];
And that is it! This will create a new array, and then put each item from greatThings into it, one-by-one.
Try it! Yes! We can see summer in the copy, but we did not modify the original array.
13 - Template Strings
https://symfonycasts.com/screencast/javascript-es6/template-strings#play
This is the way we used to do things in JavaScript. But no more! Thanks to ES2015, we now have something called Template Strings. And it's awesome. Instead of quotes, use a tick. And as soon as you do that, you're allowed to put variables inside of your string! Remove this single quote plus garbage. Replace it with ${, the variable name, then }
const favoriteFood = 'gelato';
const iLoveFood = `The year is ${(new Date()).getFullYear()} and my favorite food is ${favoriteFood}`;
console.log(iLoveFood);
Turning our Template into a Function
const rowTemplate = (repLog) => `
<tr data-weight="${repLog.totalWeightLifted}">
<td>${repLog.itemLabel}</td>
<td>${repLog.reps}</td>
<td>${repLog.totalWeightLifted}</td>
<td>
<a href="#"
class="js-delete-rep-log"
data-url="${repLog.links._self}"
>
<span class="fa fa-trash"></span>
</a>
</td>
</tr>
`;
const html = rowTemplate(repLog);
14 - The for of Loop
https://symfonycasts.com/screencast/javascript-es6/for-of-loop#play
for (let repLog of data.items) {
this._addRow(repLog);
}
15 - Map and WeakMap
https://symfonycasts.com/screencast/javascript-es6/map-weak-map
let foods = new Map();
foods.set('italian', 'gelato');
foods.set('mexican', 'tortas');
foods.set('canadian', 'poutine');
let southernUsStates = ['Tennessee', 'Kentucky', 'Texas'];
foods.set(southernUsStates, 'hot chicken');
console.log(
foods.get('italian'),
foods.get(southernUsStates),
foods.size
);
16 - Private Variables & WeakMap
https://symfonycasts.com/screencast/javascript-es6/private-vars-weak-map#play
For us it means we should use Map in normal situations... and WeakMap only if we find ourselves with this problem.
17 - Array, Set and ES2016
https://symfonycasts.com/screencast/javascript-es6/array-setf
let foods = []; //same as new Array();
foods.push('gelato');
foods.push('tortas');
foods.push('gelato');
console.log(foods);
Introducing Set
let foods = new Set();
foods.add('gelato');
foods.add('tortas');
foods.add('gelato');
console.log(foods);
That's the key difference between Array and Set: Set should be used when you need a unique collection of items. It automatically makes sure that duplicates aren't added.
18 - yarn & npm: Installing Babel
https://symfonycasts.com/screencast/javascript-es6/npm-yarn#play
In a nut shell, Babel reads new JavaScript code, i.e. ES2015 code, and recompiles it to old JavaScript so that all browsers can understand it. Yea, it literally reads source code and converts it to different source code. It's wild!
yarn add babel-cli --dev
19 - Babel: Transpiling to Old JavaScript
https://symfonycasts.com/screencast/javascript-es6/babel#play
yarn add babel-preset-env --dev
.babelrc:
{
"presets": ["env"]
}
babel-and-the-polyfill
abel's job is to convert all the new language constructs and syntaxes to the old version. But if there are new objects or functions, it leaves those. Instead, you should use something called a polyfill. Specifically, babel-polyfill. This is another JavaScript library that adds missing functionality, like WeakMap, if it doesn't exist in whatever browser is running our code.