Friday, October 5, 2018

Learn ES2015

es6features

This document was originally taken from Luke Hoban's excellent es6features repo. Go give it a star on GitHub!

REPL

Be sure to try these features out in the online REPL.

Introduction

ECMAScript 2015 is an ECMAScript standard that was ratified in June 2015.
ES2015 is a significant update to the language, and the first major update to the language since ES5 was standardized in 2009. Implementation of these features in major JavaScript engines is underway now.
See the ES2015 standard for full specification of the ECMAScript 2015 language.

ECMAScript 2015 Features

Arrows and Lexical This

Arrows are a function shorthand using the => syntax. They are syntactically similar to the related feature in C#, Java 8 and CoffeeScript. They support both expression and statement bodies. Unlike functions, arrows share the same lexical this as their surrounding code. If an arrow is inside another function, it shares the "arguments" variable of its parent function.
// Expression bodies
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);

// Statement bodies
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

// Lexical this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
};

// Lexical arguments
function square() {
  let example = () => {
    let numbers = [];
    for (let number of arguments) {
      numbers.push(number * number);
    }

    return numbers;
  };

  return example();
}

square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]

Classes

ES2015 classes are a simple sugar over the prototype-based OO pattern. Having a single convenient declarative form makes class patterns easier to use, and encourages interoperability. Classes support prototype-based inheritance, super calls, instance and static methods and constructors.
class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    super(geometry, materials);

    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  update(camera) {
    //...
    super.update();
  }
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}

Enhanced Object Literals

Object literals are extended to support setting the prototype at construction, shorthand for foo: fooassignments, defining methods and making super calls. Together, these also bring object literals and class declarations closer together, and let object-based design benefit from some of the same conveniences.
var obj = {
    // Sets the prototype. "__proto__" or '__proto__' would also work.
    __proto__: theProtoObj,
    // Computed property name does not set prototype or trigger early error for
    // duplicate __proto__ properties.
    ['__proto__']: somethingElse,
    // Shorthand for ‘handler: handler’
    handler,
    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    },
    // Computed (dynamic) property names
    [ "prop_" + (() => 42)() ]: 42
};
The __proto__ property requires native support, and was deprecated in previous ECMAScript versions. Most engines now support the property, but some do not. Also, note that only web browsers are required to implement it, as it's in Annex B. It is available in Node.

Template Strings

Template strings provide syntactic sugar for constructing strings. This is similar to string interpolation features in Perl, Python and more. Optionally, a tag can be added to allow the string construction to be customized, avoiding injection attacks or constructing higher level data structures from string contents.
// Basic literal string creation
`This is a pretty little template string.`

// Multiline strings
`In ES5 this is
 not legal.`

// Interpolate variable bindings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Unescaped template strings
String.raw`In ES5 "\n" is a line-feed.`

// Construct an HTTP request prefix is used to interpret the replacements and construction
GET`http://foo.org/bar?a=${a}&b=${b}
    Content-Type: application/json
    X-Credentials: ${credentials}
    { "foo": ${foo},
      "bar": ${bar}}`(myOnReadyStateChangeHandler);

Destructuring

Destructuring allows binding using pattern matching, with support for matching arrays and objects. Destructuring is fail-soft, similar to standard object lookup foo["bar"], producing undefined values when not found.
// list matching
var [a, ,b] = [1,2,3];
a === 1;
b === 3;

// object matching
var { op: a, lhs: { op: b }, rhs: c }
       = getASTNode()

// object matching shorthand
// binds `op`, `lhs` and `rhs` in scope
var {op, lhs, rhs} = getASTNode()

// Can be used in parameter position
function g({name: x}) {
  console.log(x);
}
g({name: 5})

// Fail-soft destructuring
var [a] = [];
a === undefined;

// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;

// Destructuring + defaults arguments
function r({x, y, w = 10, h = 10}) {
  return x + y + w + h;
}
r({x:1, y:2}) === 23

Default + Rest + Spread

Callee-evaluated default parameter values. Turn an array into consecutive arguments in a function call. Bind trailing parameters to an array. Rest replaces the need for arguments and addresses common cases more directly.
function f(x, y=12) {
  // y is 12 if not passed (or passed as undefined)
  return x + y;
}
f(3) == 15
function f(x, ...y) {
  // y is an Array
  return x * y.length;
}
f(3, "hello", true) == 6
function f(x, y, z) {
  return x + y + z;
}
// Pass each elem of array as argument
f(...[1,2,3]) == 6

Let + Const

