# ES6+

  • The 6 edition of the ECMAScript-262 standard for JavaScript
  • Also known as ECMAScript 2015
  • Was finalized and published in June 2015
  • This added significant new syntax and features
  • Native support in most browsers at this time for most features
  • Can use a tool like Babel to transpile to ES5 for compatibility
  • New additions are published yearly. Browser support lags behind slightly.
  • ES7 or ECMAScript 2016 is widely supported by current major browsers
  • https://en.wikipedia.org/wiki/ECMAScript#6th_Edition_-_ECMAScript_2015
  • https://kangax.github.io/compat-table/es6/

# ES6 Features

http://es6-features.org/

  • ES6 adds some new syntax and features. Some of the bigger changes are:
    • Classes
    • Block-Scoped Constructs let and const
    • Arrow Functions
    • Default Parameters
    • Rest and Spread Parameters
    • Destructuring Assignment
    • Template Strings
    • Multi-line String
    • Maps & Sets
    • Modules
  • http://kangax.github.io/compat-table/es6/

# JavaScript OOP Patterns

Patterns to implement Object Oriented Programming in JavaScript
We will be looking at a few basic ones:

  • Object Literal
  • Constructor Function (Constructor Pattern) 构造函数
  • Constructor Function with Prototype (Constructor Pattern) 带有原型的构造函数
  • Function that returns an object (Factory Pattern) 返回一个对象的函数
  • ES6 Classes

# Object Member Visibility With Constructor Function

Public, Private, Privileged

  • These are ways we can have private and public members and methods for objects when we model them with the Constructor pattern.
    当使用构造函数模式为对象建模时,这些方法可以让对象拥有私有和公共成员和方法。
  • Functions and variables assigned in a constructor with the this keyword will be publically visible.
    this 在构造函数中赋值的函数和变量将是公开可见的。
    Functions and variables assigned normally will be private.
    通常分配的函数和变量将是私有的。
  • Be careful, the this keyword can get bound to the window object so it is common to see a var that = this; line in the object to bind that to the proper this .
    注意, this 可以绑定到 window 对象,因此通常会在对象中看到一个 var that = this; 的行,将它绑定到恰当的 this

http://crockford.com/javascript/private.html
http://robertnyman.com/2008/10/14/javascript-how-to-get-private-privileged-publicand-static-members-properties-and-methods/

Simple Visibility Example
function Person(fname, lname) {
    this.name = "person: " + fname;
    var fullName = fname + " " + lname;
    function print() {
        alert(fullName);
    }
    this.render = function(){
        print();
    };
}
var myPerson = new Person("Brian", "Bailey");

# ES6 Classes

# class syntax

  • ES6 added a class syntax similar to other languages.
    ES6 增加了类似其他语言的 class 类语法。
  • Just syntactic sugar, still prototypal under the hood.
    只是语法糖,实际还是原型
  • Constructor is used to setup parameters and set properties.
    构造函数用于设置参数和设置属性。
class Song {
    constructor(title, artist, duration) {
        this.title = title;
        this.artist = artist;
        this.duration = duration;
        this.isPlaying = false;
    }
    start() {
        this.isPlaying = true;
    }
}

# Property Accessors 属性访问器

  • Classes can have getter and setter properties/methods
    类可以具有 gettersetter 属性 / 方法
  • These allow you to add methods that handle class properties when you use dot notation to get or set their value
    当使用 . 点符号获取或设置类属性的值时,这些方法允许您添加处理类属性的方法
class Song {
    constructor(title) {
        this.title = title;
    }
    get title() {
        return this.title;
    }
    set title(t) {
        this.title = "new title: " + t;
    }
}
let s = new Song("hello");
s.title; //returns "hello"
s.title = "goodbye";
s.title; //now returns "new title: goodbye"

# Inheritance

  • Classes can have inheritance
    类可以继承
  • Uses the extends keyword to define a "subclass"
    extends 关键字定义 "子类"
  • Still uses prototype inheritance in the background
    内部仍使用原型继承
class RockSong extends Song {
    constructor(title, artist, duration, type) {
        super(title, artist, duration);
        this.type = type;
    }
    logType() {
        console.log(this.type);
    }
}

# Public & static class fields

  • Experimental feature not final yet.
    实验功能,还没有最终确定。
  • Allows you to define class fields outside the constructor.
    允许在构造函数外部定义类字段。
  • Also allows for a static keyword for static fields that are shared on the class
    允许为类上共享的静态字段使用 static 关键字
class ClassWithPublicAndStaticFields {
    static staticProperty = 'aValue';
    static staticMethod() {
        return 'static method statements';
    }
    instatceProperty = 'aValue'
    publicMethod() {
        return 'public method statement';
    }
}

