vvscode / tr--The-Past--Present--and-Future-of-JavaScript

:speech_balloon: Translate @rauschma book 'The Past, Present, and Future of JavaScript'

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JavaScript Starter Kit 2012 ad

Прошлое, настоящее и будущее JavaScript

Содержание

Этапы развития JavaScript

Настоящее

Будущее

Эволюция языка

JavaScript как цель компиляции (?)

JavaScript вне сети (?)

Чего не хватает в JavaScript

Заключение

Ссылки

# Прошлое, настоящее и будущее JavaScript**

Axel Rauschmayer**

Опубликовано O’Reilly Media

Пекин ⋅ Кембридж ⋅ Фарнхэм ⋅ Кёльн ⋅ Севастополь ⋅ Токио

Часть 1. Прошлое, настоящее и будущее JavaScript**

За последние несколько лет JavaScript показал впечатляющий рост популярности. Первоначально эта популярность была обусловлена успехом сценариев на стороне клиента, но JavaScript все чаще используется для решения задач общего характера, например для написания серверных и настольных приложений. В данной книге(?) феномен JavaScript рассматривается под тремя углами:

  • Прошлое
  • Настоящее
  • Будущее

В заключение список пожеланий и несколько напутственных слов

Прошлое**

В 1995 году Netscape Navigator был доминирующим браузером, и компания Netscape приняла решение добавить интерактивности на HTML страницы при помощи легковесного языка программирования. Для разработки этого языка был приглашён Брендан Айк (Brendan Eich). Первая версия языка была уже готова спустя 10 дней, в мае 1995. Первоначально язык носил название Mocha, которое сентябре того же было изменено на новое в стиле Netscape - LiveScript. В декабре Netscape и Sun заключили лицензионное соглашение, которое определило окончательное имя языка - JavaScript. В это же время JavaScript был включён в Netscape Navigator 2.0B3.

Имя "JavaScript" намекает на начальное назначение языка: язык Java компании Sun предоставлял крупные строительные блоки для сетевых приложений, в то время как JavaScript должен был служить "клеем", соединяющим эти блоки. Очевидно, что разделение ответственности на стороне пользователя произошло: сегодня JavaScript доминирует в браузере, в то время как Java здесь практически вымерла.

JavaScript формировался под влиянием нескольких языков программирования: диалект Scheme языка Lisp привнёс правила области видимости переменных, включая замыкания. Из языка программирования Self - потомка Smalltalk - было заимствовано наследование, основанное на прототипах (объектно-ориентированное как противопоставление классово-ориентированному).

Поскольку предполагалось, что JavaScript будет выступать как поддержка Java, руководство Netscape потребовало, чтобы синтаксис нового языка был похож на синтаксис Java. Это исключило использование синтаксиса существующих скриптовых языков таких как Perl, Python или TCL. Однако несмотря на то, что синтаксис JavaScript похож на синтаксис Java, это достаточно разные языки. [1]

Стандартизация**

После выхода Javascript компания Microsoft реализовала аналогичный язык с изменённым названием JScript в Internet Explorer 3.0 (август 1996). Netscape решила стандартизировать язык и обратилась в международную ассоциацию по стандартизации Ecma International для введения стандарта. Работа над спецификацией под названием ECMA-262 началась в ноябре 1996 года. Первая редакция ECMA-262 появилась в июне 1997. Из-за того что компания Sun (сейчас Oracle) имела права на торговую марку со словом Java, язык, описываемый стандартом, не мог называться Javascript. Так что было выбрано следующее именование: ECMAScript - название стандарта для языка, его реализации официально называются Javascript, JScript и т.д. Вне официальных документов для обозначения реализация чаще всего используют название Javascript. Текущая версия языка ECMAScript - это 5.1, или говоря иначе ECMA-262 в редакции 5.1. Эта версия так же стала ISO стандартом ISO/IEC 16262:2011.

Язык ECMA-262 развивается под управлением технического комитета №39 ассоциации Ecma(сокращённо ТС39). Его членами являются такие компании как Microsoft, Mozilla, Google которые выдвигают сотрудников для участия в работе комитета - среди других есть три человека: Брендан Эйк (автор языка), Аллен Вирфс-Брок (инженер-разработчик языка JavaScript в Microsoft, один из редакторов стандарта) и Девид Херман. Работа ТС39 включает обсуждение дизайна следующих версий с открытыми источниками, такими как листы рассылки.

Достижение согласия с создание стандарта не всегда даётся легко, но именно благодаря этому Javavscript является действительно открытым языком который поддерживается большим числом производителей ПО и отличается высокой степенью совместимости. Такая совместимость стала возможной благодаря детальной и чёткой спецификации. Например для определения некоторого поведения используется псевдокод. Спецификация дополняется набором тестов, который называется test262. Он проверяет реализации языка на соответствие спецификации. Интересным является то, что ECMAScript на находится под управлением консорциума W3C. ТС39 и W3C сотрудничают везде, где пересекаются Javascript и HTML5.

Исторические вехи JavaScript

JavaScript потребовалось много времени чтобы произвести впечатление. Многие технологии существуют какое-то время, пока не приобретают популярность(?). Эта часть описывает то, что произошло с момента создания JavaScript до настоящего времени. Всегда упоминаются только наиболее популярные проекты, а большинство игнорируются, даже если они были первыми. Вот два примера: часто упоминается Dojo Toolkit, в то время как qooxdoo менее известен, хотя и был создан в тоже время. Также все слышали про Node.js, но никто не помнит про Jaxer, существовавший до него.