Block-scoped binding constructs. let is the new varconst is single-assignment. Static restrictions prevent use before assignment.
function f() {
  {
    let x;
    {
      // this is ok since it's a block scoped name
      const x = "sneaky";
      // error, was just defined with `const` above
      x = "foo";
    }
    // this is ok since it was declared with `let`
    x = "bar";
    // error, already declared above in this block
    let x = "inner";
  }
}

Iterators + For..Of

Iterator objects enable custom iteration like CLR IEnumerable or Java Iterable. Generalize for..in to custom iterator-based iteration with for..of. Don’t require realizing an array, enabling lazy design patterns like LINQ.
let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        return { done: false, value: cur }
      }
    }
  }
}

for (var n of fibonacci) {
  // truncate the sequence at 1000
  if (n > 1000)
    break;
  console.log(n);
}
Iteration is based on these duck-typed interfaces (using TypeScript type syntax for exposition only):
interface IteratorResult {
  done: boolean;
  value: any;
}
interface Iterator {
  next(): IteratorResult;
}
interface Iterable {
  [Symbol.iterator](): Iterator
}

Support via polyfill

In order to use Iterators you must include the Babel polyfill.

Generators

Generators simplify iterator-authoring using function* and yield. A function declared as function* returns a Generator instance. Generators are subtypes of iterators which include additional next and throw. These enable values to flow back into the generator, so yield is an expression form which returns a value (or throws).
Note: Can also be used to enable ‘await’-like async programming, see also ES7 await proposal.
var fibonacci = {
  [Symbol.iterator]: function*() {
    var pre = 0, cur = 1;
    for (;;) {
      var temp = pre;
      pre = cur;
      cur += temp;
      yield cur;
    }
  }
}

for (var n of fibonacci) {
  // truncate the sequence at 1000
  if (n > 1000)
    break;
  console.log(n);
}
The generator interface is (using TypeScript type syntax for exposition only):
interface Generator extends Iterator {
    next(value?: any): IteratorResult;
    throw(exception: any);
}

Support via polyfill

In order to use Generators you must include the Babel polyfill.

Comprehensions

Removed in Babel 6.0

Unicode

Non-breaking additions to support full Unicode, including new unicode literal form in strings and new RegExp u mode to handle code points, as well as new APIs to process strings at the 21bit code points level. These additions support building global apps in JavaScript.
// same as ES5.1
"𠮷".length == 2

// new RegExp behaviour, opt-in ‘u’
"𠮷".match(/./u)[0].length == 2

// new form
"\u{20BB7}" == "𠮷" == "\uD842\uDFB7"

// new String ops
"𠮷".codePointAt(0) == 0x20BB7

// for-of iterates code points
for(var c of "𠮷") {
  console.log(c);
}

Modules

Language-level support for modules for component definition. Codifies patterns from popular JavaScript module loaders (AMD, CommonJS). Runtime behaviour defined by a host-defined default loader. Implicitly async model – no code executes until requested modules are available and processed.
// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
import {sum, pi} from "lib/math";
console.log("2π = " + sum(pi, pi));
Some additional features include export default and export *:
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.exp(x);
}
// app.js
import exp, {pi, e} from "lib/mathplusplus";
console.log("e^π = " + exp(pi));

Module Formatters

Babel can transpile ES2015 Modules to several different formats including Common.js, AMD, System, and UMD. You can even create your own. For more details see the modules docs.

Module Loaders

Not part of ES2015

This is left as implementation-defined within the ECMAScript 2015 specification. The eventual standard will be in WHATWG's Loader specification, but that is currently a work in progress. What is below is from a previous ES2015 draft.
Module loaders support:
  • Dynamic loading
  • State isolation
  • Global namespace isolation
  • Compilation hooks
  • Nested virtualization
The default module loader can be configured, and new loaders can be constructed to evaluate and load code in isolated or constrained contexts.
// Dynamic loading – ‘System’ is default loader
System.import("lib/math").then(function(m) {
  alert("2π = " + m.sum(m.pi, m.pi));
});

// Create execution sandboxes – new Loaders
var loader = new Loader({
  global: fixup(window) // replace ‘console.log’
});
loader.eval("console.log(\"hello world!\");");

// Directly manipulate module cache
System.get("jquery");
System.set("jquery", Module({$: $})); // WARNING: not yet finalized

Additional polyfill needed

Since Babel defaults to using common.js modules, it does not include the polyfill for the module loader API. Get it here.

Using Module Loader

In order to use this, you'll need to tell Babel to use the system module formatter. Also be sure to check out System.js

