ECMAScript 6 — что нового
Table of Contents
Содержание
- let
- const
- Блочные функции
- Выражение деструктурирования
- Значения по умолчанию для аргументов функций
- Остальные параметры вызова функции
- Spread
- Proxy
- WeakMap
- Итераторы
- Генераторы
- Comprehensions
- for…of
- StructType
- Классы (class)
- Модули
- Строки-шаблоны
- Полезные ссылки
let
объявление переменной (аналог var), локальной для блока (внутри if, switch и т.п.).
var a = 5;
var b = 10;
if (a === 5) {
let a = 4; // видна только внутри if
var b = 1; // видна везде внутри функции
console.log(a); // 4
console.log(b); // 1
}
console.log(a); // 5
console.log(b); // 1
Ссылки:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/let,
http://wiki.ecmascript.org/doku.php?id=harmony:let
const
объявляет переменную и присваивает ей значение, которое потом не может быть изменено.
const a = 15; console.log(a); // 15 a = 1; console.log(a); // 15 const b; console.log(b); // undefined b = 1; console.log(b); // undefined
Ссылки:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/const,
http://wiki.ecmascript.org/doku.php?id=harmony:const
Блочные функции
функции, видимые только внутри блока (по аналогии с let).
// обычная функция
[1, 2, 3].map(function (x) { return x
// блочная функция
[1, 2, 3].map {|x| x * x} // [1, 4, 9]
http://wiki.ecmascript.org/doku.php?id=harmony:block_functions,
http://www.slideshare.net/dmitrysoshnikov/falsyvalues-dmitry-soshnikov-ecmascript-6
Выражение деструктурирования
«Разворачивает» объект или массив в последовательность переменных. При этом при разворачивании объекта нужно указать только ключи, которые нужны.
Аналоги: в Python это называется распаковыванием, в php для этого используется функция list.
var a, b, c = [1, 2];
[a, b] = c;
console.log(a, b); // 1, 2
var pt = {x:2, y:-5, z: 1};
var {x, y1, z} = pt;
console.log(x, y1, z); // 2, undefined, 1
console.log(y); // ReferenceError: y is not defined
var {x: n1, y1: n2, z: n3} = pt;
console.log(n1, n2, n3); // 2, undefined, 1
Значения по умолчанию для аргументов функций
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/default_parameters
Остальные параметры вызова функции
Конструкция позволяет получить все параметры вызова функции, для которых не определены аргументы, в виде массива (замена arguments)
function fun1(a, b, ...theArgs) {
console.log(theArgs.length);
}
fun1(); // 0
fun1(5); // 0
fun1(5, 6, 7); // 1
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/rest_parameters
Spread
Распаковывание массива в параметры вызова функции (аналог распаковки кортежа в параметры вызова функции в Python)
let a = [0,1,2,3], o = func(...a);
https://developer.mozilla.org/en-US/docs/Syntax/Spread_operator (на момент написания ссылка ведёт на пустую статью).
Proxy
Кто-то называет это мета-объектами, но, к сожалению, очень это похоже на классы. Лично я надеюсь, что широкого распространения эта функциональность не получит. (Возможно тоже вдохновлено Python-овскими метаклассами, но всё-таки мета-объекты — это же классы).
В примере заменяется метод get объекта, чтобы для несуществующего свойства возвращать 37, а не undefined:
var handler = {
get: function(target, name){
return name in target?
target[name] :
37;
}
}
var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
Подробнее: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Proxy,
http://wiki.ecmascript.org/doku.php?id=harmony:virtual_object_api.
WeakMap
Объект, ключами которого могут быть объекты. Вроде как не боится циклических ссылок внутри себя.
Имеет методы get, set, has, delete.
var wm1 = new WeakMap(),
wm2 = new WeakMap();
var o1 = {},
o2 = function(){},
o3 = window;
wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // любое значение, включая функции и объекты
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // ключами и значениями могут быть любые объекты, даже WeakMaps
wm1.get(o2); // "azerty"
wm2.get(o2); // undefined, т.к. нет такого ключа
wm2.get(o3); // undefined, т.к. там хранится именно это значение
wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (несмотря на значение "undefined")
wm1.has(o1); // true
wm1.delete(o1);
wm1.has(o1); // false
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/WeakMap
Итераторы
Объект, который знает, в каком порядке нужно обходить его свойства, и хранит текущую позицию в обходе. Сводится к методу next.
var lang = { name: 'JavaScript', birthYear: 1995 };
var it = Iterator(lang);
// однажды инициализированный, позволяет получить последовательный доступ к парам ключ-значение объекта
var pair = it.next(); // пара ["name", "JavaScript"]
pair = it.next(); // пара ["birthYear", 1995]
pair = it.next(); // Возбуждается исключение StopIteration
// удобно использовать для обхода объекта
var it = Iterator(lang);
for (var pair in it)
console.log(pair); // каждый раз выводит пару [key, value]
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Iterators_and_Generators.
Частные случаи итераторов — генераторы и прокси-объекты (могут быть).
Генераторы
Упрощённые итераторы. Отличаются от обычных функций тем, что не вычисляют все значения сразу (если, допустим, в результате получается массив), а вычисляет следующее значение после обращения к нему. Это позволяет сберечь память и делать вычисления быстрее (не нужно ждать вычисления всех значений в массиве, возвращаемом из функции, чтобы начать обходить их в цикле; возможно, все значения и не понадобятся).
function fibonacci() {
let [prev, curr] = [0, 1];
while (true) { // бесконечный цикл
[prev, curr] = [curr, prev + curr];
yield curr;
// здесь будет продолжено выполнение после следующего вызова метода next()
}
}
for (let n in fibonacci()) {
// ограничим выборку несколькими значениями
if (n > 1000) {
break;
}
console.log(n); // 1, 2, 3, 5, 8 ... 987
}
console.log('------------');
for (let n in fibonacci()) {
// ограничим выборку несколькими значениями
if (n > 2000) {
break;
}
console.log(n); // 1, 2, 3, 5, 8 ... 1597
}
var fib = fibonacci();
console.log('------------');
console.log(fib.next()); // 1
console.log(fib.next()); // 2
console.log(fib.next()); // 3
console.log(fib.next()); // 5
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Iterators_and_Generators
Comprehensions
Выражения для создания генераторов на основе других генераторов.
Выражения для работы с массивами:
var ar_a = [0, 1, 2, 3],
ar_b = [0, 1, 2, 3],
ar_c;
ar_c = [a + b for (a in ar_a) for (b in ar_b)];
console.log(ar_c); // ["00", "01", "02", "03", "10", "11", "12", "13", "20", "21", "22", "23", "30", "31", "32", "33"]
Выражения-генераторы:
var obj = {a: 1, b: 2, c: 3};
let generator = (x for (x in obj) if (obj[x] >= 2));
for (let i in generator) {
console.log(i);
}
for…of
перебирает элементы коллекции (массивы, итераторы, генераторы).
Работа с массивами:
let arr = [ 3, 5, 7 ];
arr.foo = "hello";
for (let i in arr) {
console.log(i); // "0", "1", "2", "foo"
}
for (let i of arr) {
console.log(i); // "3", "5", "7"
}
Работа с генераторами:
function fibonacci() { // функция-генератор
let [prev, curr] = [0, 1];
for (;;) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
for (let n of fibonacci()) {
// прерываемся после 10
if (n > 10) {
break;
}
console.log(n); // 1, 2, 3, 5, 8
}
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for…of
StructType
const Pixel = new StructType({x:uint32, y:uint32, color:Color}); // Color тоже должен быть StructType
new ArrayType(Pixel, 3);
https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/Using_js-ctypes/Declaring_types
Классы (class)
Синтаксический сахар для функций-конструкторов (с возможным наследованием)
class Animal {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
bark() {
console.log("Woof!");
}
}
// аналог в ES3
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function() {
console.log(this.name);
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = new Animal(null);
Dog.prototype.bark = function() {
console.log("Woof!");
};
Более сложный пример:
class Point extends Base {
constructor(x,y) {
super();
this.px = x, this.py = y;
this.r = function() { return Math.sqrt(x*x + y*y); }
}
get x() { return this.px; }
get y() { return this.py; }
proto_r() { return Math.sqrt(this.px * this.px +
this.py * this.py); }
equals(p) { return this.px === p.px &&
this.py === p.py; }
}
http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes,
http://www.nczonline.net/blog/2012/10/16/does-javascript-need-classes/
Модули
// вот модуль
module DBLayer {
export function query(s) { ... }
export function connection(...args) { ... }
}
// использование модуля
import DBLayer.*; // импортировать все функции из модуля
import DBLayer.{query, connection: attachTo}; // импортировать только нужные функции (причём с возможностью назвать функцию при импорте по-другому)
query(“SELECT * FROM books”).format(“escape | split”);
attachTo(“/books/store”, {
onSuccess: function (response) { ... }
});
Работа с внешними модулями:
// загрузка из файловой системы
module $ = require(“./library/selector.js”);
// загрузка модуля из интернета
module CanvasLib = require(“http:// ... /js-modules/canvas.js”);
// можно использовать напрямую
let rect = new CanvasLib.Rectangle({width: 30, height: 40, shadow: true});
// или импортировать только нужный функционал
import CanvasLib.{Triangle, rotate};
rotate(-30, new Triangle($.query(...params)));
http://wiki.ecmascript.org/doku.php?id=harmony:modules,
http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples,
http://wiki.ecmascript.org/doku.php?id=harmony:module_loaders.
Строки-шаблоны
Используются для замены входящих в них плэйсхолдеров на значения локальных переменных.
Преследуют 4 цели: «многострочные» строки, форматирование строк, HTML-экранирование и локализация.
Синтаксис:
tag`literal${substitution}literal`
Замена:
var sub = 1;
var text = `Some ${sub}First line
Second line`;
// получим "Some 1First line
// Second line"
var total = 30,
msg = `The total is ${total} (${total*1.05} with tax)`;
console.log(msg); // "The total is 30 (31.5 with tax)"
Если переменная для замены не определена, будет возбуждено исключение.
В качестве tag можно использовать произвольную функцию.
http://www.nczonline.net/blog/2012/08/01/a-critical-review-of-ecmascript-6-quasi-literals/ (хорошая подробная статья с примерами и рассуждениями об удобстве использования).
Ссылки для более подробного изучения
- http://wiki.ecmascript.org/doku.php?id=harmony:proposals — официальная wiki ECMAScript
- https://developer.mozilla.org/en-US/docs/JavaScript/ECMAScript_6_support_in_Mozilla — описание в MDN
- http://www.slideshare.net/dmitrysoshnikov/falsyvalues-dmitry-soshnikov-ecmascript-6 — неплохая презентация (слайды)
- http://docs.webplatform.org/wiki/concepts/programming/javascript/future — описание на webplatform (пока почти пусто)
- http://espadrine.github.com/New-In-A-Spec/es6/ — краткое описание всех нововведений
- http://kangax.github.com/es5-compat-table/es6/ — сводная таблица реализации новых возможностей в существующих браузерах и node.js
- http://www.nczonline.net/blog/2012/07/24/thoughts-on-ecmascript-6-and-new-syntax/ — что думает Nicholas C. Zakas по поводу ECMAScript 6
- http://habrahabr.ru/post/151690/ — поддержка ECMAScript Harmony в node.js с примерами
LEAVE A COMMENT
Для отправки комментария вам необходимо авторизоваться.