**1997 - Dynamic HTML(http://msdn.microsoft.com/en-us/library/ms533044%28v=vs.85%29.aspx).**Dynamic HTML позволяет динамически изменять содержимое и внешний вид интернет-страницы. Это достигалось при помощи манипуляции объектной моделью документа (Document Object Model - DOM): изменение содержимого, стиля, отображение и скрытие элементов и т.д. Dynamic HTML впервые появился в Internet Explorer 4 и в Netscape Navigator 4.

1999 XMLHttpRequest. Это API позволяло скрипту на клиентской стороне посылать HTTP или HTTPS запросы к серверу и получать обратно данные, преимущественно в текстовом формате (XML, HTML, JSON). Было введено в Internet Explorer 5.

2001 — JSON, основанный на JavaScript формат обмена данными. В 2001 Дуглас Крокфорд (Douglas Crockford) дал название и документировал JSON (JavaScript Object Notation) - способ в стиле языка Lisp, использующий синтаксис JavaScript и позволяющий сохранять данные в текстовом формате. JSON использует литералы объектов, массивов, строк, чисел и булевых значение JavaScript для представления структур данных. На пример:

    {

        "first": "Jane",

        "last": "Porter",

        "married": true,

        "born": 1890,

        "friends": [ "Tarzan", "Cheeta" ]

    }

Спустя годы JSON стал популярной легковесной альтернативой XML, особенно когда структура представляет данные без разметки. И действительно, в JavaScript очень удобно работать с JSON.

2004 — Dojo Toolkit, фреймворк для программирования на JavaScript (?). Dojo Toolkit облегчает процесс программирования в целом, предоставляя необходимую инфраструктуру: библиотеку наследования, модульную структуру, API для реализации графических компонентов в стеле настольного приложения и т.д.

2005 — Ajax, приложения подобные настольным, но реализованные на базе браузера. Ajax - это стек технологий, делающий интернет-страницу интерактивной, которая теперь может соперничать с настольным приложением. Впечатляющим примером, того что можно достичь при помощи Ajax, в 2005 году стал сервис Google Maps. Вы можете панорамировать и зумировать катру всего мира, в то время как браузер загружает только видимою её часть. После того как появились Google Maps Джесси Джеймс Гаррет (Jesse James Garrett) отметил, что Google Maps имеет много общего черт с другими интернет-сайтами. Он назвал эти черты "Ajax", сокращённо Asynchronous JavaScript and XML (Асинхронный JavaScript и XML). Двумя краеугольными камнями Ajax являются: во-первых, асинхронная фоновая загрузка (посредством XMLHttpRequest), и во-вторых, динамическое обновление текущей страницы на основании полученных данных (посредством Dynamic HTML). Это было значительное повысило удобство использования в сравнении с необходимости постоянной перезагрузки страницы.

Ajax стал значительным прорывом JavaScript и динамических интернет-приложений. Интересным фактом является то, сколько времени это заняло: составные части Ajax были доступны на протяжении нескольких лет. С приходом Ajax стали популярны другие форматны данных (JSON вместо XML), используются другие протоколы (например, Web-сокеты в дополнение к HTTP), а также возможна двунаправленная связь. Но базовые технологии все те же. Несмотря на это термин Ajax используется все реже и уже практически заменён более комплексным понятием - HTML5 (JavaScript плюс браузер-API).

2005 — Apache CouchDB, JavaScript-ориентированная база данных. Грубо говоря, CouchDB - это JSON-база данных, которая позволяет хранить объекты JSON без определения схемы самой базы данных. А также позволяет определить представления и индексы посредством функций, которые выполняют операции записи и чтения. Следовательно, CouchDB очень хорошо подходит для JavaScript потому, что вы можете работать напрямую с объектами языка. В сравнении с реляционными базами данных, в CouchDB отсутствует потеря соответствия при отображении данных. В сравнении с объектно ориентированными базами данных вы избегаете многих осложнений, потому что сохраняется только данные, без поведения объекта. CouchDB только одна из подобных "NoSQL" баз данных, но имеющая лучшую поддержку JavaScript.

2006 — jQuery, облегчает манипуляцию с DOM. Объектная модель документа (Document Object Model) одна из наиболее болезненных частей разработки клиентского приложения. jQuery делает процесс манипуляции с DOM очень простой, путём абстрагирования от конкретного браузера и предоставления мощного API для выборки и модификации DOM-объектов.

2007 — WebKit положил начало web-приложений для мобильных устройств. Основанный на предыдущей версии KDE(?), WebKit - это HTML- движок, который был анонсирован в апреле 2003 и исходный код которого был открыт в 2005. С выходом iPhone в 2007, он получил статус основы web-разработки для мобильных устройств. Сегодня WebKit является основным движком для Android единственным для iOS, и преобладает на мобильном рынке. Это значит, если вы хотите написать кросс-платформенное мобильное приложение, то web-технологии подойдут для этого лучше всего (если вам не нужны проприетарные функции).

2008 — V8, JavaScript может быть быстрее. Когда Google анонсировал Chrome web browser, одной из его особенностей был быстрый JavaScript-движок, названный V8. Он изменил представление о JavaScript как о медленном и вызвал гонку производителей. V8 является проектом с открытым исходным котом и может использоваться как самостоятельный компонент везде, где может потребоваться встроенный и широко известный язык.

2009 — Node.js, JavaScript на сервере. Node.js позволяет вам создавать сервер, который имеет высокую производительность. Для этого он использует событийно-ориентированный и неблокирующий ввод/вывод и JavaScript. Создатель Node.js Райан Дал (Ryan Dahl) упоминает следующие причины, которые стали основанием для выбора JavaScript:

  • "Потому что JavaScript не изолирован и не имеет собственного API ввода" [таким образом Node.js может ввести свой собственный неблокирующий API.]
  • "Web-разработчики уже используют JavaScript" [JavaScript широко известный язык программирования, особенно в web-контексте.]
  • "API для работы с DOM событийно-ориентированное. Все уже привыкли работать без потоков и циклов событий" [Web-разработчики не боятся обратных вызовов.]"

Дал основывался на существующих событийно-ориентированных серверах и серверном JavaScript(?) (в основном на проекте CommonJS).

Привлекательность Node.js для JavaScript программистов выходит за рамки только возможности использовать знакомый язык; вы получаете возможность использовать один и тот же язык и на клиенте и на сервере. Это позволит вам сделать сложные вещи, такие как отступления для браузеров, которые не могут выполнять достаточно сложный JavaScript код: сборка страницы может происходить на сервере с использованием того же кода, который вы используете на обычном клиенте. (на пример: FunctionSource’s web-сервер, Yahoo Cocktails).

Настояшее**

Благодаря динамическим web-приложениям JavaScript получил свою начальную популярность. Web стал отличной средой для разработки приложений, и было необходимо, чтобы JavaScript был её частью. Как отмечалось выше, с тех пор очень много частей было добавлено в головоломку JavaScript с тем, чтобы сделать его более привлекательным как язык общего назначения. Такое быстрое развитие стало возможным благодаря современным JavaScript движкам. Они позволяют использовать JavaScript-ориентированные базы данных и обмениваться данными с другими системами (например web-сервисами) посредством JSON. Серверный JavaScript позволяет использовать один и тот же языка как на сервере, так и на клиентской стороне. Кроме того Node.js позволяет использовать JavaScript для скриптов сборки и скриптов командной строки. И напоследок, JavaScript, возможно, самый открытый язык программирования из существующих: нет единой группы, контролирующей язык; полная спецификация языка (значение, которой нельзя переоценить); доступно несколько хорошо совместимый реализаций.

Будущее**

Будущее приносит для JavaScript множество интересных решений: ECMAScript.next исправит некоторые причуды языка и добавит новые возможности. JavaScript станет лучшим целевым языком для компилятора (?). Поддержка параллельных вычислений важна, и сейчас рассматривается несколько возможных вариантов. И в завершение, HTML5 становится отличной основой не только для web-приложений, но также для мобильных и настольных приложений.

Эволюция языка**

После ECMAScript 3 был период, когда TC39 разделилась в вопросе дальнейшего развития языка. Встреча в августе 2008 уладила разногласия. Решением стало дальнейшее развитие языка (которое в конце концов переросло в ECMAScript 5), а также реализация новых возможностей. Эти возможности, из-за характера встречи, носили кодовое имя Harmony (Гармония). Список изменений ECMAScript Harmony очень велик для того, чтобы уместить его в одну версию языка. Поэтому существовало другое кодовое название для следующей версии ECMAScript - ECMAScript.next. ECMAScript.next практически станет ECMAScript 6. Требования и цели Harmony описаны на ECMAScript wiki [2]:

Требования:

  • Новые особенности требуют конкретной демонстрации.
  • Сохранить удобство написания кода для случайных разработчиков (?).
  • Сохранить "начни с малого и постепенно прототипируй (?)" природу языка.

Первой целью (из нескольких) является сделать ECMAScript Harmony "лучшим языком для программирования ...".

  1. сложные приложения;
  2. библиотеки (возможно, включающие DOM) совместно используемые этими приложениями;
  3. генераторы кода, ориентированные на новое издание.

Как происходит добавление функционала в новые версии ECMAScript**

Процесс добавления новой функциональности в стандарт выглядит следующим образом. Сначала предложение о нововведении пишется "чемпионом", экспертом в соответствующей области. Это позволяет избежать некоторых ловушек "совместного проектирования". Далее перспективные предложения проходят полевые испытания посредством прототипирования реализации для одного или нескольких браузеров. Если новшество оправдывает себя, его описание добавляется в проект следующей версии ECMAScript [3]. Естественно, принимается во внимание обратная связь по результатам полевых испытаний.

В нескольких следующих разделах будут описаны несколько предложений для будущего ECMAScript. Некоторые из них наверняка будут реализованы (например let), другие все ещё в стадии обсуждения (например объявление классов, новые типы данных). До завершения обсуждения в конце 2013 года ( на момент перевода - первая половина 2014 - стандарт ещё не был принят ) все может поменяться. Нововведения могут измениться или TC39 посчитает, что они вносят слишком большие изменения в ECMAScript и отклонит эти изменения.

Блочная область видимости посредством let and const**

В текущей версии JavaScript переменные имеют область видимости внутри функции - если вы определяете переменную посредством var, она существует в любом месте функции окружающей объявление переменной. В следующем примере, tmp не ограниченна блоком "если-то":

function order(x, y) {
  console.log(tmp); // undefined

  if (x > y) {
    var tmp = x;

    x = y;

    y = tmp;
  }

  return [x, y];
}

ECMAScript.next будет дополнительно иметь блочные области видимости. Их поддержка будет обеспечена ключеывми словами let, const и блочными функциями (объявление фунций которое используется для создания блока видимости). let - версия var с блочной видимостью (“let это новый var“). Переменные, объявленные с этим ключевым словом, будут доступны только внутри блока объявления. Например:

function order(x, y) {
  console.log(tmp); // ReferenceError: tmp is not defined

  if (x > y) {
    let tmp = x;

    x = y;

    y = tmp;
  }

  return [x, y];
}

const это тот же let, но переменные, объявленные с его помощью, могут быть проинициализированны только один раз — они становятся доступными только на чтение. Кроме того, если вы попытаетесь обратиться к ним до присвоения значения, вы получите ошибку. Например:

const BUFFER_SIZE = 256;

Обработка параметров, присвоение

В ECMAScript.next специальный аргумент arguments станет устаревшим. Вместо него будут доступны значения параметров по умолчанию и список аргументов переменной длины:

    // Значения параметров по умолчанию

    function foo(mandatory, optional1=123, optional2="abc") { ... }



    // Список аргументов переменной длины

    function bar(arg1, ...remainingArguments) { ... }

Присваивание может быть разрушающим (destructuring assignment). Такое присваивание сопоставляет значения справа и слева от оператора присваивания, используя простой шаблон соответствия:

// Обмен значения переменных a и b

let [b, a] = [a, b];

// Присваивание значения x переменной horiz

let { x: horiz } = { x: 5, y: 3 };

console.log(horiz); // 5

Разрушающее присваивание очень удобноЮ если необходимо указать необязательные параметры:

// Объявление функции

    function moveBy(point, { x = 0, y = 0 }) {

        ...

    }


    // Вызов

    moveBy(somePoint, { x: 2, y: 7 });

    moveBy(somePoint, {});

Также возможно определить объект с дополнительными параметрами, значения которых могут быть опущены:

    // Объявление

    function moveBy(point, { x = 0, y = 0 } = { x: 0, y: 0 }) {

        ...

    }


    // Вызов

    moveBy(somePoint);

Аналогом списка аргументов переменной длинны является использование спред-оператор(?) (spread operator):

function myfunc(...args) {
  otherfunc(...args);
}

В ECMAScript 5, эта запись может быть переписана следующим образом:

function myfunc() {
  otherfunc.apply(null, arguments);
}

Стрелочные функции

JavaScript использует одну и ту же конструкцию для создания функций, будь это метод объекта или независимая функция. Вас может смутить ключевое слово function в контексте объявления метода. Ещё одна проблема, которая становится заметной позже, это значение this в контексте выполнения (“лексемма this“), вместо использования вашего объекта в качестве this. Для обхода этого ограничения часто используется паттерн сохранения контекста that = this (*):

let jane = {
  name: 'Jane',

  logHello: function(friends) {
    var that = this; // (*)

    friends.forEach(function(friend) {
      console.log(that.name + ' says hello to ' + friend);
    });
  },
};

ECMAScript.next исправляет обе проблемы. Во-первых, более корокая запись при объявлении методов (*). Во-вторых, решает вопрос доступа к контексту arrow functions при помощи лексеммы this (**):

let jane = {
  name: 'Jane',

  logHello(friends) {
    // (*)

    friends.forEach(friend => {
      // (**)

      console.log(this.name + ' says hello to ' + friend);
    });
  },
};

Стрелочная функция получает лексемму this через привязку, так что следующие два примера будут примерно равнозначеными (bind создаст два объекта-функции, а стрелочная функция только один):

    let func = (a, b) => { return this.offset + a + b }

    let func = function (a, b) { return this.offset + a + b }.bind(this);

Тело стрелочной функции так же может быть выражениями, что сделает код более читабельным. Сравните:

    let squares = [ 1, 2, 3 ].map(function (x) { return x * x });

    let squares = [ 1, 2, 3 ].map(x => x * x);

Литералы объектов

Рассматривается несколько вариантов, которые призваны упростить использование объектной ориентации в JavaScript. Литералы объектов претерпят большие изменения:

let name = "foo";

    let obj = MyProto <| {        // оператор прототипирования

        myMethod(arg1, arg2) {           // определение метода

            super.myMethod(arg1, arg2);    // ссылка на родительский объект

        },

        [name]: 123,                 // вычисляемое имя свойства

        bar                       // короткая запись значения свойства

    }

Использованные особенности:

Оператор прототипирования (<|) позволяет указать литерал прототипа, что значительно удобнее, чем использование Object.create() и практически устраняет необходимость в свойстве __proto__, которое является нестандартным и проблематично в использовании.

Определение метода может использовать короткую запись.

Ссылка на родительский объект позволяет ссылаться на свойство, которое было определённо ранее в цепочке прототипов. Поиск свойства начинается в прототипе объекта, в контексте которого определён текущий метод. Заметим, что это способ обращения к свойству родительского объекта работает как для подтипов (если возможно, например, ссылается на метод супертипа, который был изменён), так и для непосредственно построенных цепочек прототипов (?).

Вычисляемый ключ свойства - это способ указать имя свойства посредством выражения (которое особенно полезно для защищённых объектов - см. пример ниже)

Сокращённая запись значений свойств сокращает некоторую избыточность при заполнении литерала объекта значениями. При такой записи bar является сокращением для

bar: bar

Ещё несколько примеров:

{
  foo;
} // аналогично { foo: foo }

{
  x, y;
} // тоже самое, что и { x: x, y: y }

Литералы расширения(?) объекта

Метод, имеющий реализацию в родетильском объекте, но тесно связанный с объектом, в контексте которго он храниться, должен иметь ссылку на реализацию этого метода в объекте-родителе. Синтаксис определения метода, указанный выше, заботится о этом и является предпочтительным способом при создании метода. Литерал расширения объекта гарантирует, что такой синтаксис также может использоваться для добавления новых методов в существующий объект. Пример:

    obj.{

        anotherMethod(x) {

            return super.anotherMethod(10 + x);

        }

    }

Для того чтобы добавить метод "вручную", нельзя использовать присваивание, вместо этого нужно использовать новую функцию Object.defineMethod:

Object.defineMethod(obj, 'anotherMethod', function(x) {
  return super.anotherMethod(10 + x);
});

Ещё пример:

    function Point(x, y) {

        this.{ x, y };

    }

эквивалентная запись:

function Point(x, y) {
  this.x = x;

  this.y = y;
}

Частные свойства

Если вы хотите сделать приватные члены класса то в JavaScript у вас есть два возможнных пути: вы можете поместить их в окружение конструктора, или вы можете хранить их в свойствах со специальными именами (например начинающихся с подчёркивания). Использование окражения конструктора означает, что только методы, которые были добавленные внутри него будут иметь доступ к скрытым данным, но не т.н. публичные методы, которые были добавлены через прототип. Чтобы получить такой доступ они нуждаются в помощи "привелегированных" методов, добавленных к сущности в конструкторе.

Замечание

Следующий пример не является рабочим кодом, но он демонстрирует то, как это работает.

// Скрытые данные: factor

function Multiplier(factor) {
  // Привелегированный метод:

  this.getFactor = function() {
    return factor;
  };
}

// Публичный метод:

MyType.prototype.multiply = function(value) {
  return this.getFactor() * value;
};

Следующий код аналогичен, но скрытые данные хранятся в свойстве _factor. Имя, начинающееся с подчёркивания, означает, что переменная частная. Проблема такого подхода в том, что данные занимают имя свойства в публичной области видимости и загрязняет её тогда, когда просто должны быть скрыты. Кроме того такие частные переменные никак не защищены от доступа из вне.

function Multiplier(factor) {
  // Частная переменная:

  this._factor = factor;
}

// Публичный метод:

MyType.prototype.multiply = function(value) {
  return this._factor * value;
};

Предложение “именование частных свойств” для ECMAScript.next комбинирует преимущества двух подходом и работает следующим образом. В данный момент, имя свойства должно быть строкой. Предложение дополнительно позмоляет использовать явно заданные имена свойств объекта, но они должны быть уникальными в пределах списка свойств:

import Name from '@name';

let factorKey = new Name(); // Создаём объект имени частного свойста

function Multiplier(factor) {
  // частное свойство:

  this[factorKey] = factor;
}

// Публичный метод:

MyType.prototype.multiply = function(value) {
  return this[factorKey] * value;
};

Свойство, чьё имя заданно значением объекта factorKey не может быть найдено ниодним из механизмов рефлексии (Object.getOwnPropertyNames(), for...in, etc.). Единственный способ обратиться к его значениею - обратиться к нему по имени. Таким образом область именования не загрязняется, а данные безопасно скрыты от внешнего воздействия.

Объявление классов

Реализация одинаковых типов через функции-конструкторы в JavaScript достаточно простая, но вот реализация наследования слишком сложная а создание ссылок на объект-родитель выглядит неуклюже.

Сейчас приходится писать такой код:

// Родитель

function Point(x, y) {
  this.x = x;

  this.y = y;
}

Point.prototype.toString = function() {
  return '(' + this.x + ', ' + this.y + ')';
};

// Наследник

function ColorPoint(x, y, color) {
  Point.call(this, x, y);

  this.color = color;
}

ColorPoint.prototype = Object.create(Point.prototype);

ColorPoint.prototype.constructor = ColorPoint;

ColorPoint.prototype.toString = function() {
  return this.color + ' ' + Point.prototype.toString.call(this);
};

Если предложение “максимально минимизированные классы” будет принято, то вместо этого вы сможете писать такой код:

// Родитель

class Point {
  constructor(x, y) {
    this.x = x;

    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

// Наследник

class ColorPoint extends Point {
  constructor(x, y, color) {
    super.constructor(x, y);

    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString();
  }
}

Модули

JavaScript не имеет встроенной поддержки модулей для импорта и экспорта. Вы можете реализовать мощную модульную систему на этом языке, но есть несколько конкурирующих стандартов. Самые важные из них - два: асинхронное объявление модулей (Asynchronous Module Definitions - AMD ) на стороне клиента и модули Node.js (которые очень близки к стандарту CommonJS) на стороне сервера. ECMAScript.next обеспечит общий стандарт модулей для языка. Ниже демонстрируется пример объявления модуля

    import 'http://json.org/modules/json2.js' as JSON;

    import { add, sub } from Math;


    export const HELLO_STRING = JSON.stringify({ hello: 'world' });

    export function total(...args) {

        args.reduce((prevResult, elem) => add(prevResult, elem));

    }

Модули из ECMAScript.next более статичны, чем модульные системы, которые реализованный в JavaScript сейчас. Это обеспечит такие преимущества, как быстродействие, предзагрузку и проверку на этапе компиляции (поиск не связанных переменных и т.п.)

Циклы и итераторы

Для обхода свойств объекта можно использовать цикл for...in. Однако, этот цикл имеет несколько особенностей. ECMAScript.next представит новую систему итераторов, включающую в себя цикл for...of , который исправит недостатки for...in. Например, он пройдёт по всем элементам массива, но не затронет именованные свойства:

let arr = ['hello', 'world'];

for (let elem of arr) {
  console.log(elem);
}

Вывод:

    hello

    world

Перебор свойств объекта также станет удобнее:

let obj = { first: 'Jane', last: 'Doe' };

// Перебор свойств

for (let [name, value] of obj) {
  console.log(name + ' = ' + value);
}

// Перебор имён свойств

import keys from '@iter'; // returns an iterable (see below)

for (let name of keys(obj)) {
  console.log(name);
}

for...of работает в сочетании с интерфейсом итерации: объект может реализовать свой собственный механизм итерации за счёт реализации метода iterate(), который вернёт т.н. объект-итератор (итератор). Объект с таким методом называется итерируемым. Название метода совпадает с именем объекта (??) (см. выше). Итератор имеет один единственный метод next() который при последовательном вызове вернёт все “элементы” итерируемого объекта. Если метод будет вызван больше раз, чем имеющееся количество элементов, то будет выброшено исключение StopIteration. Например:

    import iterate from "@iter";  // имя объекта

    function iterArray(arr) {

        let i = -1;

        // Возвращаемый объект является одновременно и итерируемым и итератором

        return {

            [iterate]() {  // свойство с именем объекта

                return this;  // итератор

            },

            next() {  // метод итерации

                i++;

                if (i < arr.length) {

                    return arr[i]

                } else {

                    throw new StopIteration();

                }

            }

        }

    }

`iterArray()` можно использовать следующим образом:

    for (let elem of iterArray(["a", "b"])) {

        console.log(elem);

    }

Генераторы

Генераторы - это легковесные подпрограммы. При вызове они создают объект, который является обёрткой фукции. Выполнение функции можно продолжать с помощью метода next() и приостанавливать выполнение при помощи оператора yield (внутри функции); yield очень похож на оператор return и обеспечивает возвращаемое значения для вызова next(). Генератор создаётся ключевым словом function* (нельзя использовать ключевое слово generator т.к. это может сломать существующий код). Давайте позьмем обычную функцию iterTreeFunc и превратим её в генератор.

// Проход по дереву вложенных массивов

function iterTreeFunc(tree, callback) {
  if (Array.isArray(tree)) {
    // inner node

    for (let i = 0; i < tree.length; i++) {
      iterTreeFunc(tree[i], callback);
    }
  } else {
    // leaf

    callback(tree);
  }
}

Использование:

    > iterTreeFunc([[0, 1], 2], function (x) { console.log(x) });

    0

    1

    2

iterTreeFunc выглядела бы следующим образом, если бы была написана как генератор:

function* iterTree(tree) {
  if (Array.isArray(tree)) {
    // inner node

    for (let i = 0; i < tree.length; i++) {
      yield* iterTree(tree[i]); // yield recursively
    }
  } else {
    // leaf

    yield tree;
  }
}

Использование:

    > let gen = iterTree([[0, 1], 2]);

    > gen.next()

    0

    > gen.next()

    1

    > gen.next()

    2

    > gen.next()

    // Исключение: StopIteration

Как видно генератор так же является итератором, так что по нему можно проходить циклом:

for (let x of iterTree([[0, 1], 2])) {
  console.log(x);
}

task.js — пример использования генераторов. Если вы хотите посмотреть на интересные приёмы применения генераторов, ва стоит посмотреть на библиотеку task.js Дэвида Германа. Она позволяет писать асинхронный код в синхронном стиле посредством генераторов. Ниже пример кода с подключением task.js (немного отредактированная task.js на GitHub).

spawn(function*() {
  try {
    var [foo, bar] = yield join(read('foo.json'), read('bar.json')).timeout(
      1000,
    );

    render(foo);

    render(bar);
  } catch (e) {
    console.log('read failed: ' + e);
  }
});

Тот же самый код написанный с использованием колбэков гораздо сложнее:

var foo, bar;

var tid = setTimeout(
  function() {
    failure(new Error('timed out'));
  },

  1000,
);

var xhr1 = makeXHR(
  'foo.json',

  function(txt) {
    foo = txt;
    success();
  },

  failure,
);

var xhr2 = makeXHR(
  'bar.json',

  function(txt) {
    bar = txt;
    success();
  },

  failure,
);

function success() {
  if (typeof foo === 'string' && typeof bar === 'string') {
    cancelTimeout(tid);

    xhr1 = xhr2 = null;

    render(foo);

    render(bar);
  }
}

function failure(e) {
  if (xhr1) {
    xhr1.abort();

    xhr1 = null;
  }

  if (xhr2) {
    xhr2.abort();

    xhr2 = null;
  }

  console.log('read failed: ' + e);
}

Больше числовых типов

Все числа в JavaScript являются 64-битными с плавающей точкой (IEEE 754 двойной точности). Из этих 64 бит только 53 доступны для целых чисел. Естественно, когда речь идёт об очень больших числах или очень маленьких приращениях мы сталкиваемся с проблемой ограниченной точности. Но главной проблемой для использования JavaScript в ненаучных вычислениях является то, что он не может обрабатывать 64-битные целые числа, которые очень распространены (например для уникальных ключей ). В этой ситуации встаёт вопрос, как лучше всего добавить поддержку нескольких числовых типов в язык. ECMAScript.next скорее всего сделает это с помощью значимых объектов. Значимые объекты являются объектами (не примитивными значениями), которые неизменны. Тогда как обычные объекты сравниваются по-ссылке, значимые объекты сравниваются по значению (по тому что "внутри" у таких сравниваемых объектов ).

    {} === {}  // false

    uint64(123) === uint64(123)  // true

uint64 является конструктором для 64-битного представления целых чисел. Отсутствие использования оператора new и имя в нижнем регистре являются признаком того, что значимые объекты отличаются от ссылочных объектов. Значимые объекты считаются объектами, что подтверждается конструкцией typeof:

typeof uint64(123); // "object"

Это означает, что существующий код не будет сбит столку если натолкнётся на значимый объект. В отличии от этого, добавление новых примитивных типов в язык скорее всего вызовет появление большого количества проблем. В ECMAScript.next значимые объекты скорее всего будут единственным способом добавить новые числовые типы. Позже программисты смогут добавлять реализации своих собственных типов значимых объектов. Возможно с поддержкой перегрузки операторов. Благодаря тому, что uint64 будут неизменными и сравниваться по значению, JavaScript движки получат возможность напрямую (без обёрток ) работать с 64-битными значениями. Это должно привнести значительные преимущества для производительности. Текущая реализация прототипов [4] в Firefox предоставляет просто uint64 (без-знаковые 64-битные целые) и int64 (знаковые 64-битные целые), плюс корректно работающие операторы (+, *, и т.п.). Так же реализованы литералы вроде -123L для int64(-123).

Например:

> 123L + 7L

130L

Поддержка остальные числовых типов будет добавлена позже.

Двоичные данные

JavaScript все чаще используется в тех областях, где необходима максильно эффективная работа с двоичными данными. Нарпимер: обработка сетевых пакетов, декодирование видео, взаимодествие со встроенным API и процессорами, кодирование и декодированме различных форматов данных. Для поддержки таких вариантов использования языка было внесено предложение о типах бинарных данных:

const Point = new StructType({ x: uint32, y: uint32 });

const Triangle = new ArrayType(Point, 3);

let pt = new Triangle([{ x: 0, y: 3 }, { x: 0, y: 3 }, { x: 0, y: 3 }]);

Point и Triangle - это бинарные типы данных, и могут быть использованы для обработки и генерирования двоичных данных.

Квази-литералы для строковой интерполяции

Строковая интерполяция, такая как шаблоны, очень распространённая операция в JavaScript. Квази-литералы упрощают её использование. Квази-литералы записываются как

quasiHandler`Hello ${firstName} ${lastName}`

Грубо говоря, это всего лишь альтернативный способ вызова функции:

quasiHandler("Hello ", firstName, " ", lastName)

На самом деле вызов обработчика немного сложнее. Среди прочего, обработчик различать статические (например, "Привет") и динамические части (например, Имя). Также обработчик использует кэширование предыдущих вызовов, например когда один и тот же вызов выполняется несколько раз в цикле.

Несколько примеров использования:

"Сырые" строки: строковые литералы состоящие из нескольких строк текста без интерпретации управляющих символов.

let str = raw`This is a text

    with multiple lines.

    Escapes are not interpreted,

    \n is not a newline.`;

Интерпретация простых строк:

alert(`Error: expected ${expected}, but got ${actual}`);

При опущенном имени интерпретатора код выше выполнит обработчик по умолчанию. В Node.js такая же команда будет записана как

alert(util.format('Error: expected %s, but got %s', expected, actual));

Параметризованный литерал регулярного выражения, игнорирующий пробельные символы:

re`\d+ ( ${localeSpecificDecimalPoint} \d+ )?`;

Выше, localeSpecificDecimalPoint, содержащий точку или запятую, будет экранирован непосредственно перед вставкой в регулярное выражение. При этом пробелные символы будут игнорироваться, поэтому Вы можете вставлять пробелы и символы перехода на новую строку для того, чтобы сделать регулярное выражение более читабельным.

Аргументы для языков запросов:

$`a.${className}[href=~'//${domain}/']`;

Подобно примеру с регулярным выражением, className и domain будут вставлены в команду языка запросов и экранированы должным образом.

Локализированные сообщения:

alert(msg`Welcome to ${siteName}, you are visitor

              number ${visitorNumber}:d!`);

Статические части в выражении выше используются для поиска перевода на выбранный в настоящий момент язык. Динамические части будут вставлены в результат после возможной обработки. Флаг :d говорит, что visitorNumber следует отображать, использую десятичный разделитель в соответствии с текущей локалью (Английская локаль - 1,300, Немецкая - 1.300).

Шаблоны:

let myTmpl = tmpl`

    <h1>${{ title }}</h1>

    ${{ content }}

    `;

Обработчик получит версию в виде разобранного шаблона (разделённого на сегменты) и скомпилирует его. Отметим, что {title} является литералом объекта и сокращением от { title: title }.

Прокси

Прокси позволяет Вам поместить обработчик "перед" объектом, для того чтобы перехватить операцию, применяемою к данному объекту. Выглядит это следующим образом:

// target указывает на объект

let proxy = Proxy(target, handler);

При каждой из следующих операций будет выполнен соответствующий метод обработчика handler:

    proxy["foo"]              handler.get(target, "foo", proxy)

    proxy["foo"] = 123        handler.set(target, "foo", 123, proxy)

    "foo" in proxy            handler.has(target, "foo")

    for (key in proxy) {...}  handler.enumerate(target)

Прокси также может быть помещён в цепочку прототипов объекта:

let child = Object.create(proxy);

Операции над child, в прототип которого был передан proxy, очевидно, будут вызывать выполнение соответствущих методов обработчика:

    child["foo"]              handler.get(target, "foo", child)

    child["foo"] = 123        handler.set(target, "foo", 123, child)

    "foo" in child            handler.has(target, "foo")

    for (key in child) {...}  handler.enumerate(target)

Одно из возможных применений - это отслеживание вызова несуществующих методов:

let handler = {
  get(target, name, receiver) {
    return (...args) => {
      console.log('Missing method ' + name + ', arguments: ' + args);
    };
  },
};

let proxy = Proxy({}, handler);

Использование:

    $ let obj = Object.create(proxy);

    $ obj.foo(1, 2)

    Missing method foo, arguments: 1, 2

    undefined

Варианты использования прокси включают такие задачи как:

  • Перенаправление вызова методов другому объекту
  • Создание объектов доступа к базе данных
  • Привязка данных
  • Логирование

Коллекции

JavaScript не имеет подходящих типов коллекций. Поэтому программисты часто используют объекты в качестве карт (?). Но использование объекта в такой роли достаточно сложно. ECMAScript.next предоставит три типа коллекций: Map, Set и WeakMap. Map может использовать произвольные ключи (не только строки):

let map = new Map();

let obj = {};

map.set(true, 1); // key не проеобрадуется в строку!

map.set('true', 2);

map.set(obj, 3);

console.log(map.get(true)); // 1

console.log(map.get('true')); // 2

console.log(map.get(obj)); // 3

console.log(map.has(obj)); // true

console.log(map.has({})); // false

map.delete(obj);

console.log(map.has(obj)); // false

Следующий код демонстрирует использование типа set:

let set = new Set();

set.add('hello');

console.log(set.has('hello')); // true

console.log(set.has('world')); // false

Тип данных weak map представляет собой тип map, который не запрещает сборщику мусора удалять включённые элементы: это касается как ключей так и значений - если на них ссылается только объект типа weak map они будут утилизированны. Ктому же, объект типа weak map нельзя итерировать по ключам, значениям или записям. Вы должны иметь ключ, чтобы получить значение. Это позволит создавать безопасные приложения. Одним из возможных вариантов использования якляется случай, при котором приватные данные содержатся в общедоступной структуре: в таком случае ключами weak map являются экземпляры объектов, а значениями приватная информация. Если экземпляр объекта будет удалён, то и ассоцииронное с ним значение также будет утилизированно сборщиком мусора.

Улучшение API

Было предложено несколько небольших улучшений стандартной библиотеки. Некоторые из них реализуют абсолютно новую функциональность:

    > "abc".repeat(3)

    'abcabcabc'

    > "abc".startsWith("ab")

    true

    > "abc".endsWith("bc")

    true

Другие исправляют причуды языка:

    > Array.of(1, 2, 3)

    [ 1, 2, 3 ]

    > Array.of(3)

    [ 3 ]

    > Number.isNaN("abc")

    false

В конствукци выше исправлены следуюшие неочевидные особенности

    > new Array(1, 2, 3)  // OK

    [ 1, 2, 3 ]

    > new Array(3)  // пустой массив длинной 3

    [ , ,  ]

    > isNaN("abc")  // сначала происходит преведение типа

    true

Компиляция в JavaScript

Цель ECMAScript Harmony(1c) возмоно окажется для кого-то сюрпризом: "Стать лучшим языком для создания генераторов кода". Но действительно, JavaScript все больше и больше становиться целевым языком для компиляторов. Вот несколько примеров:

  • Google Web Toolkit (GWT) позволяет создавать web-приложение полностью на Java. На сервере, Java исполняется напрямую. В то время как клиентская часть компилируется в JavaScript.
  • CoffeeScript - диалект JavaScript, который имеет синтаксис отличный от JavaScript (отсутствуют фигурные скобки и символ точки с запятой), упрощает некоторые задачи.
  • [Traceur] от Google (http://code.google.com/p/traceur-compiler/) компилирует код ECMAScript.next в JavaScript на лету.
  • Emscripten компилирует LLVM байткод в JavaScript. Этот байткод может быть сгенерирован из кода на C и C++, что позволяет множеству интересных проектов на базе C быть запущенными на движке JavaScript. Вот несколько примеров: SQLite (SQL база данных), eSpeak (синтезатор речи), FreeType (движок рендеринга шрифтов). Удивительно, но полученный JavaScript код выполняется достаточно быстро.
  • Минификация программного кода на JavaScript позволяет получить более компактную версию программы без нарушения её функциональности. Для этого используетя удаление комментариев, символов перевода каретки, короткие имена переменных и так далее.

Некоторые даже называю JavaScript "асемблером в web". Но в тоже время, свойства целевого языка для компиляции ECMAScript.next, делают его хорошим языком программирования для решения собственных задач, что ещё более важно. Таким образом языки, которые компилируются в JavaScript, будут сталкиваться с конкуренцией со стороны самого JavaScript.

Скопмилированный JavaScript и исходный язык

Когда исходный язык компилируется в JavaScript, мы хотели бы работать с оригинальным кодом как можно больше. Но увы, это не возможно года дело доходит до выполнения программы:

  • Сообщения исключений ссылаются на строки кода, полученного в ходе компиляции, а не исходной текста.
  • Сообщения в консоли браузера также указывают на скомпилированный код.
  • Отладка возможна только в скомпилированном коде.

Source Maps помогает "оставаться" в коде исходного языка во всех трёх случаях: если файл (where orig is java, cs, etc.) был скомпилирован в JavaScript файл file.js, то Source Map находится в сопутствующем файле file.js.map. В этом файле отражается соответсвие между текстом исходного файла file.js и файла-результата file.orig. Это соответствие используется для отображения в консоли номеров строк файла file.orig и ссылок на эти строки. Работать с отладчиком в исходном языка также будет возможно. Firefox и WebKit уже имеют базовую поддержку Source Maps.

Универсальный язык для компиляции

Некоторые особенности ECMAScript.next делают его ещё более универсальным при компиляции из других языков.

Ограничение роста стека при хвостовой рекурсии. Хвостовой рекурсией называю вызов самой себя, который выполняется в конце тела функции:

function logNumbers(start, end) {
  if (start >= end) return;

  console.log(start);

  logNumbers(start + 1, end); // хвостовой вызов
}

В текущей реализации языка, стек будет расти при каждом вызове функции. Но в этом нет необходимости потому, что в данном случае нет необходимости возвращаться к точку вызова (например, возвращать значение). Большинство функциональных языков ограничивают росте стеку вызова в подобных случаях. Вот предложение, которое позволило бы делать интерпретатору JavaScript делать тоже самое. На самом деле, это сделало бы более привлекательным компиляцию функциональных языков в JavaScript.

More useful features:

  • Improved support for binary data avoids compiler writers being limited by JavaScript’s built-in types.
  • Data parallelism (similar to the River Trail approach described above) is being discussed for Harmony (post ECMAScript.next).

Распаралеливание

Долгое время увеличение скорости вычислений происходило за счёт создания более быстрых процессоров. Но скорость улучшения процессоров уменьшилась. Так что дальнейшее увеличение скорости должно происходить за счёт использования нескольких процессоров в параллельных режимах. Так что если помнить о дальнейшем развитии языка, то в нем должна появиться поддержка параллельной работы. Её очень не просто сделать на должном уровне, но уже предложено несколько перспективных вариантов развития в этом направлении.

(Веб-вокреры)Web Workers [5] - это текущая реализация параллельных вычислений в JavaScript. Её поддерживают все современные браузеры и Node.js. Воркер - это JavaScript код, который выполняется в новом потоке, создаваемом операционной системой, который имеет ограниченный доступ к окружению (например, он не имеет доступа к DOM-дереву документа ). Workers и основной поток могут взаимодействовать только посредством обмена простыми сообщениями, такими как строки или JSON объекты. Все эти ограничения делают механизм вполне устойчивым — каждый поток защищён от проблем распараллеливания вроде блокировок. Следующий код демонстрирует как основной потом создаёт новый процесс, ожидает от него сообщение посредством "слушателя" сообщений и отправляет сообщения в поток (строку"Hello worker!").

var worker = new Worker('worker_code.js');

worker.onmessage = function(event) {
  console.log('Message from worker: ' + event.data);
};

worker.postMessage('Hello worker!');

Код в файле worker_code.js выглядит следующим образом. Он "подписан" на сообщения от основного потока и отправляет ему сообщение "Hello main!".

self.onmessage = function(event) {
  console.log('Message from main thread: ' + event.data);
};

self.postMessage('Hello main!');

Обычный JavaScript работает в том же потоке, что и пользовательский интерфейс. Так что выполнение длительных операций в фоне посредством воркеров сохраняет "отзывчивость" интерфейса. Если воркеру нужно больше потоков, он может создавать новые экземпляры (т.н. подпотоки/subworkers).

WebCL [6] привносит в JavaScript разновидность OpenCL standard [7], который позволяет отправлять задачи нескольким ядрам процессора, включая графический чипсет. В терминах OpenCL - он запускает ядра (куски кода) на устройствах. Каждое устройство имеет один или несколько рабочих модулей, где фактически выполняют вычисления. Задача (ядро + параметры) отправляется устройствам в очередь команд, где они ожидают, пока вычисляющий модуль освободится. WebCL очень гибок. ВЫ можете точно указывать где и как ваш код должен выполняться. Поддерживаются два вида параллельности:

  • Параллельность данных: несколько экземпляров одного и того же ядра запускаются сразу,каждый из них имеет свой набор данных для.
  • Распараллеливание задач: параллельно запускается несколько разных ядер/задач, Похоже на систему выполнения задач в Unix.

С другой стороны WebCL требует много "ручной" работы: Вы самостоятельно должны управлять устройствами и писать код для OpenCL на диалекте C.

River Trail [8] is an experiment by Intel Labs that adds data parallelism to JavaScript, but without having to explicitly control it, as with WebCL. It introduces the new type ParallelArray with transformation methods that are parameterized via a function implementing the transformation (a so-called elemental function). Arrays have similar methods (e.g. Array.prototype.map), but ParallelArray’s methods execute their elemental functions several times in parallel. The following code uses ParallelArray:

var a = new ParallelArray(1, 2, 3);

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

console.log(String(squares)); // [1, 4, 9]

var cubes = a.combine(function(index) {
  return a.get(index) * squares.get(index);
});

console.log(cubes); // [1, 8, 27]

The current River Trail prototype is an extension for Firefox. To distribute the work, it uses OpenCL, which must be installed on the operating system.

Conveniently, one has the option of using a sequential implementation of ParallelArray, in pure JavaScript, if River Trail is not installed.

Создание приложений на JavaScriot не для Web

Постепенно HTML5 становится основой для создания полноценных кросс-платформенных приложений, подобно тому как это происходило с Java.

Мобильные приложения: PhoneGap — PhoneGap - это проект, который позволяет Вам писать мобильные приложения с использованием HTML5. Эти приложения будут выполнятся на семи платформах: iOS (iPhone, iPod touch), Android, Blackberry, webOS, Windows Phone, Symbian, и Bada. Кроме HTML5 API, также существует специальное API для доступа к проприетарным функциям таким как акселерометр, камера и контакты. Зародившееся как web-технология, и поддерживающая мобильные платформы сегодня, HTML5 стал лучшим выбором для создания кросс платформенных мобильный приложений.

Приложение для стационарных компьютеров: Open Web Apps project - наиболее интересным аспектом этого проекта является то, что он поддерживается операционными системами обычный компьютеров: это, в свою очередь, позволяет устанавливать web-приложения как нативное на Windows, Mac OS и Android. Так как приложение выполняется при помощи Firefox, но в своём отдельном процессе. Что выглядит и работает как отдельное приложение. Оно также имеет свои уникальные свойства (настройка, cookies, историю и т.д.), и окно приложения не выглядит как окно браузера. Например, оно не имеет адресной строки.

Эти два фактора обеспечивают WebAPI project более полную совместимость посредством HTML5 APIs. Например:

  • Web-телефония: ответ и удержание звонка.
  • Camera API: доступ к встроенной камере для создания снимков и записи видео. Часть WebRTC, необходима видео связь.
  • API для доступа к WiFi: непосредственно доступные сети, определение уровня их сигнала, имя сети, к которой в настоящий момент подключено устройство и т.д.
  • API для доступа к списку контактов: чтение и изменение встроенной адресной книги устройства.

Все предыдущие решения использовали HTML5 поверх нативного слоя. Но ещё существует операционная система, где HTML5 является нативным (или, по крайней мере, тесно интегрированным с ней). На пример:

  • 2009: GUI слой Palm webOS (в настоящее время Open webOS) основанный на HTML.
  • 2009: [Chrome/Chromium OS] от Google (http://www.chromium.org/chromium-os), которую можно назвать "операционной системой браузера"
  • 2011: [Windows 8] от Microsoft (http://windows.microsoft.com/en-US/windows-8/consumer-preview) сделала JavaScript языком первого класса. Несколько важных приложение написаны на JavaScript, таких как встроенные магазин приложений и email-клиент.
  • 2011: Mozilla’s на основе Gecko проект очень похож на Chrome OS, но нацелена на все мобильные устройства и особенно на мобильные телефоны, в то время как Chrome OS используется на ноутбуках.

HTML5 сильно выигрывает от этого, потому что эти решения продвигают платформу. Если HTML5 - это все, что у вас есть, вы быстро поймёте, что у вас нет нативного API. Его замещение может в будущем стать основой для кросс-платформенного API.

Список пожеланий

В то время, пока разрабатывается множество проектов связанных с JavaScript, все ещё несколько вещей упущено. Эта часть описывает эти моменты.

Хорошая интегрированная среда разработки (EDI). Вещь, которой мне не хватает больше всего - это хорошая EDI. Уже существует несколько EDI, но ни одна из них не работает с JavaScript так хорошо как, скажем, Eclipse с Java (справедливости ради, стоит отметить, что создание и отладка EDI для языка требует времени). Одна из трудностей - это автоматическое определение информации о типе (т.е. какие типы параметров функции обычно принимает). В настоящий момент экспериментируют с новыми способы определения типа. Надеюсь, определение классов устранит множество библиотек, реализующий механизмы наследования, которые сейчас имеет JavaScript. После принятия ECMAScript.next два предложения быть одинаково полезны. Первое - это guards, которое позволяет делать аннотации объявления переменной, параметров и результатов функции, определения свойств. Аннотации требуют соблюдения определённых пользователем инвариантов, включая типы. Пример из данного предложения:

    let x :: Number = 37;

    function f(p :: String, q :: MyType) :: Boolean { ... }

    let o = {a :: Number : 42, b: "b"};

Второе - это множественное наследование. Механизм, который в настоящее время реализован при помощи сторонних библиотек. Доступно множество вариаций этого механизма, известных под названиями "миксины" или "трейты". Существует предложение добавления терейтов в ECMAScript. Грубо говоря, это позволит собирать "класс" из "фрагментов класса" (трейтов).

Следует иметь в виду, что нам не следует просто применять идеи существующих статических IDE к JavaScript; следует взять во внимание динамическую природу JavaScript. Вы можете иметь среду, где вы редко перезапускаете программу, но постоянно изменяете её. Т.о. нам необходимо извлечь урок из динамических сред разработки, таких как Lisp в операционной среде Genera, различные системы Smalltalk и Self.

Объединённые платформы браузера и Node.js. В настоящее время две браузерные платформы JavaScript и Node.js разделяются на два пути: они используют различные системы модулей и их API сильно различаются. Формальные различия будут устранены общей модульной системой следующего ECMAScript.next. Последнее особенно прискорбно потому, что создаётся все больше и больше HTML5 приложений предназначенных для нативного развёртывания, которые имеют больше общего с серверным окружением, нежели с приложение на стороне клиента. Node.js имеет очень востребованный пакетный менеджер (Node Package Manager - npm) и активное сообщество. Многие из npm-пакетов будут также востребованы в браузере. Да, есть некоторые отличия, но я не вижу причины, почему от них нельзя абстрагироваться.

Содействие обновлению до ECMAScript.next Управление версированием языка в сети значительно сложнее нежели для традиционного, который просто устанавливается администратором на рабочую станцию или сервер. Сложности включают в себя:

  1. Новая версия языка должна обеспечивать работоспособность существующего кода: обновление версии языка всегда требует обновление приложений, использующих этот язык. Но несмотря на это существующий код должен оставаться работающим. Для оффлайн языков это более "статично", потому обновление может быть применено тогда, кода приложение будет готово. Для мажорных обновлений довольно частое явление, когда обновление делает приложение нерабочим.
  2. Новый код не может исполнятся во всех браузерах: Когда разработчики переключаются на новую версию, они теряют контроль на тем, на каких движках будет выполняться их код.

Какой способ отслеживания изменений лучший? №1 - Можно добавлять префикс каждой части кода с прагма-индикатором (некоторые метаданные) указывающий на номер версии языка. Очевидным преимуществом является то, что это позволит нам очистить язык. Но есть также и очень важная обратная сторона. Такой подход будет неудобным в использовании, т.к. на странице может присутствовать в разных частях страницы: загружаться из сети, размещаться между тегами script и в HTML атрибутах. В некоторых случаях это только небольшие фрагменты кода. JavaScript-программисты навряд ли согласятся с таким подходом, как показало ограниченное принятие строго (strict) режима ECMAScript 5. Скорее это разделит JavaScript на два диалекта (скажем, ECMAScript 5 и ECMAScript 6), которые скорее всего со времён разойдутся.

Вместо этого TC39 принял предложение названное "Единый JavaScript." Он определяет модули как новый синтаксический контекст, где может использоваться только определённая версия JavaScript. Эти версии содержат минорные изменения: некоторые старые функции удалены, некоторые, валидные ранее (но сомнительные) практики вызывают ошибки. В отличии от этого все новые функции только добавляются в язык и могут использоваться где угодно. Как результат, код, который использует только новые функции и лучшие практики, проще поддерживать между разными контекстами. И старый код (в старом контексте) будет также сохранять свою работоспособность.

ССпособ №2 - напоминания. Поддержка двух версий кода: одной для движка ECMAScript.next, а второй для более ранних версий не является возможной. Кое-что может shim-прослойка реализующая новое API в старых версиях. Разработанное Крисом Ковалом (Kris Kowal) es5-shim является примером такой прослойки, позволяющей использовать множество ECMAScript 5 функций в старых браузерах. Несмотря на это много особенностей ECMAScript.next невозможно реализовать таким образом. Единственным решением является компиляция программного кода на ECMAScript.next в код более старой версии, например ECMAScript 3.

Затем нужно решить выполнять компиляцию на лету (в браузере) или статически (в процессе разработки). Traceur компании Google - это компилятор, который реализует первый подход. Некоторые техники и инструменты разработанные CoffeeScript могли бы помочь в реализации второго.

Библиотеки лучшего стандарта. В сравнении других динамических языков программирования, стандартные библиотеки JavaScript оставляют желать лучшего. Члены TC39 подчёркиваю, что они не разработчики библиотек. Из работа является только основанием для разработки хороших библиотек. После того как появятся хорошие библиотеки, они могут быть стандартизированы. По словам Алана Вайрфс-Брока (Allen Wirfs-Brock):

*>

"Мы остановим преждевременную разработку новой функциональности до момента стандартизации основной части платформы." [Потому что это мешает разработке библиотек языка.] *

Добавление библиотек в ECMAScript.next делает сложным то, что новый функционал может быть реализовано как в самом языке, так и в библиотеке. Многие существующий библиотеки кажутся хорошими кандидатами, для того чтобы быть стандартизированными. На пример:

  • Underscore.js популярная библиотека с большим количеством утилит для работы с объектами, массивами и т.д.
  • XRegExp предоставляет множество улучшений существующего в JavaScript механизма регулярных выражений. Использование квази-литералов сделало бы эту библиотеку более лёгкой для использования, решения, использованные в этой библиотеке, должны быть добавлены в RegExp и литералы регулярных выражений.

Увы, в поле зрения нет комплексных библиотек для структур данных. И, на конец, некоторых API ECMAScript стандартизирован отдельно от ECMA-262. Что позволяет этому API быть добавленным в текущую версию JavaScript не дожидаясь ECMAScript.next. Примером может служить ECMAScript Internationalization API](http://norbertlindenberg.com/2012/02/ecmascript-internationalization-api/):

*>

Спецификация API локализации ECMAScript поддерживает сопоставление (сравнение строк), форматирование, а также форматирование даты и времени, и позволяет приложениям выбирать язык и подстраиваться исходя из их нужд.

Заключение

JavaScript - это разносторонний и гибкий язык. Он определённо будет использоваться в новых сферах, из-за своей привлекательности, как язык широко известный и полностью открытый (открытые стандарты и открытая реализация). Я все ещё смотрю в сторону JavaScript с некоторой неприязнью в основном из-за двух причин: первая - это некоторые концепции (такие как наследование, основанное на прототипах) не совсем обычны. Во-вторых, он имеет некоторые причуды. В обоих случаях решением является обучение людей. Они должны оставить свой ум открытым для необычных особенностей и изучить шаблоны работы с этими причудами. Хороший пример: имитация области видимости программного блока путём использования само выполняемой функции. Текущая версия - ECMAScript 5 - пока останется действующей. Её текущая доля на рынке составляет около 50%. Вайрфс-Брокс предполагает [10], что эта версия станет основной для приложений на JavaScript к середине 2013 года и будет оставаться такой на протяжении 5 лет.

ECMAScript.next - следующая версия JavaScript, должна решить сложные задачи по исправлению "причуд" языка и реализации новый возможностей, сохраняя обратную совместимость. Поэтому в языке всегда будут оставаться некоторые шероховатости, но мы все равно получим более мощный язык с меньшим количеством странностей. Поэтому теперь хорошее время, чтобы быть или стать JavaScript программистом. Экосистема уже процветает, едва появившись.

Источники

Слудующий список послужил источником для данной стоатьи

Об авторе

Доктор Аксель Раушмаер консультант и инструктор по JavaScript, web-технологиям и информационному управлению. Практикующий программист с 1985 года, участвует в разработке web-приложений с 1995, в 2006 провёл свою первую лекцию про AJAX. В 1999 был техническим менеджером интернет стартапа, который позднее стал интернациональным проектом.

Прошлое, Настоящее, и будущее JavaScript

Аксель Раушмаер**

Редактор

Мак Слокум

История редакций 2012-07-20 Певое издание

Copyright © 2012 Аксель Раушмаер

Книги O’Reilly могут быть куплены для образования, бизнеса или продаж в рекламных целях. Онлайн редакции также доступны для изданий (http://my.safaribooksonline.com). Для получения дополнительной информации обращайтесь в наш отдел продаж: 800-998-9938 или corporate@oreilly.com.

Логотип справочника и логотип O’Reilly являются зарегистрированной торговой маркой и принадлежат O’Reilly Media, Inc. Прошлое, Настоящее, и будущее JavaScript является торговой маркой O’Reilly Media, Inc.

Множество обозначений используемых производителями и распространителями их продукции являются обозначениями торговых знаков. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Если такие обозначения встречаются в этой книге, и O'Reilly Media, Inc., было известно о торговой марке, то к обозначению добавляется название торговой марки прописными или начальными буквами.

В то время как все меры предосторожности были приняты в подготовке этой книги, издатель и авторы не несут никакой ответственности за ошибки или упущения, или за ущерб, возникший в результате использования информации, содержащейся в настоящем документе.

O’Reilly Media

1005 Gravenstein Highway North

Sebastopol, CA 95472

2012-08-09T07:56:23-07:00

About

:speech_balloon: Translate @rauschma book 'The Past, Present, and Future of JavaScript'