Map + Set + WeakMap + WeakSet

Efficient data structures for common algorithms. WeakMaps provides leak-free object-key’d side tables.
// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set

Support via polyfill

In order to support Maps, Sets, WeakMaps, and WeakSets in all environments you must include the Babel polyfill.

Proxies

Proxies enable creation of objects with the full range of behaviors available to host objects. Can be used for interception, object virtualization, logging/profiling, etc.
// Proxying a normal object
var target = {};
var handler = {
  get: function (receiver, name) {
    return `Hello, ${name}!`;
  }
};

var p = new Proxy(target, handler);
p.world === "Hello, world!";
// Proxying a function object
var target = function () { return "I am the target"; };
var handler = {
  apply: function (receiver, ...args) {
    return "I am the proxy";
  }
};

var p = new Proxy(target, handler);
p() === "I am the proxy";
There are traps available for all of the runtime-level meta-operations:
var handler =
{
  // target.prop
  get: ...,
  // target.prop = value
  set: ...,
  // 'prop' in target
  has: ...,
  // delete target.prop
  deleteProperty: ...,
  // target(...args)
  apply: ...,
  // new target(...args)
  construct: ...,
  // Object.getOwnPropertyDescriptor(target, 'prop')
  getOwnPropertyDescriptor: ...,
  // Object.defineProperty(target, 'prop', descriptor)
  defineProperty: ...,
  // Object.getPrototypeOf(target), Reflect.getPrototypeOf(target),
  // target.__proto__, object.isPrototypeOf(target), object instanceof target
  getPrototypeOf: ...,
  // Object.setPrototypeOf(target), Reflect.setPrototypeOf(target)
  setPrototypeOf: ...,
  // for (let i in target) {}
  enumerate: ...,
  // Object.keys(target)
  ownKeys: ...,
  // Object.preventExtensions(target)
  preventExtensions: ...,
  // Object.isExtensible(target)
  isExtensible :...
}

Unsupported feature

Due to the limitations of ES5, Proxies cannot be transpiled or polyfilled. See support in various JavaScript engines.

Symbols

Symbols enable access control for object state. Symbols allow properties to be keyed by either string (as in ES5) or symbol. Symbols are a new primitive type. Optional name parameter used in debugging - but is not part of identity. Symbols are unique (like gensym), but not private since they are exposed via reflection features like Object.getOwnPropertySymbols.
(function() {

  // module scoped symbol
  var key = Symbol("key");

  function MyClass(privateData) {
    this[key] = privateData;
  }

  MyClass.prototype = {
    doStuff: function() {
      ... this[key] ...
    }
  };

  // Limited support from Babel, full support requires native implementation.
  typeof key === "symbol"
})();

var c = new MyClass("hello")
c["key"] === undefined

Limited support via polyfill

Limited support requires the Babel polyfill. Due to language limitations, some features can't be transpiled or polyfilled. See core.js's caveats section for more details.

Subclassable Built-ins

In ES2015, built-ins like ArrayDate and DOM Elements can be subclassed.
// User code of Array subclass
class MyArray extends Array {
    constructor(...args) { super(...args); }
}

var arr = new MyArray();
arr[1] = 12;
arr.length == 2

Partial support

Built-in subclassability should be evaluated on a case-by-case basis as classes such as HTMLElement can be subclassed while many such as DateArray and Error cannot be due to ES5 engine limitations.

Math + Number + String + Object APIs

Many new library additions, including core Math libraries, Array conversion helpers, and Object.assign for copying.
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false

Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2

"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"

Array.from(document.querySelectorAll("*")) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1,2,3].findIndex(x => x == 2) // 1
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) })

Limited support from polyfill

Most of these APIs are supported by the Babel polyfill. However, certain features are omitted for various reasons (e.g. String.prototype.normalize needs a lot of additional code to support). You can find more polyfills here.

Binary and Octal Literals

Two new numeric literal forms are added for binary (b) and octal (o).
0b111110111 === 503 // true
0o767 === 503 // true

Only supports literal form

Babel is only able to transform 0o767 and not Number("0o767").

Promises

Promises are a library for asynchronous programming. Promises are a first class representation of a value that may be made available in the future. Promises are used in many existing JavaScript libraries.
function timeout(duration = 0) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, duration);
    })
}

var p = timeout(1000).then(() => {
    return timeout(2000);
}).then(() => {
    throw new Error("hmm");
}).catch(err => {
    return Promise.all([timeout(100), timeout(200)]);
})