# References

  • JavaScript Object Creation Patterns
    http://leoasis.github.io/posts/2013/01/24/javascript-object-creation-patterns/
  • JavaScript Classes
    https://javascript.info/classes
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
  • Learning JavaScript Design Patterns Online Book (More in depth patterns)
    https://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript
  • Douglas Crockford – Private Member in JavaScript
    http://crockford.com/javascript/private.html
    Describes public and private members and methods in Constructor pattern
  • Douglas Crockford - http://www.crockford.com/
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript OOP Demo</title>
</head>
<body>
    <script>
        // Object Literal
        let carLiteral = {
            door: 4,
            color: 'black',
            wheels: 4,
            start: function(){
                console.log('car literal is started');
            }
        };
        let carLiteral2 = {
            door: 2,
            color: 'blue',
            wheels: 4,
            start: function(){
                console.log('car literal 2 is started');
            }
        };
        // Constructor Function
        function Car1(doors, color) {
            this.doors = doors;
            this.color = color;
            let miles = 0;
            let that = this;
            let report = function(){
                console.log('run report');
                console.log('Miles: ' + miles);
                console.log('Doors: ' + that.doors);
            };
            this.start = function(){
                console.log('Car with ' + this.doors + ' doors has started.');
                console.log('Miles: ' + miles);
                report();
            };
            this.addMile = function(){
                miles = miles + 1;
            };
            this.runReport = function(){
                report();
            };
        }
        let c1 = new Car1(2, 'red');
        let c2 = new Car1(4, 'blue');
        // Constructor Function with Prototype
        function CarProto(doors, color) {
            this.doors = doors;
            this.color = color;
            let miles = 0;
            let that = this;
            let report = function(){
                console.log('run report');
                console.log('Miles: ' + miles);
                console.log('Doors: ' + that.doors);
            };
            this.start = function(){
                console.log('Car with ' + this.doors + ' doors has started.');
                console.log('Miles: ' + miles);
                report();
            };
            this.addMile = function(){
                miles = miles + 1;
            };
            this.runReport = function(){
                report();
            };
        }
        CarProto.aClassProp = 'Ford';
        CarProto.prototype.run = function(){
            console.log('Car with ' + this.doors + ' doors has started.');
            this.runReport();
        };
        let cproto1 = new CarProto(2, 'red');
        // Factory Pattern
        function carFactory(doors, color) {
            let car = {};
            car.doors = doors;
            car.color = color;
            car.run = function(){
                console.log(this.color + ' Car with ' + this.doors + ' doors is running.');
            };
            return car;
        }
        let cfactory1 = carFactory(4, 'red');
        function vehicleFactory(wheels, color) {
            if (wheels === 2) {
                let v = new Motocycle(color);
                return v;
            } else {
                return new Car(wheels, color);
            }
        }
        // ES6 Classes
        class Vehicle {
            constructor(wheels, doors) {
                this.wheels = wheels;
                this._doors = doors;
                this._miles = 0;
            }
            get doors() {
                console.log('getting _doors value');
                return this._doors;
            }
            set doors(d) {
                console.log('setting _doors value');
                this._doors = d;
            }
            get miles() {
                return this._miles + ' miles driven';
            }
            set miles(m) {
                this._miles = m;
            }
            get desc(){
                return 'Vehicle with ' + this._doors + ' doors and ' + this.wheels + ' wheels';
            }
            run(){
                console.log('Vehicle is running');
            }
            start() {
                console.log('Started Vehicle with ' + this._doors + ' doors.');
            }
        }
        let v = new Vehicle(4, 4);
        class Car extends Vehicle {
            constructor(wheels, doors, color){
                super(wheels, doors);
                this._color = color;
            }
            
            get color() {
                return this._color;
            }
            set color(c) {
                this._color = c;
            }
            start(){
                console.log('Started Car with ' + this._doors + ' doors.');
            }
        }
        let c = new Car(4, 2, 'blue');
        class Ford extends Car {
            constructor(wheels, doors, color, model) {
                super(wheels, doors, color);
                this._model = model;
            }
            get model(){
                return this._model;
            }
            set model(m) {
                this._model = m;
            }
            start(){
                console.log('Started Ford ' + this.model +  ' with ' + this._doors + ' doors.');
            }
            static report(){
                console.log('This is a static method you call on the class');
            }
        }
        let f = new Ford(4, 4, 'red', 'explorer');
        class ClassWithPublicFields {
            wheels = 4;
            static staticProperty = 'This is a statick property';
            report() {
                console.log('Class public field wheels: ' + this.wheels);
            }
            static staticMethod() {
                console.log('Static Method');
            }
        }
        let cc = new ClassWithPublicFields();
    </script>
</body>
</html>

# JavaScript Closure 闭包

A closure is an inner function that has access to the outer (enclosing) function's variables — scope chain
闭包是一个内部函数,它可以访问外部 (封闭) 函数的变量作用域链

  • http://javascriptissexy.com/understand-javascript-closures-with-ease/
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
  • http://www.javascriptkit.com/javatutors/closures.shtml

