addconf. Дмитрий Сошников - Будущее ecmascript

62
ECMAScript сегодня и в будущем. Дмитрий Сошников http://dmitrysoshnikov.com

Upload: dmitry-soshnikov

Post on 08-May-2015

10.128 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: AddConf. Дмитрий Сошников  - Будущее ECMAScript

ECMAScript сегодня и в будущем.

Дмитрий Сошников

http://dmitrysoshnikov.com

Page 2: AddConf. Дмитрий Сошников  - Будущее ECMAScript

ES5 : Новый API объектов

Page 3: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Два вида свойств:

Обычные data-свойства (явная ассоциация имени и значения)

Accessor-свойства (геттеры/сеттеры) (неявная ассоциация имени с accessor-функциями)

Page 4: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Работа со свойствами

Object

// работа с атрибутами

.defineProperty

Page 5: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Работа со свойствами

Object

// работа с атрибутами

.defineProperty

// сразу несколько свойств

.defineProperties

Page 6: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Работа со свойствами

Object

// работа с атрибутами

.defineProperty

// сразу несколько свойств

.defineProperties

// анализ атрибутов (дескриптор)

.getOwnPropertyDescriptor

Page 7: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Работа со свойствами

Object

// работа с атрибутами

.defineProperty

// сразу несколько свойств

.defineProperties

// анализ атрибутов (дескриптор)

.getOwnPropertyDescriptor

// список свойств

.keys

.getOwnPropertyNames

// статика

.preventExtensions / .isExtensible

// «опечатывание»

.seal / .isSealed

// «заморозка»

.freeze / .isFrozen

// наследование; прототипы

.getPrototypeOf

.create

Page 8: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Дескриптор data-свойства

{

value: 10, // значение

writable: true, // только чтение?

enumerable: false, // перечислимо в for-in?

configurable: true // можно удалить?

}

Page 9: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Data-свойство

var foo = Object.defineProperty({}, “x” {

value: 10,

writable: true,

enumerable: false,

configurable: true

});

Page 10: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Data-свойство

var foo = Object.defineProperty(,-, “x” ,

value: 10,

writable: true,

enumerable: false,

configurable: true

});

Object.defineProperty(foo, “MAX_SIZE” {

value: 20,

writable: false, // default

enumerable: false, // default

configurable: false // default

});

По умолчанию все атрибуты : false

Page 11: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Data-свойство

var foo = Object.defineProperty(,-, “x” ,

value: 10,

writable: true,

enumerable: false,

configurable: true

});

Object.defineProperty(foo, “MAX_SIZE” {

value: 20,

writable: false,

enumerable: false,

configurable: false

});

foo.z = 30;

Object.defineProperty(foo, “z” ,

value: 30,

writable: true,

enumerable: true,

configurable: true

});

ES3

По умолчанию все атрибуты : false

Создание свойства присваиванием -- атрибуты : true

Page 12: AddConf. Дмитрий Сошников  - Будущее ECMAScript

enumerable: false

ES3

Object.prototype.x = 10;

var foo = {y: 20};

for (var k in foo) {

console.log(k); // y, x

}

ES5

Object.defineProperty(

Object.prototype, “x”, {

value: 10

}

);

for (var k in foo) {

console.log(k); // y

}

Page 13: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Дескриптор accessor-свойства

{

get: function () {...}, // чтение значения

set: function (v) {...}, // установка значения

enumerable: false, // перечислимо в for-in?

configurable: true // можно удалить?

}

Page 14: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Accessor-свойство

Object.defineProperty(foo, “z” {

get: function () {

return this.x + this.y;

},

set: undefined,

enumerable: false,

configurable: false

});

console.log(foo.z); // 30

foo.z = 40; // false, только геттер

console.log(foo.z); // не изменилось - 30

Page 15: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Декларативное объявление геттера/сеттера

var foo = {

x: 10,

y: 20,

get sum() {

return this.x + this.y;

}

};

foo.sum; // 30

Page 16: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Список свойств объекта

// только enumerable-свойства