Support via polyfill

In order to support Promises you must include the Babel polyfill.

Reflect API

Full reflection API exposing the runtime-level meta-operations on objects. This is effectively the inverse of the Proxy API, and allows making calls corresponding to the same meta-operations as the proxy traps. Especially useful for implementing proxies.
var O = {a: 1};
Object.defineProperty(O, 'b', {value: 2});
O[Symbol('c')] = 3;

Reflect.ownKeys(O); // ['a', 'b', Symbol(c)]

function C(a, b){
  this.c = a + b;
}
var instance = Reflect.construct(C, [20, 22]);
instance.c; // 42

Support via polyfill

In order to use the Reflect API you must include the Babel polyfill.

Tail Calls

Calls in tail-position are guaranteed to not grow the stack unboundedly. Makes recursive algorithms safe in the face of unbounded inputs.
function factorial(n, acc = 1) {
    "use strict";
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}

// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES2015
factorial(100000)

Thursday, October 4, 2018

Hiểu về ES5, ES2015 và TypeScript

Lời nói đầu

Đã bao giờ các bạn nghe đến các khái niệm ES, ES2015 và TypeScript chưa? Chúng đều liên quan đến một ngôn ngữ mà chúng ta vẫn thường sử dụng để lập trình ra các web động là Javascript. Vậy chúng có gì khác nhau, và chúng ta nên học và sử dụng cái nào? Trước khi đề cập tới sự khác nhau của 3 khái niệm trên chúng ta sẽ đi vào tìm hiểu như thế nào là ES5, ES2015 (hay còn biết tới là ES6) và TypeScript.

ES5 là gì?

ES (ECMAScript) là một ngôn ngữ được chuẩn hóa bởi tổ chức ECMA và được giám sát bởi hội đồng TC39. Và Javascript là cài đặt cụ thể của chuẩn ECMAScript này và trở thành một ngôn ngữ thông dụng trong lập trình web hiện này. ES trải qua rất nhiều phiên bản khác nhau và nó dần được cải tiến để mạnh mẽ và phù hợp hơn. Javascript là cài đặt cụ thể của ES, tuy nhiên nó không gắn liền với một phiên bản ES cụ thể mà có thể bao gồm các phiên bản ES từ cũ đến phiên bản hiện tại. ES5 là phiên bản thứ năm cửa ECMAScript, nó được giới thiệu vào năm 2009. Nó được chúng ta sử dụng nhiều nhất trong nhiều năm để làm chuẩn cài đặt ra Javascript được hỗ trợ hầu hết bởi tất cả các trình duyệt hiện tại. ES5 sử dụng lập trình hàm (Functional Programming) để là tiểu chuẩn cho Javascript, do đó hầu hết hiện này chúng ta vẫn sử dụng Javascript theo cách lập trình hàm là chủ yếu, trong khi các ngôn ngữ khác chạy theo xu hướng OOP. ES5 rất mềm dẻo và dễ dàng để lập trình với các đặc trưng như Scoping, closures, IIFE (immediately-invoked function expression), loosely typed (đặc trưng của Javascript). Tuy nhiên với ES5 chúng ta cũng gặp không ít khó khăn khi lập trình với ES5. Đó là trong quá trình lập trình rất khó để kiểm tra các vấn đề liên quan tới ES5 (hay còn biết tới việc debug), rất khó để debug đối với Javascript, và các công cụ hỗ trợ cho việc này cũng rất ít và khá là phức tạp để sử dụng. Nói tóm lại có thể xem ES5 chính là Javascript mà chúng ta sử dụng hiện nay để lập trình các web động.

ES6/ES2015

ES6 là phiên bản thứ sáu của ECMAScript, nó được ra mặt vào 2015. ES2015 được xem là một bước nhảy lớn của ES5 khi nó được thêm các khái niệm mới, chức năng mới vào cho Javascript. Các tính năng mới giải quyết các vấn đề còn tồn tại và là thách thức của ES5. Các tính năng này là tùy chọn vì vậy chúng ta vẫn có thể sử dụng ES5 để lập trình trong ES2015. Dưới đây là là danh sách cụ thể các tính năng của ES2015
  • arrows
  • classes
  • enhanced object literals
  • template strings
  • destructuring
  • default + rest + spread
  • let + const
  • iterators + for..of
  • generators
  • unicode
  • modules
  • module loaders
  • map + set + weakmap + weakset
  • proxies
  • symbols
  • subclassable built-ins
  • promises
  • math + number + string + array + object APIs
  • binary and octal literals
  • reflect api
  • tail calls