# JS Scope 作用域

Here are some links to further explain JavaScript Scope.

  • https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/

  • https://toddmotto.com/understanding-the-this-keyword-in-javascript/

  • https://toddmotto.com/es6-arrow-functions-syntaxes-and-lexical-scoping/

  • Remember that when using the var keyword to declare a variable there is no block scope, only functional scope.
    当使用 var 关键字声明变量时,没有块作用域,只有函数作用域

  • ES6 adds two new keywords that declare block scoped constructs
    ES6 添加了两个声明块作用域构造的新关键字

    • let
    • const
  • let is similar to var but has block scope

  • let is the new var

  • const declares an immutable variable that also has block scope. Once the
    value is assigned it is fixed and can't be changed.
    const 声明了一个同样具有块作用域的不可变变量。一旦赋值,它就是固定的,不能更改。

# Arrow Functions

  • This is a new syntax to declare a function
    这是声明函数的新语法
  • Using an arrow function fixes the problems associated with the this keyword in some cases.
    在某些情况下,使用箭头函数可以修复与 this 关键字相关的问题。
    The this keyword will have the same value as in the context of the enclosing function.
    this 关键字的值将与封闭函数的内容中的值相同。
    It fixes the problem when creating closures and makes the that = this less necessary.
    它修复了创建闭包时的问题,并减少了 that = this 的必要性。
    Not to be used in all cases, see MDN link.
    不是在所有情况下都使用
  • If the function executes a single statement, it will implicitly return the result of that statement.
    如果该函数执行单个语句,它将隐式返回该语句的结果。
Old Style
function add (a, b) {
    return a + b
}
New Style
const add = (a, b) => a + b;

# Default Parameters

  • Default parameters are parameters to a function that are given some default values in the function declaration.
    默认参数是函数的参数,在函数声明中给出了一些默认值。
  • The value can be changed when calling the function
    调用函数时可以更改该值
const add = (a = 5, b = 6) => {
    return a + b;
}
function add(a = 5, b = 6) {
    return a + b;
}

# Rest Parameter

  • You can use the rest prefix of ... to extract the rest of the args from a function.
  • This lets you accept unlimited number of parameters and process them dynamically.
  • They come in as an array and only has the arguments that were not provided explicitly.
function add(a, b, ...more) {
// more variable in this block is an array of as many params that were passed
}
add(5, 6, 8, 2, 5, 6);
  • Inside the add function more is [8, 2, 5, 6] .

# Spread Operator

  • Similar to rest parameter in look but functions differently
    与 rest 参数在外观上类似,但功能不同
  • It spreads out the values of an array or iterable to separate elements
    它将数组的值展开,或者用迭代的方式分隔元素
  • Uses the ... before the variable name
var params = ["hello", true, 7];
var other = [1, 2, ...params ]; // results are [1, 2, "hello", true, 7]
var val = [1, 2];
function add(a, b) {
    return a + b
}
add(...val) // outputs 3

# Destructuring

  • Destructuring allows you to extract values from arrays and object
    析构允许从数组和对象中提取值
  • Uses the array brackets or object curly brackets
    使用数组括号或对象花括号
let arr = [5, 8, 2, 5];
let [x, y, z, w] = arr;
// x is 5, y is 8, z is 2, w is 5
var o = { p: 42, q: true };
var { p, q } = o;
// p is 42 and q is true

Can rename obj properties to new variable names
可以将 obj 属性重命名为新的变量名

var {p: foo, q: bar} = o;
//now foo is 42 and bar is true

# Template and Multi-line String

  • Use the back tick ``` to define and wrap the string.
  • This is for both template strings and multi-line strings.
    这既适用于模板字符串,也适用于多行字符串。
  • With template strings you can then evaluate variables in the string with ${}
Multi-Line String
var text = `This is a mult line string that
continues on to the next line.`;
Template String
var name = 'brian';
var greeting = `Hello ${name}!`;

# Maps and Sets

Map
Holds key-value pairs similar to an object but keeps track of insertion order.
保存类似于对象的键 - 值对,但保持插入顺序的跟踪。
Maps are iterable.
可迭代
Keys don't have to be strings but can be any object.
键值不一定是字符串,但可以是任何对象。
Set
Collections of unique values of any data type.
任何数据类型的唯一值的集合。
Sets are iterable and also keep track of insertion order.
可迭代,并且保持插入顺序的跟踪。
A value in a set can only occur once.
集合中的值只能出现一次。

Additional ES6 Resources to review
http://es6-features.org/
https://scotch.io/tutorials/demystifying-es6-classes-and-prototypalinheritance
https://github.com/getify/You-Dont-Know-JS
http://blog.teamtreehouse.com/get-started-ecmascript-6
https://webapplog.com/es6/
https://codeburst.io/es6-tutorial-for-beginners-5f3c4e7960be
https://html5hive.org/es6-and-babel-tutorial/