Jordan Kasper | @jakerella
What's the "ES" and how did we get to 6...
or 2015... or whatever?
They're awesome, and you should look into them...
... especially in combination with the
new fetch API
(versus traditional Ajax libraries).
class Todo {
constructor(text) {
this.text = text;
this.isComplete = false;
}
}
let item = new Todo('finish presentation');
class Todo {
constructor(text, dueDate) {
this.text = text;
this.isComplete = false;
this._dueDate = dueDate;
}
}
class Todo {
constructor(text, dueDate) {
this.text = text;
this.isComplete = false;
// Default dueDate is tomorrow
this._dueDate = dueDate || Date.now() + 86400000;
}
}
class Todo {
constructor(text = 'stuff', dueDate) {
this.text = text;
this.isComplete = false;
this._dueDate = dueDate || Date.now() + 86400000;
}
}
class Todo {
constructor(text='stuff', dueDate = Date.now() + 86400000) {
this.text = text;
this.isComplete = false;
this._dueDate = dueDate;
}
}
class App {
constructor() {
// kick off all the things...
}
}
new App(); // Get things started
class App {
constructor() {
document.querySelector('.create-todo')
.addEventListener('submit', (eventObj) => {
eventObj.preventDefault();
// do the work!
});
}
}
this
)
// ES5 callback
someFunction() {
someNode.addEventListener("click", function (eventObj) {
console.log(this); // someNode
});
}
// ES6 arrow function
someFunction() {
someNode.addEventListener("click", (eventObj) => {
console.log(this); // whatever someFunction's `this` is
});
}
The question is: do you need it?
[1, 2, 3].map(num => {
console.log(num); // 1 (then 2, then 3)
console.log(this); // undefined
})
someNode.addEventListener("click", (eventObj) => {
console.log(this); // undefined
console.log(eventObj.target); // someNode (probably)
});
One note: if you delegate events this gets tricky!
[1, 2, 3].map( num => num * num ); // [1, 4, 9]
Note there are no curly braces!
num => num * num
Only when there is no code block (curly braces).
class App {
constructor() {
document.querySelector('.create-todo')
.addEventListener('submit', (eventObj) => {
eventObj.preventDefault();
App.createTodo();
});
}
static createTodo() {
const text = document.querySelector('.todo-text').value;
const item = new Todo(text);
}
}
let
AND const
a short tangent
let
and block scoping
let z = 1;
if (x === y) {
let z = 10;
z++;
}
// what is `z` now?
`z` will be 1 at the bottom!
let
and block scoping
for (var i=0; i<10; i++) {
// do some stuff...
}
console.log(i); // i is 10 outside the loop!
for (let i=0; i<10; i++) {
// do some stuff...
}
console.log(i); // ReferenceError!
let
vs const
let counter = 1;
counter++; // totally fine
const index = 1;
index++; // TypeError
let
vs const
const o = {};
o.foo = 'bar'; // totally fine
constant reference vs. constant value
class App {
constructor() { /* ... */ }
static createTodo() {
const text = document.querySelector('.todo-text').value;
const item = new Todo(text);
// put it into the DOM...
}
}
class Todo {
constructor() { /* ... */ }
render() {
return
`
${this.text}
`;
}
}
class Todo {
constructor() { /* ... */ }
render() {
return
`
${this.text}
`;
}
}
class App {
// ...
static createTodo() {
const text = document.querySelector('.todo-text').value;
const item = new Todo(text);
const list = document.querySelector('.todo-list');
list.innerHTML += item.render();
}
}
<li class="">
<p>finish presentation</p>
<time>1508702292483</time>
</li>
(Yes, that spacing is intentional, but do you care?)
class Todo {
constructor() { /* ... */ }
render() { /* ... */ }
get dueDate() {
return (new Date(this._dueDate)).toLocaleString();
}
set dueDate(value) {
this._dueDate = (new Date(value)).getTime();
}
}
render() {
return
`
${this.text}
`;
}
Look closesly at the <time>
element!
<li data-id="1234567890">
<p>finish presentation</p>
<time>10/22/2017, 4:07:55 PM</time>
</li>
I don't like repeating myself...
this.text
this.dueDate
this.isComplete
render() {
const { text, dueDate, isComplete } = this;
return
`
${text}
`;
}
What about saving the Todo Item?
Resource
| |
Todo User
|
Admin
class Resource {
constructor() { } // You need this, but it can be blank
save() { }
get() { }
destroy() { }
}
class Todo extends Resource {
constructor( /* params... */ ) {
super();
// your other code...
}
}
function Todo() {
Resource.prototype.constructor.apply(this, Array.from(arguments));
// ...
}
Todo.prototype = Object.create(Resource.prototype);
Todo.prototype.constructor = Todo;
...which is fine,
but you still need to know about prototypes!
class Resource {
constructor() { }
save() { } // let's look closer at this...
get() { }
destroy() { }
}
class Resource {
constructor() { }
save() {
// What if there's bad data?
// We need validation!
// do the save...
// maybe with fetch()?
}
}
class Resource {
constructor() { }
save() {
this.validate();
// do the save...
// maybe with fetch()?
}
}
class Resource {
constructor() { }
save() {
/* ... */
}
validate() {
if (this.id && typeof(this.id) !== "number") {
throw new Error("Invalid resource ID");
}
}
}
class Todo extends Resource {
constructor() { /* ... */ }
render() { /* ... */ }
validate() {
if (typeof(this.text) !== "string") {
throw new Error("Invalid Todo text");
}
// more data checks...
}
}
We have a problem... the ID is never checked!
Don't duplicate, reuse!
class Todo extends Resource {
constructor() { /* ... */ }
render() { /* ... */ }
validate() {
super.validate();
if (typeof(this.text) !== "string") {
throw new Error("Invalid Todo text");
}
// more data checks...
}
}
This is still just prototypes!
(Be careful, it's really just a new keyword that behaves differently in different conditions.)
(You still need to know about prototypes.)
class App {
// ...
static createTodo() {
const text = document.querySelector('.todo-text').value;
const item = new Todo(text);
try {
item.save();
const list = document.querySelector('.todo-list');
list.innerHTML += item.render();
} catch(err) {
// Handle the error!
// (Maybe tell the user something's wrong?)
}
}
}
... but can I use these today?
Feature | Modern Browsers? | IE 11? |
---|---|---|
Classes | ◕‿◕ | ಠ_ಠ |
Default Fn args | ◕‿◕ | ಠ_ಠ |
let and const | ◕‿◕ | o_o |
Template Literals | ◕‿◕ | ಠ_ಠ |
Object Deconstruction | ◕‿◕ | ಠ_ಠ |
Promises | ◕‿◕ | ಠ_ಠ |
Arrow Functions | ◕‿◕ | ಠ_ಠ |
fetch | ◕‿◕ | ಠ_ಠ |
Jordan Kasper | @jakerella