Trong bài viết này mình sẽ không đi cụ thể vào ES2015 mà chỉ đưa ra các khái niệm để hiểu hơn về nó. Với một lượng lớn các tính năng mới ta có thể sử dụng để viết code bằng javascript. Các trình duyệt hiện đại ngày nay cũng đang chạy đua để hỗ trợ các tính năng trên của ES2015. Do là chuẩn mới nên còn một số trình duyệt chưa hỗ trợ ES2015 tuy nhiên ta có thể viết code bằng ES2015 rồi sử dụng các tool để dịch code xuống các phiên bản Javascript cũ hơn. Một tool cụ thể cho việc này là Babe. Như vậy ES2015 cũng chính là Javascript nhưng nó được tiến hóa hơn khi đưa thêm một số khái niệm và tính năng mới vào so với Javascript của ES5.

TypeScript

TypeScript được coi là tập cha của Javascript, sau khi được biện nó sẽ biên dịch ra javascript thuần. Có thể coi TypeScript bao gồm ES2015 cùng với việc thêm vào các khái niệm mới là:
  • Types (Các kiểu dữ liệu)
  • Interface (Giao diện)
Một trong những vấn đề xảy ra khi làm việc đối với Javascript đó là rất khó để xác định lỗi trong quá trình code (có thể gọi là debug). Và TypeScript ra đời để góp phần vào giải quyết vấn đề này. TypeScript không giúp chúng ta code đơn giản đi mà nó giúp ta code an toàn hơn giảm tối thiểu lỗi và phát hiện sớm các lỗi tiềm ẩn. Ngoài ra nó giúp chúng ta code hiểu quả hơn bằng việc sử dụng lợi thế của các tool, editor để xác định các lỗi, tự động sinh và gán các biến, hàm, thuộc tính ...
Như vậy có thể nói TypeScript về mặt bản chất nó cũng là JavaScript tuy nhiên, nó đưa vào một số khái niệm, nguyên tắc giúp ta là việc với JavaScript một cách an toàn, nhanh chóng và hiểu quả hơn

Kết Luận

Dưới đây là bảng so sánh, và kết luận về ES5, ES2015 và TypeScript
Tiêu Chí ES5 ES2015 TypeScript
Bản chất JavaScript JavaScript JavaScript
Sử dụng Viết trực tiếp và chạy không cần biên dịch Cần biên dịch để chạy Cần biên dịch để chạy
Tính năng Sử dụng lập trình hàm để thực hiện viết code Tương tự ES5 tuy nhiên đưa vào một số khái niệm mới Cũng có thể sử dụng lập trình hàm như ES5 và các tính năng của ES2015, tuy nhiên còn sử dụng thêm các types và interface
Tóm lại công nghệ ngày càng thay đổi nhanh và để có thể theo kịp chúng ta cần tận dụng lợi thế của các công cụ giúp ta tiếp thu và ứng dụng công nghệ đó vào quá trình phát triển phần mềm. Dó đó việc Chúng ta chọn ES2015 và TypeScript để lập trình javascript sẽ giúp tăng hiệu quả trong việc code cũng như phát hiện và sửa các lỗi với ngôn ngữ này hơn.

Tài liệu tham khảo

  1. https://johnpapa.net/es5-es2015-typescript/

Monday, September 24, 2018

Canvas


<body>
<canvas id="my-canvas" width="300" height=”300"></canvas>
</body>

const canvas = document.getElementById('my-canvas');
const context = canvas.getContext('2d');

Vẽ đường thẳng

context.beginPath();
context.moveTo(50, 50);
context.lineTo(250, 150);
context.strokeStyle='red';
context.stroke();

Vẽ hình chữ nhật
context.fillStyle = 'red';
context.fillRect(x, y, width, height);

Vẽ hình tròn
context.beginPath();
context.arc(100, 100, 50, 0, 2*Math.PI);
context.stroke();

Vẽ Text
context.fillStyle='red';
context.font='30px Arial';
context.fillText('Hello World',20,50,200);

Ve anh
const background= new Image();
background.src ='images/bg.png';
context.drawImage(background, 0, 0);
trong game loop sử dụng
requestAnimationFrame(update);

Wednesday, September 19, 2018

ES6

var, let, const
es6 không sử dụng var nữa, chỉ sd let và const

arrow function
x=>{x*x;}
tương đương với
function(x){
return x*x;
}

spread operator
... ten_array:
sẽ trải array đó ra các phần tử