Object.keys(foo); // *“y”, “z”+

// все родные свойства

Object. getOwnPropertyNames(foo); // *“x”, “y”, “z”+

Page 17: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Фиксация объектов

Статика: запрещает расширение объекта

Object.isExtensible(Object.preventExtensions(foo)); // false

foo.bar = 100; // false

console.log(“bar” in foo); // false

var foo = { x: 10 };

Page 18: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Фиксация объектов

Статика: запрещает расширение объекта

Object.isExtensible(Object.preventExtensions(foo)); // false

foo.bar = 100; // false

console.log(“bar” in foo); // false

Опечатывание (seal): + устанавливает всем свойствам configurable == false

Object.isSealed(Object.seal(foo)); // true

Object.getOwnPropertyDescriptor(foo, “x”).configurable; // false

var foo = { x: 10 };

Page 19: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Фиксация объектов

Статика: запрещает расширение объекта

Object.isExtensible(Object.preventExtensions(foo)); // false

foo.bar = 100; // false

console.log(“bar” in foo); // false

Опечатывание (seal): + устанавливает всем свойствам configurable == false

Object.isSealed(Object.seal(foo)); // true

Object.getOwnPropertyDescriptor(foo, “x”).configurable; // false

Заморозка (freeze): + устанавливает всем свойствам writable == false

Object.isFrozen(Object. freeze(foo)); // true

foo.y = 100; // false

console.log(foo.y); // не изменилось, 20

var foo = { x: 10 };

Page 20: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Получение прототипа объекта

Object.getPrototypeOf(foo)

===

Object.prototype; // true

Page 21: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Прототипное наследование

Object.create(proto, [properties])

// объект-родитель

var foo = {

x: 10,

y: 20,

z: 30

};

Page 22: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Прототипное наследование

Object.create(proto, [properties])

console.log(bar.x, bar.y, bar.z, bar.q); // 10, 20, 30, 40

// объект-родитель

var foo = {

x: 10,

y: 20,

z: 30

};

// наследуем bar от foo

var bar = Object.create(foo, {

q: {

value: 40

}

};

Page 23: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Обычные hash-таблицы без прототипа

var foo = Object.create(null);

alert(foo); // ?

Page 24: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Обычные hash-таблицы без прототипа

var foo = Object.create(null);

alert(foo); // error

Нет метода toString. Объект foo пустой и ни от кого не наследует.

Page 25: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Будущее > ES6

Page 26: AddConf. Дмитрий Сошников  - Будущее ECMAScript

let : переменные в блоках

Page 27: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Блочная область видимости

// ES3

if (false) {

var a = 10;

}

alert(a); // ?

Page 29: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Блочная область видимости

// ES6 Harmony

if (false) {

let a = 10;

}

alert(a); // ReferenceError

Page 30: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Блочная область видимости

// ES3, ES5

var data = [];

for (var k = 0; k < 3; k++) {

data[k] = function () {

alert(k);

};

}

data[0](); // ?

data[1](); // ?

data[2](); // ?

Page 31: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Блочная область видимости

// ES3, ES5

var data = [];

var k;

for (k = 0; k < 3; k++) {

data[k] = function () {

alert(k);

};

}

data[0](); // 3

data[1](); // 3

data[2](); // 3

Page 32: AddConf. Дмитрий Сошников  - Будущее ECMAScript

let : блочная область видимости

ES3, ES5

for (var k = 0; k < 3; k++) {

(function (x) {

data[x] = function () {

alert(x);

};

})(k);

}

data[0](); // 0

ES6

for (let k = 0; k < 3; k++) {

let x = k;

data[x] = function () {

alert(x);

};

}

data[0](); // 0

Page 33: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Деструктуризация или «нестогий pattern-matching»

Page 34: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Деструктуризация : массивы

// для массивов

let [x, y] = [10, 20, 30]; // нестрогий matching

console.log(x, y); // 10, 20

Page 35: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Деструктуризация: объекты

// для объектов

let foo = {value: 100, data: {x: 10, y: 20}};

let {value: v, data: {x: x, y: y}} = foo;

console.log(v, x, y); // 100, 10, 20

Page 36: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Деструктуризация параметров функции

function foo({a: a, b: [x, y]}) {

return a + x * y;

}

let data = {a: 1, b: [2, 3]};

foo(data); // 7

Page 37: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Деструктуризация: обмен переменных

// обмен двух переменных без третьей?

let x = 10;

let y = 20;

[x, y] = [y, x]; // легко

Page 38: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Замена arguments: ”rest” и ”spread”

Page 39: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Объект arguments

// ES3, ES5

function foo(name, /* rest */) {

var rest = [].slice.call(arguments, 1);

var squares = rest.map(function (x) { return x * x});

return squares;

}

foo(“squares”, 1, 2, 3); // [1, 4, 9]

Page 40: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Прощай, arguments

// ES3, ES5

function foo(name, /* rest */) {

var rest = [].slice.call(arguments, 1); // сложно

var squares = rest.map(function (x) { return x * x});

return squares;

}

foo(“squares”, 1, 2, 3); // *1, 4, 9+

Page 41: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Привет, ”rest”

// ES6 aka Harmony

function foo(name, …rest) { // настоящий массив

var squares = rest.map(function (x) { return x * x});

return squares;

}

foo(“squares”, 1, 2, 3); // [1, 4, 9]

Page 42: AddConf. Дмитрий Сошников  - Будущее ECMAScript

А также ”spread”

// ES6 aka Harmony

function bar(x, y, z) {

return x + y * z;

}

let args = [1, 2, 3];

bar(…args); // 7

bar.apply(null, args); // или так, 7

Page 43: AddConf. Дмитрий Сошников  - Будущее ECMAScript

”spread” в pattern-matching

// ES6 aka Harmony

let args = [“data”, 1, 2, 3];

let [name, ...values] = args;

console.log(name); // “data”

console.log(values); // [1, 2, 3]

Page 44: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Сокращенные нотации

Page 45: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Сокращения в деструктуризации

// полная нотация

let {x: x, y: y, z: z} = {x: 10, y: 20, z: 30};

// сокращенная нотация

let {x, y, z} = {x: 10, y: 20, z: 30};

Page 46: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Короткий синтаксис функций. #-функции

// обычные функции

[1, 2, 3].map(function (x) { return x * x; }); // [1, 4, 9]

// #-функции

[1, 2, 3].map(#(x) { x * x }); // [1, 4, 9]

Синтаксически:

• необязательный return;

• # вместо function

Page 47: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Семантика #-функций

// обычная функция

let object = {

start: function () {

setTimeout(function () { this.continue(); }, 500);

},

continue: function () { ... }

};

object.start(); // error

Динамически связываемый this

Решения: var that = this;

.bind(this)

Page 48: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Семантика #-функций

// #-функции

let object = {

start: function () {

setTimeout(#{ this.continue(); }, 500);

},

continue: function () { ... }

};

object.start(); // ok

this автоматом связан с лексическим контекстом

Page 49: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Семантика #-функций

// #-функции

let object = {

start: # (this) {

setTimeout(#{ this.continue(); }, 500);

},

continue: # (this) { ... }

};

object.start(); // ok

Динамический this в #-функциях

Page 50: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Proxy объекты : мета уровень

Page 51: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Proxy-объекты

/* handler – обработчик мета-уровня

* proto – прототип прокси-объекта */

Proxy.create(handler, [proto])

/* handler – мета-обработчик

* call – проксирование вызова

* construct – проксирование конструирования */

Proxy.createFunction(handler, [call, [construct]])

See: http://wiki.ecmascript.org/doku.php?id=harmony:proxies

Page 52: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Proxy-объекты

// original object

let foo = {

x: 10,

y: 20

};

// proxied object

let pFoo = Proxy.create({

get: function (rcvr, name) {

console.log(“get: ”, name);

return foo[name];

},

set: function (rcvr, name, value) {

console.log(“set: ”, name, value);

foo[name] = value;

}

}, Object.getPrototypeOf(foo));

Перехват чтения свойства

Перехват записи свойства

Page 53: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Proxy-объекты

// перехват чтения

pFoo.x; // get: x, 10

// перехват записи

pFoo.x = 100; // set: x, 100

// отображается на оригинале

foo.x; // 100

// proxied object

let pFoo = Proxy.create({

get: function (rcvr, name) {

console.log(“get: ”, name);

return foo[name];

},

set: function (rcvr, name, value) {

console.log(“set: ”, name, value);

foo[name] = value;

}

}, Object.getPrototypeOf(foo));

Мета-обработчик

Page 54: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Callable Proxy-объекты

// original object

let foo = {x: 10, y: 20};

function callTrap() {

console.log(“call”);

}

function constructTrap() {

console.log(“construct”);

}

pFoo(10, 20); // “call”

new pFoo(100); // “construct”

// proxied object

let pFoo = Proxy.createFunction({

get: function (rcvr, name) {

console.log(“get: ”, name);

return foo[name];

},

set: function (rcvr, name, value) {

console.log(“set: ”, name, value);

foo[name] = value;

}

}, callTrap, constructTrap);

Перехват вызова Перехват

конструирования

Page 55: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Proxy : примеры // логгеры (на чтение и запись)

Proxy.create(logHandler(object));

// множественное наследование (делегирующие примеси)

Proxy.create(mixin(obj1, obj2));

// noSuchMethod

Proxy.create(object, noSuchMethod)

// Массивы с отрицательными индексами (как в Python)

let a = Array.new([1, 2, 3]);

console.log(a[-1]); // 3

a[-1] = 10; console.log(a); // [1, 2, 10]

See: https://github.com/DmitrySoshnikov/es-laboratory/tree/master/examples

Page 56: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Система модулей

Page 57: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Модули в ES3, ES5 var Library = (function (global) {

/* save original */

var originalLibrary = global.Library;

function noConflict() {

global.Library = originalLibrary;

}

/* implementation */

function query() { ... }

/* exports, public API */

return {

noConflict: noConflict,

query: query

};

})(this);

1. Создать локальный скоп 2. Функция восстановления 3. Имплементация 4. Публичный интерфейс

Page 58: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Модули в ES3, ES5 var Library = (function (global) {

/* save original */

var originalLibrary = global.Library;

function noConflict() {

global.Library = originalLibrary;

}

/* implementation */

function query() { ... }

/* exports, public API */

return {

noConflict: noConflict,

query: query

};

})(this);

1. Создать локальный скоп 2. Функция восстановления 3. Имплементация 4. Публичный интерфейс

Слишком много синтаксического «шума».

Нужен «сахар».

Page 59: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Модули в ES6 module Library {

export function query(s) { ... }

export function ajax(...args) { ... }

}

import Library.*; // импортировать все

import Library.{query, ajax: xhr}; // импортировать только нужное

query(“#my-element”).hide();

xhr(“/books/store”, {

onSuccess: # (response) { ... }

})

Page 60: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Модули в ES6 module Widgets {

var collection= [ ... ]; // приватное свойство

function registerWidget(name, ...params) { ... } // приватное ?

// внутренний приватный модуль

module Register { ... }

// вложенный публичный модуль

export module Panel {

export function create() { ... }

}

// множественный export

export { register: registerWidget }

}

let panel = Widgets.Panel.create({title: “Options”});

// ошибка, нельзя присвоить export’у Widgets.Panel = false; // ошибка, нет такого export’а let bar = Widget.Window

В дополнение:

Page 61: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Внешние модули в ES6 // на файловой системе

module $ = “./library/selector.js”;

// глобально, из сети; сами определяем имя модуля

module CanvasLib = “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)));

Page 62: AddConf. Дмитрий Сошников  - Будущее ECMAScript

Спасибо за внимание

Дмитрий Сошников

[email protected]

http://dmitrysoshnikov.com

@DmitrySoshnikov