John Kozlov @orionll read-only
Пользователь
4 апреля 2013 в 21:49

Разработка → Обзор ECMAScript 6, следующей версии JavaScript

Для начала, ликбез и несколько фактов:
  • ECMAScript — это официальный стандарт языка JavaScript (Слово JavaScript не могло быть использовано, потому что слово Java являлось торговой маркой компании Sun) Т.е. JavaScript — это имплементация стандарта ECMAScript.
  • TC39 — комитет, развивающий стандарт ECMAScript и принимающий решения по включению фич в него.
  • ECMAScript стандартов много. Самый популярный из них — ECMA-262.
  • ECMAScript 5 — последняя редакция стандарта ECMA-262 (утвержден в 2009 году).
  • Предыдущие версии стандарта ECMA-262 были (совсем старые не упоминаю):
    • ECMAScript 3 — поддерживается большинством браузеров (утвержден в 1999 году).
    • ECMAScript 4 — не принят в виду слишком радикальных изменений в стандарте. Позднее в июле 2008 году в урезанном варианте (но все же намного богаче, чем ECMAScript 3) вылился в новый проект ECMAScript Harmony.

  • ECMAScript 6 (кодовое имя ECMAScript.next) должен утвердиться до конца 2013 года.


Итак, что же нас ждет в новой версии JavaScript?



Блочная область видимости (block scope)


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

function f(a) {
   if (a < 0) {
      var i = 3;
   }

  console.log(i); // 3
}

f(-1)


В новой версии появится ключевое слово let, которое позволит объявлять переменные с блочной областью видимости:

function f(a) {
   if (a < 0) {
      let i = 3;
   }

   console.log(i); // ReferenceError: i is not defined
}

f(-1)


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


В функциях добавилась возможность объявлять у параметров значения по умолчанию:

function setLevel(newLevel = 0) {
   ...
}

setLevel(); // newLevel = 0
setLevel(5); // newLevel = 5
setLevel(undefined); // newLevel = 0


Именованные параметры функций


В функциях также появилась возможность указывать именованные параметры:

function foo({ from, to = 10 }) {
   ...
}

foo({ from: 1, to: 5 });
foo({ to: 5, from: 1 });
foo({ from: 1 });


Именованные параметры можно комбинировать с обычным (позиционными параметрами):

function foo(positional, { named1, named2 }) {
   ...
}

foo(123, { named1: 'abc', named2: 'def' })
foo(123, { named2: 'def', named1: 'abc' })


Destructuring assignment


ECMAScript 6 позволит деструктуризировать при присваивании:

let { first: f, last: l } = { first: 'Jane', last: 'Doe' };
console.log(f); // 'Jane'
console.log(l); // 'Doe'


Кстати, в примере из предыдущего пункта (Именованные параметры) вы видели пример деструктуризации параметров функции.

Деструктуризация по умолчанию является refutable (не имею понятия, как это переводить). Т.е. если в объекте-источнике присваивания соответствующего поля нету, то выбрасывается ошибка:

let { first: f, last: l } = { first: 'Jane' };  // ошибка


Если же вы не хотите, чтобы ошибка генерировалась, то переменную можно объявить как irrefutable с помощью суффикса ?:

let { first: f, last?: l } = { first: 'Jane' };  // ok
console.log(l);  // undefined


Либо можно дать переменной значение по умолчанию:

let { first: f, last: l = 'Unknown' } = { first: 'Jane' };  // ok
console.log(l);  // 'Unknown'


Значение по умолчанию также срабатывает, если соответствующее поле в объекте-источнике является undefined:

let { a: x = 1 } = { a: undefined }
console.log(x);  // 1


Наконец, если вы хотите, чтобы все переменные были irrefutable, то можно поставить суффикс ? в конце всего шаблона присваивания:

let { foo: f }? = anything;  // всегда ok

В последнем примере переменная f будет инициализирована значением undefined, если anything будет равно undefined, null или не иметь поля foo.

С помощью деструктуризации можно одной строчкой кода поменять значение двух переменных (без всяких tmp):

{ foo: foo, bar: bar } = { foo: bar, bar: foo};


Или ище короче:

[ foo, bar ] = [ bar, foo ];


Классы


В ECMAScript 6 появятся классы:

// Supertype
class Person {
   constructor(name) {
      this.name = name;
   }

   describe() {
      return "Person called " + this.name;
   }
}

// Subtype
class Employee extends Person {
   constructor(name, title) {
      super.constructor(name);
      this.title = title;
   }

   describe() {
      return super.describe() + " (" + this.title + ")";
   }
}


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

let jane = new Employee("Jane", "CTO");
jane instanceof Person; // true
jane instanceof Employee; // true
jane.describe(); // 'Person called Jane (CTO)'


Всего того же можно было добиться с помощью прототипов:

// Supertype
function Person(name) {
   this.name = name;
}

Person.prototype.describe = function () {
   return "Person called " + this.name;
};

// Subtype
function Employee(name, title) {
   Person.call(this, name);
   this.title = title;
}

Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function () {
   return Person.prototype.describe.call(this) + " (" + this.title + ")";
};


Как видите, классы в ECMAScript 6 — это просто синтаксический сахар над конструкторами и функциями.

Классы могут иметь статические методы:

class Point {
   constructor(x, y) {
      this.x = x;
      this.y = y;
   }
   
   static zero() {
      return new Point(0, 0);
   }
}


Приватных полей и методов не будет (по крайней мере, в ECMAScript 6). Однако некоторое сокрытие данных все же появится. Через модули.

Модули


В JavaScript наконец-то появятся модули:

module Math {
   export function sum(x, y) {
      return x + y;
   }

   export var pi = 3.141593;

   // Не видна снаружи
   function internal() {
      ...
   }
}


Импортирование модуля:

import Math.{sum, pi}; 
alert("2π = " + sum(pi, pi));


Можно использовать *, чтобы импортировать всё:

import Math.*; 
alert("2π = " + sum(pi, pi));


Модули можно вкладывать друг в друга:

module Widgets {
   module Button { ... }
   module Alert { ... }
   module TextArea { ... }
   ...
}

import Widgets.Alert.{messageBox, confirmDialog};
...


Модули можно подгружать из веба или через файловую систему:

module JSON = require('http://json.org/modules/json2.js'); // web
import JSON.*;

module File = require('io/File'); // file system

import require("bar.js").y; // file system


Все глобальные переменные в модули являются глобальными только в этом модуле.

Возможны циклические зависимости между модулями.

Цикл for-of


Как вы знаете, цикл for-in в JavaScript итерирует по всем полям объекта (включая наследованных). Т.е. итерироваться по значениям массива можно, но опасно:

let arr = [ "blue", "green" ];
arr.notAnIndex = 123;
Array.prototype.protoProp = 456;

for(var x in arr) {
   console.log(x); // Напечатает blue, green, notAnIndex, protoProp
}


В ECMAScript 6 появится цикл for-of, который решит данную проблему:

for(var x of arr) {
   console.log(x); // Напечатает только blue, green
}


Также, возможно, в язык добавится оператор yield, с помощью которого можно легко и красиво писать кастомные итераторы.

Arrow-функции


В ECMAScript 6 появятся arrow functions:

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


Код выше эквивалентен этому:

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


Arrow-функции немножко отличаются от обычных функций. В первую очередь тем, что в arrow-функциях this привязан к вышестоящему контексту. Т.е.

let jane = {
   name: "Jane",
        
   sayHello: function (friends) {
      friends.forEach(friend => { console.log(this.name + " says hello to " + friend) });
   }
}

jane.sayHello([ 'Mark', 'John' ]);

выведет
Jane says hello to Mark
Jane says hello to John

как и ожидалось. А

let jane = {
   name: "Jane",
        
   sayHello: function (friends) {
      friends.forEach(function(friend) { console.log(this.name + " says hello to " + friend) });
   }
}

выведет:
 says hello to Mark
 says hello to John


Проблема в том, что this из анонимной функции function(friend) { ... }) перекрывает this из окружающего контекста. Для того, чтобы этого избежать, можно использовать старый прием с var self = this или использовать функцию bind:

var jane = {
   name: "Jane",
        
   sayHello: function (friends) {
      friends.forEach(function (friend) {
         console.log(this.name + " says hello to " + friend)
       }.bind(this));
   }
}


Т.е. по сути своей arrow functions — опять же синтаксический сахар над существующими анонимными функциями:

(x, y) => x + y + this.z


есть ничто иное как:

function (x, y) { return x + y + this.z }.bind(this)


Другие отличия arrow-функций от обычных функций:
  • Нельзя использовать arrow-функции как конструкторы (new (() => {}) кинет ошибку)
  • Arrow-функции не могут обратиться к переменной arguments (да и незачем)


В остальном arrow-функции не отличаются от обычных функций. Они поддерживают значения по умолчанию, переменное количество параметров, операторы typeof и instanceof:

typeof () => {}; // 'function'
() => {} instanceof Function; // true


Заключение


Я описал далеко не всё, что появится в новом стандарте ECMAScript 6. И очень возможно, что что-то из того, о чем я написал выше, может измениться или вообще не появиться в стандарте. Тем не менее, все, что я описал, — это не слухи. Это вещи, реально обсуждаемые комитетом TC39. И к концу этого (2013) года стандарт должен быть утвержден.

Ссылки


Большая часть информации взята из блога доктора Axel'а Rauschmayer'a, послушать которого и повидать вживую мне посчастливилось на конференции CodeFest в Новосибирске.

PS. Спасибо 2GIS за организацию конференции!
John Kozlov @orionll
карма
42,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (179)

  • +4
    > или использовать функцию bind

    forEach() можно задавать контекст:
    [10, 20, 30].forEach(function(value, index, array){}, this)
    • +2
      В библиотеках полно API, где можно передавать контекст. Например, computed properties в Knockout JS:

      this.fullName = ko.computed(function() {
          return this.firstName() + " " + this.lastName();
      }, this);
      


      Другое дело, что в одних библиотеках контекст может передаваться так, в других — иначе. И когда работаешь с несколькими либами сразу, то начинаешь путаться. bind же работает всегда одинаково, так что со временем я на него пересел.
      • +6
        forEach входит в JS.
        • +1
          bind() — тоже.
    • 0
      forEach() можно задавать контекст:
      [10, 20, 30].forEach(function(value, index, array){}, this)

      А addEventListener и десятки других, где контекст задавать нельзя?
      • 0
        Конкретно в addEventListener можно задать контекст
        var eventObject = { a: -99 };
        document.addEventListener("click", eventObject);
        eventObject.handleEvent = function(e){console.log(e.type, e, ++this.a)};
        

        Просто приведённый в статье пример с forEach неэффективен, а то, что есть такая функция как bind, должен знать каждый разработчик.
        • +1
          О! Слона-то я и не приметил: «This must be an object implementing the EventListener interface, or simply a JavaScript function».
  • +16
    Аллилуйя! Славься let!
    • –7
      Славься ли? Необходимости в let нет.
      • –1
        А чем let не устраивает?
        • –5
          Тем, что есть var. Зачем ещё и делающий-почти-то-же-самое let?
          • +1
            Ну вот тут описано, чем var может быть опасен
            • +8
              Там описано, чем пренебрежение чтением документации может быть опасно.

              > Pitfall 1
              // Все знают, что
              function ololo(){
              for (var i in array)…
              }

              // То же самое, что
              function ololo(){
              var i;

              for (i in array)…
              }

              > Pitfall 2
              // 1
              for (var i=0; i < (arr.length — 1); i++){
              var func = function(i){
              return arr[i];
              }.bind(null, i);

              result.push(func);
              }

              // 2
              for (var i=0; i < (arr.length — 1); i++){
              var func = (function(i){
              return arr[i];
              })(i);

              result.push(func);
              }

              // 3
              arr.forEach(function(v){
              var func = (function(){
              return v;
              });

              result.push(func);
              });

              И получается, что let вводят, как защиту от дурака, который может случайно оконфузиться в паре случаев. А ещё дурацкие скобки постоянно приходится закрывать… Надо в ECMA 7 это учесть, ага. :)
            • –2
              Дык надо просто вар сделать как лет хотят.
              • +3
                Тогда в старых скриптах возможно появление неожиданных ошибок, приводящих к самым разным глюкам.

                Хорошей практикой чуть позже станет использование let повсеместно, вот и все.
                • –2
                  Я считаю, что разработчикам ecmascript давно пора забить на старые скрипты и сделать всё по уму, как когда-то это сделала Adobe.
                • 0
                  Тогда в старых скриптах возможно появление неожиданных ошибок

                  Оно не просто возможно, а очень даже вероятно, и такая вероятность приближалась бы к 100%. И все же появление в коде let наряду c var несколько усложнит понимание этого кода, пожалуй
                  • –1
                    Выходит новый стандарт и нужен новый контракт. Пусть скажем контейнер будет, что то

                    script type=«text/javascript» language=«javascript» version=«6.0»

                    в случае ошибки искать и думать как обойти, но не выдумывать как сделать совпадение контрактов в разных версиях — все равно ни к чему это не приводит смотрите хотя бы расширение интерфейсов SQL в Java. Просто не нерабочий код и и все…
              • 0
                Уже ответили.
              • –1
                не надо. очень «весело» внутри catch-блока не меть доступа к переменным объявленным в try. а после for-in не иметь возможности узнать, что тело ни разу выполнено не было. var + короткие функции = куда более практично.
                • 0
                  Почему-то в других языках таких проблем нет.
                • 0
                  не надо. очень «весело» внутри catch-блока не меть доступа к переменным объявленным в try. а после for-in не иметь возможности узнать, что тело ни разу выполнено не было. var + короткие функции = куда более практично.
                  Объявлять необходимые переменные на необходимом уровне? Например:

                  // Было 
                  try {
                    let foo = fail();
                  } catch (e) {
                    // foo
                  }
                  
                  // Стало
                  let foo;
                  try {
                    foo = fail();
                  } catch (e) {
                    // foo!
                  }
                  
      • +1
        Не было бы, если бы var работал как let.
  • 0
    А что насчет хвостовой рекурсии?
    • 0
      Похоже, будет
      • 0
        Что еще для счастья надо? Currying
        • 0
          Function.prototype.bind, чем-то не устраивает — свое пишется в несколько строчек.
          • 0
            Частичное применение функции и карринг это разные вещи
            • +1
              .bind — не каррирование, но, повторяю, чем-то не устраивает — каррирование пишется в несколько строчек — кол-во ожидаемых аргументов у функции в length и функции высшего порядка никто не отменял.
              • –1
                Простите, а таки чем bind не карирование?
                • +1
                  Разница в понятиях — частичное применение задает один параметр из N и возвращает функцию от (N-1) параметра. Каррирование — разложение функции от N аргументов на последовательность из N функций от 1 аргумента каждая:

                  var f = function(x, y, z) {
                    console.log([x, y, z]);
                  };
                  
                  // Частичное применение
                  var g = f.bind(null, 54);
                  g(2, 3); // => [54, 2, 3]
                  
                  // Карринг
                  var h = function(x) {
                    return function(y) {
                      return function(z) {
                        f(x, y, z);
                      };
                    };
                  };
                  h(10)(20)(30); // => [10, 20, 30]
                  


                  Или как-то так :)
                  • 0
                    А какой тогда практический смысл в карринге?
                    • –1
                      Function.prototype.curry=function(){
                        var fn=this,args=[];
                        return function cur(){
                          args.push.apply(args,arguments);
                          return fn.length>args.length?cur:fn.apply(this,args)
                          }
                        }
                      Function.prototype.part=function(){
                        var fn=this,args=[].slice.call(arguments);
                        return function(){
                          args.push.apply(args,arguments);
                          return fn.apply(this,args)
                          }
                        }
                      
                      function fn(a,b,c,d){console.log(a+b+c+d)}
                      
                      // каррирование
                      fn.curry()(1)(2,3)(4)             // 10
                      // частичное применение (без смены контекста)
                      fn.part(1).part(2,3)(4)           // 10
                      // .bind
                      fn.bind(null,1).bind(null,2,3)(4) // 10
                      

                      В js практического смысла в каррировании, в отличии от частичного применения, тоже не вижу.
                      • 0
                        А в других языках в чём смысл?
                        • 0
                          Вопрос не ко мне — активно языки с более продвинутой функциональщиной не использовал, может там смысл и есть.
                        • 0
                          Вот пример с каррированием в Ruby:

                          def parse(enum)
                            processor = MetadataProcessor.new
                            reader = ->(dir_path) {processor.read_metadata dir_path}
                            saver  = ->(metadata) {processor.save_metadata metadata if metadata}
                                
                            loop do
                              EM.run_block do
                                enum.portion.each do |dir_path|
                                  # EventMachine вызывает первый коллбэк без параметров, 
                                  # поэтому необходимо обернуть лямбду с параметром в замыкание.
                                  EM.defer(reader.carry(dir_path), saver)
                                end
                              end
                            end
                          end
                          


                          Этот же код без каррирования:

                          def parse(enum)
                            processor = MetadataProcessor.new
                            reader = ->(dir_path) {processor.read_metadata dir_path}
                            saver  = ->(metadata) {processor.save_metadata metadata if metadata}
                                
                            loop do
                              EM.run_block do
                                enum.each do |dir_path|
                                  # EventMachine вызывает первый коллбэк без параметров, 
                                  # поэтому необходимо обернуть лямбду с параметром в замыкание.
                                  reader_closure = ->() {reader.(dir_path)}
                                  EM.defer(reader_closure, saver)
                                end
                              end
                            end
                          end
                          


                          То есть в этом случае каррирование — синтаксический сахар для создания замыкания.
                          • 0
                            Ну это как раз частичное применение функции, bind из javascript:
                            EM.defer(reader.bind(null, dir_path), saver)
                            
                      • 0
                        В целом, это удобный элемент чисто функционального программирования — в той же Scala каррирование реализовано на уровне синтаксиса языка.

                        Я могу ошибаться, но мне кажется что каррирование — это вырожденный случай частичного применения функций или, по крайней мере, может легко через него выражаться. Адепты функционального программирования, поправьте меня :)
                      • 0
                        Переработал, забыл массивы аргументов скопировать, но сути не меняет:)
        • +1
          На вскидку github.com/monolithed/Tuples
  • +4
    Неплохой обзор, но сильно уж краткий — например, про yield (как по мне — одна из основных фишек ES6) — одна строчка, хотя Аксель довольно неплохо тему на квартирнике раскрыл. Про Proxy — вообще ни слова. Про rest и spread ничего…
    • 0
      К сожалению, не был на квартирнике. Если организаторы выложат видео с него, дополню статью
    • 0
      Более того, yield уже есть в FF и принят к разработке в Chrome. Вот и пример хороший есть его использования taskjs.org/
    • +1
      Вот rest и spread действительно нужно добавить в статью, как мне кажется, полезная вещь.
  • 0
    Уже хочу!
  • +26
    «Мы долго пытались навязать мнение, что вам не нужны классы, импорты, блочная область видимость, и часть адептов даже поверила в это на уровне религии. Они убеждали остальных, что в JS есть „классы“, что там всё намного круче, потому что код „можно лепить самому“. А потом мы решили сделать всё, как положено.»
    • –2
      Классы в новом стандарте — синтаксический сахар для прототипов.

      А с let просто пошли на поводу. Ещё теплится надежда, что let отменят.
      • 0
        Да, я в курсе про классы. Но может хотя бы это хоть немного отвадит людей каждый чих описывать в либах и фреймворках.
        • +3
          Думаю, именно с этой целью и вводят «классы». :)
      • +1
        Чем вам let мешает? Вас заставляют им пользоваться? Или все же вопрос религии?
        • 0
          Тем, что он ничем не помогает. Не пришей п**де рукав, называется.

          let не привносит ничего нового, а просто выступает защитой от дурака, который может случайно оконфузиться в паре случаев. Зато у людей теперь будет винегрет: тут let, там var.

          Нелепость какая-то.
      • +3
        Let в драфтовом стандарте с 2011 года (12.2.1 Let and Const Declarations).
        Возможно вы не понимаете всей мощи let?

        var array = [];
        var i = 10;
        
        while (i--) {
           array.push(function() {
              return i;
           });
        }
        
        array[0](); // -1
        array[1](); // -1
        //... -1
        


        Решение:

        var array = [];
        var i = 10;
        
        while (i--) {
           array.push(function(i) {
              return function() {
                  return i;
              };
           }(i));
        }
        
        array[0](); // 9
        array[1](); // 8
        // ...
        


        Теперь с let:

        var array = [];
        var i = 10;
        
        while (i--) {
           let conter = i;
        
           array.push(function() {
              return conter;
           });
        }
        
        array[0](); // 9
        array[1](); // 8
        // ...
        
        


        • +1
          Решение посимпатишнее
          array.push(function(i){
          return i;
          }.bind(null, i));

          Или использовать forEach (http://habrahabr.ru/post/175371/#comment_6098047).

          Я ведь не дурак и знаю JS — его в моей жизни, хоть попой ешь: серверный и клиентский JS, AS, Haxe и даже VBScript. :)
        • 0
          Проблема на самом деле немного глубже, а именно в смешивании функциональной и императивной парадигм, замыканий и мутабельных переменных. Каждый выкручивается как может. В python, например, используется хак lambda i = i: <текст функции>, в С++ — точными указаниями что и как замыкать.
  • –13
    Непонятный гибрид функционального и «типа ООП» языка. Должен быть понятным для тех, кто, скажем так, «не программист» и одновременно приемлем для остальных. Короче, я думаю, что было бы неплохо уже определиться, в какую сторону двигаться — либо понятности, либо удобности.
    • +6
      А вы считаете понятности с удобностью не по пути?
      • –4
        Ну если брать функциональное программирование, то таки да — оно не сразу понятно. ООП более очевидный. Так что да, в данном случае им не по пути :)
        • +4
          Не согласен. Объяснить гипотетическому программисту который умеет программировать исключительно на Лиспе как работает ООП в C++ будет значетельно сложнее чем обучить С++ программиста писать на Лиспе. Очевидность ООП состоит только в том что это по сути общепринятый стандарт на сегодняшний день. А совместить ООП с функциональщиной, да еще и так чтобы было удобно и понятно — вполне возможно. Scala тому пример.
          • 0
            Не знаю, мне кажется, что плохо мешать парадигмы. Раз уж изначально решили делать JavaScript функциональным (а ведь так и есть), то пусть он таковым и будет.
            • 0
              Вы что выдумываете? JS с дня номер раз ООП. Или вы ещё не различаете классовое ООП и прототипное?
            • +2
              Не знаю, мне кажется, что плохо мешать парадигмы

              Наоборот, это очень хорошо. Весь кайф в JS в том, что можно паралельно писать в двух парадигмах.
            • 0
              А теперь давайте вспомним про общеизвестный C++. Как вы думаете, сколько парадигм переплетено в его стандарте?
          • +1
            Насчет лиспа не согласен, на лиспе ООП очень легко реализуется с помощью макросов. Lisp не удачный пример, хорошего Lisp программиста будет легко обучить любому языку. :)
            • 0
              Это точно :) Лисп стоит выучить только за это
  • +9
    Наверное единственное чего мне действительно сейчас не хватает, так это лямбды подобные C#.
    • 0
      Ага вместе с generics =)

      А между тем, можно так

          function(x) x * x
      
      • 0
        Не очень понял вашу строку кода. Поясните?
        • 0
        • 0
          Но со стрелочкой конечно лаконичнее.
          • 0
            Пока только фф поддерживает, как я понял (хотя фф и let поддерживает и остальные ништяки).
            Мне такая запись крайне не нравится, как и операторы условий без блоков. Стрелочка сразу показывает, что это лямбда.
            • +2
              Вы не поверите. По крайней мере, сам на днях наткнулся, тепер с нетерпением жду этой фичи :) Есть даже мысль пока подсесть на TypeScript так как он (в отличии от, например, CoffeeScript) нормально воспринимает обычный синтаксис JS, но одновременно позволяет добавить синтаксический сахар вроде тех же лямбда-функций через стрелочку. А там на ECMAScript6 можно будет код перевести практически без сложностей.
              • +1
                Плюс, как они (MS) и говорили, они старались идентичные возможности с ECMAScript-6 в TypeScript реализовывать одинаково. Что и видно по этой статье.

                И обобщенные типы в TypeScript — со следующей версии! И сразу нормальные типизированные реализации а-ля LINQ и прочее счастье :)
    • +1
      Судя по нововведениям, почему-то показалось, что MS не последнюю скрипку играет в TC39.
  • 0
    Не совсем понимаю, зачем нужны именованные параметры функций в JS. Может кто-нибудь обьяснить?
    • +8
      Для того же что и во всех языках — улучшения читабельности кода. А в чем проблема-то?
      • –4
        JSON же. Зачем его во что-то ещё оборачивать?
        • +1
          Если вы посмотрите внимательнее, увидите что это просто разбор переданных объектов. Если функция объявлена как split(sep=" ", count=0), ее по прежнему нельзя будет вызвать split(count=5).
          • +1
            В других языках именованные параметры используются для того, чтобы не запоминать их порядок, чтобы они были опциональны и чтобы можно было добавить новые в функцию не поломав старый код. В JS с этим справляется JSON. В чем смысл? Просто как сахар над JSON?
            • 0
              Да, сахар. Почему бы нет. Только не JSON, а хеш.
            • +4
              Пожалуйста, не говорите, что в js используется json, это тавтология. Json — это «запись объектов как в js». И в других языках тоже объекты как-то записываются. Тем не менее в них есть именованные параметры. Потому что передача объекта и именованные параметры — не одно и то же. И то, что предлагается сейчас в ecma6 — просто сахар для объектов, да.
              • 0
                Ок, про сахар понял. Вобщем, почти ничего кроме сахара не добавили. Печально.
                • +1
                  Ну как же, деструктуризация, да еще со значениями по умолчанию — вещь. Это не просто сахар, эта штука уберет огромное количество муторного кода.
              • 0
                Не каждый валидный объект в js будет валидным объектом json. Но любой json будет валидным js объектом. Думаю различие уместно
                • 0
                  Нет, не любой (: Строки обрабатываются по-разному.
                  • 0
                    А приведите, пожалуйста, пример. Кроме того, прошу заметить, что я не говорил, что JSON декларация и литерал объекта в JS будут идентичными.
                    • +1
                      С википедии вкратце:

                      Despite the widespread belief that JSON is a JavaScript subset, this is not the case. Specifically, JSON allows the Unicode line terminators U+2028 line separator and U+2029 paragraph separator to appear unescaped in quoted strings, while JavaScript does not.[9] This is a consequence of JSON disallowing only «control characters». This subtlety is important when generating JSONP.
                      • 0
                        Признаю, был не прав. Не знал о таких тонкостях…
  • +2
    Как всегда, много плюсов но немало и минусов.

    Из минусов:
    Почему нельзя имплементировать полноценный Pattern Matching Вместо сложнозапоминаемых принципов типа «Destructuring assignment»?
    Синтаксис именованния аргументов функций перегружен лишней парой скобок.

    Главный вин для меня — сахар для анонимных функций. Для языка где активно применяются колбеки — это маст хэв.
    • +1
      Destructuring assignment
      --видимо, потому что давно отработаны в Мозилле

      Синтаксис именованния аргументов функций перегружен лишней парой скобок.
      --а это потому что они решили совместить позиционные и именованные аргументы

      вин — да, мастхев, ибо коллбеки, куул, окей. Но почему-то они не сделали эквивалентными два синтаксиса.
  • 0
    >Именованные параметры функций
    Судя по синтаксису, литералы объектов теперь передавать нельзя?
    • 0
      Да ладно, это было бы очень глупо. По сигнатуре функции интерпритатор может определить записывать ли объект в переменную полностью или попытаться присвоить его елементы именованным параметрам.
      • 0
        *интерпретатор конечно
  • +13
    Отлично. Правда сделали бы лет 5-6 назад эти изменения, может быть и не нужен был бы CoffeeScript :)
    • 0
      И тем не менее, количество сахара в кофи превосходит новую ECMA… я даже затрудняюсь предположить, во сколько раз.
      • +2
        Иногда слишком сладко — тоже плохо. Я вот смотрю на ES6 и понимаю, что это как раз то, что надо. Уже просто не могу дождаться.
        • 0
          Зачем ждать? Вроде ж уже есть компиляторы ES6. Даже с поддержкой Source Maps.
          • 0
            А поддержка IDE?
            • 0
              Для Sublime вроде что-то было. Но не юзал, к сожалению, нет возможности.
              • 0
                вроде что-то было

                Что-то вроде — это не достаточно.
                Да и текстовый редактор — не айс, я к WebStorm привык. Жду, когда в нём появится.
                • 0
                  Да, согласен, Sublime дело вкуса.
                  Сходу нагуглил. Хотя опять же, не имел с этим дело, мало ли что там написано )))
                  • 0
                    Пока сырое(
  • 0
    irrefutable = отказоустойчивый, безоговорочный?
    • +4
      Безоговорочная деструктуризация? :)
      • +3
        Сегодня на заседании правительства Владимир Владимирович Путин объявил о безоговорочной деструктуризации...

        Звучит! Пафоса, хоть лопатой греби! :)
    • 0
      Безошибочные присваивания и отказочувствительные (потенциально приводящие к исключениям).
  • –8
    зачем это все? js, как язык, коряв от рождения, но он популярен благодаря постоянству и как следствие — выдающейся совместимости. новые навороты, не несут ни чего оригинального — все это есть в нормальных языках и даже больше — но сводят все преимущества js на нет.
    • +3
      Предлагаете прекратить развитие языка?
  • –3
    Smells like Ruby.
    • 0
      Да нет. Мне например многие концепции, на первый взгляд, тоже показались «скопированными», но из Питона. На самом деле многие старые концепции в современных языках (особенно интерпретируемых) стают общепринятыми, а новых идей как то не очень много… Отсюда и дежавю.
  • 0
    Спасибо за шикарный обзор и шикарную новость! Славься JavaScript :)
  • +1
    Ура! Классы же!
    • +2
      Это синтаксический сахар, под капотом там прототип.
      • 0
        Это ясно. Но это скорее хорошо, чем плохо. Порог входа заметно упал. Я когда только начинал разбираться никак не мог понять модель ООП с прототипами. Теперь новичкам будет проще.
        • +2
          Да, для этого все и создается. Сейчас нелюбовь к JS только из-за непонимания особенностей. С классами все проще.
          • 0
            До поры до времени, пока не начнёшь углубляться.
        • 0
          Чем проще? Что будут и прототипы и классы? :)
          • 0
            Тем, что можно про прототипы изначально вообще не думать. Есть класс, у класса есть методы. Этого достаточно, чтобы начать.
            • 0
              Ну так, чтобы более-менее сносно пользоваться языком и понимать чужой код, всё равно прийдётся и прототипы и классы изучать.
              • 0
                Конечно прийдется. Тут смысл в том, что новичку проще сначала увидеть то, что он уже знает в языке и разобраться в чем отличия от других языков. А уже затем познавать особенности языка, вроде прототипов. Когда начинаешь изучать язык, и нет ничего знакомого — очень сложно начать. Просто не понятно с чего.
  • +2
    В функциях добавилась возможность объявлять у параметров значения по умолчанию

    Ура! Прощай экстенд в конструкторах!
  • 0
    Что там с for-of для объектов?
    А то в Firefox & Co только вот такое работает:
    for (var [, value] of Iterator(obj))
    

    Но удобный for each...in все равно хотят убрать. :(
  • +14
    ECMAScript — это официальный стандарт языка JavaScript

    ECMAScript — это язык программирования, а стандарт это ECMA-262!

    ECMAScript стандартов много. Самый популярный из них — ECMA-262.

    Стандарт один, редакций редакций четыре (не считая драфт).
    Однако если вы все-таки имели ввиду ECMA-*, то не забывайте C# (ECMA-334)!

    Предыдущие версии стандарта ECMA-262 были: ECMAScript 3, ECMAScript 4

    Да ладно?

    ECMA-262 1st edition,

    ECMA-262 2nd edition

    ECMA-262 3rd edition

    ECMA-262 5th edition


    Ну и на вскидку:
    ECMA-262 6th edition


    ECMAScript 6 (кодовое имя ECMAScript.next) .

    Следовало бы разьяснить чем отличается Harmony от ECMAScript.next:

    Как сказал Brendan Eich: «ES.next (the first Harmony-era JS standard)»

    Так как планы по реализации Harmony были очень амбиционзными и часто пересекались с Strawman, было решено разделить разработу на две рабочии группы ECMAScript.next и Harmony.

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

    должен утвердиться до конца 2013 года

    Откуда такая информация?

    В текущей версии JavaScript присутствует функциональная область видимости

    Вам следует ознакомиться с разделом 10.2 Lexical Environments специкации

    Также следовало бы упомянуть о том что некоторые вещи из ES6 уже доступны в FF и Chrome, а также существет несколько полифилов, один из них мой

    Ссылки к прочтению:
    http://wiki.ecmascript.org/doku.php?id=harmony:proposals
    http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts
    • 0
      > ECMAScript — это язык программирования, а стандарт это ECMA-262!
      Ну тогда ECMAScript — это семейство стандартов с различными редакциями. Есть, например, еще ECMA-357 — ECMAScript for XML

      > Да ладно?
      Я просто не весь список написал

      > Откуда такая информация?
      Из того же блога. Кроме того Аксел перед аудиторией в полтысячи человек обещал, что стандарт будет принят до конца этого года
    • 0
      Стандарт один


      Есть стандарт ISO, возможно еще какие-то.

      Откуда такая информация?


      Из интернета, сами ребята из TC39 неоднократно об этом говорили, по крайней мере в мейлинг-листе. В последнее время, правда, все чаще звучат 2 даты:

      — конец 2013 — feature freeze
      — конец 2014 — финальная редакция.
      • 0
        Блин, как долго ждать(
        • 0
          Ждать браузерных вендоров еще дольше!
          • +2
            Ждать долго только осла, остальные подхватят довольно быстро нововведения.
      • 0
        — конец 2013 — feature freeze

        Есть инфа по этому поводу?
        • +1
          Так фичи заморозили. Все новое идет в proposals ECMAScript 7+, а по 6 доводят что есть. С января месяца из изменений внесено разве что:
          > Возможность передачи нескольких объектов-источников в Object.assign
          > Добавлен итератор для arguments (спрашивается, зачем, если в ES6 arguments не рекомендуется использовать?)
          > Установлены одинаковые аргументы map-коллбэка Array.from как для итерируемых, так и для array-like объектов
          • 0
            — конец 2014 — финальная редакция

            А по этому поводу как прогресс?
            • +1
              Самому интересно.
              Может где более конкретно и проскакивала, но не видел. На свежих на выступлениях членов TC39 — тот же конец 2014. В заметках по последнему собранию проскочила такая фраза, правда она выдрана из контекста:
              September is the end, otherwise we risk delaying for another 6 months. The final reviewing needs to be done between now and July.
            • 0
              Тоже хороший. Есть уже 24 драфт, и по релизнотам там только фиксы шероховатостей. И так уже последние месяца 3-4. Можно смело читать-изучать.
              • 0
                А браузерьі как прогресс?
                • 0
                  Вот: kangax.github.io/compat-table/es6/

                  Только не обольщайтесь насчет Proxy API в Firefox — там старый вариант.

                  Из любопытного: Map, Set и WeakMap есть в IE11.
                  • 0
                    Ну прокси такой штукой можно поправить. Правда все равно пока разве что играться с ними стоит…
                  • 0
                    Шо ж за халепа то с Хромом? Ни деструктивного присваивания, ни классов, ни реста, ни стрелочньіх функций, ни итераторов, ни фор-оф =(( Я решил, что когда актуальньіе версии Фокса и Хрома будут на Екма6 — перейду на него, а для старья буду использовать транслятор, но браузерьі что-то пока вообще не спешат.

                    пс. Прокси не интересна, т.к. слишком сложна, боюсь будет слаба в плане оптимизаций и плохо поддерживаться средами и тяжко ходить дебагером.
                  • 0
                    В WeakMap в IE11 в качестве ключа нельзя frozen-объекты использовать

                    Пример
                    var w = new WeakMap;
                    
                    // Try to insert freezed object
                    var obj = {foo: 42};
                    Object.freeze(obj);
                    
                    // -- Check
                    obj.bar = 101;
                    console.log(obj.bar); // undefined
                    
                    // -- Insert to WeakMap
                    w.set(obj, 'baz');
                    console.log(w.get(obj)); // !!! undefined
                    
                    
                    // Try to insert regular extensible object
                    obj = {foo: 42};
                    
                    // -- Check
                    obj.bar = 101;
                    console.log(obj.bar); // 101
                    
                    // -- Try to insert to WeakMap
                    w.set(obj, 'baz');
                    console.log(w.get(obj)); // "baz"
                    


                    В Firefox все нормально.
              • 0
                Вот рассказал бы кто — будет возможность создания кастомных итераторов? Я имею ввиду не генераторы, а произвольные объекты которые можно передавать в оператор for..of.

                Сейчас в Фаерфоксе такое можно делать, определяя у объекта метод "@@ iterator" (т.е. внутреннее имя этого метода в спецификации), но обязательность этой возможности вроде бы не задекларирована. Знает ли кто-нибудь об этой возможности?
                • 0
                  Аналогично Firefox, только вместо строки "@@iterator" символ Symbol.iterator, тык.
                  • 0
                    Но Symbol пока что даже в Firefox не доступен?
                    • 0
                      В свежем v8 доступен. Symbol есть, for-of есть, а Symbol.iterator отсутствует.
  • 0
    Про yield — V8 JavaScript Engine Issue 2355: Implement generators принято на Status: Accepted
  • +1
    неслабенькое расширение…
  • 0
    … В ECMAScript 6 появятся классы…
    … В JavaScript наконец-то появятся модули…

    Расплакался от счастья…
    • 0
      В чем же суть несогласия с радостью по поводу этой новости? Кому-то нравится пользоваться тегом <script /> или костылями для подключения модулей? Кому-то не нравится, что когда-нибудь станет возможной реализация наследования с красивым синтаксисом? Я имею в виду веб-разработку, конечно.
  • –1
    Синхронный require? В событийно-ориентированном языке? В условиях, когда браузер не может дальше разбирать ДОМ-дерево, пока не выполнен скрипт? Вы смеётесь что ли?
  • 0
    > ECMAScript 6 позволит деструктуризировать при присваивании:

    У Фленагана это называлось присваивание с разложением, если мне память не изменяет (в русском варианте книги, ок)
  • 0
    А есть уже реализации? Или пока только стандарты?
    • 0
    • 0
      Если убрать типы из TypeScript то его можно использовать как ES6 с компиляцией в ES3 в отличии от traceur-compiler который ES6->ES5
  • 0
    очень крутой
  • +5
    От появления require() в ES6 нетрудно прийти в ужас.

    Потому что в Node.js этот оператор ужé существует и означает нечто другое.

    Да и в RequireJS этот оператор также существует и означает нечто другое.

    Обратная несовместимость грядёт.

    От такой новости волосы дыбом должны стать на голове!
    • 0
      Это не оператор, а функция.

      Судя по синтаксису, require работает практически также как в ноде (вопросы вызывают только правила записи идентификатора модуля при загрузке из файловой системы), а import просто выкладывает в глобальную область видимости части загруженного «модуля» (судя по всему, обычного JS-объекта).

      RequireJS никто не мешает перекрыть эту функцию по собственному усмотрению и использовать внутри себя оригинал, например.

      В общем, введение модулей в таком стиле нанесет минимум повреждений существующим подходам. Да, возможно что-то придется поправить по-мелочи, но про «волосы дыбом» — это перебор )
      • –2
        Поясню здесь, что термин «оператор» я употребил в значении из вон той статьи, означающем скорее «инструкция», нежели «операция». В этом значении функция — частный случай оператора.

        Если можно будет require() перекрыть, тогда ещё слава Богу.
    • 0
      По поводу require() это верно подмечено (Node.JS community негодуэ).
      И еще есть ряд вопросов по именованным параметрам функций, меня например вводит в ступор
      function foo({ from, to = 10 }) { ... }
      когда я пытаюсь понять, что то что я вижу, это не то что есть на само деле.
      { } в самой основе языка — литеральное описание анонимного объекта(до присвоения конечно)
      А в данном случае как понимать, то что заключено в { }
      Что я в итоге в теле foo получу, переданное в { } перекочуют как поля в this, а если у меня подразумевается вложенность в объекте, аля
      function foo({ from, to = 10 }) { ... } foo({ from: {bar:2, foo: 3}, to: 5 });
      мне это как описывать?
      • 0
        Подробно изучите возможности деструктуризации (destructuring assignment), именно она применяется для разбора параметров.
        В данном случае в теле функции foo будут доступны две переменные — from и to, значениями которых будут {bar:2, foo: 3} и 5 соответственно.
  • 0
    Очень радует аккуратный подход к введению новых фич.

    В harmony местами такое предлагают, что за судьбу JS страшно становится.
    Рад, что в итоге добавляется только самое лучшее и продуманное.
  • +1
    Есть пара вопросов:
    — А модули — не сахар к чему то существующему? Настоящие «модули»?
    — И что значит «подгружать из веба»? По спецификации в самом языке какое то встроенное (кроссбраузерное, стандартизированное) средство будет для обращения к удаленному хосту?

    Немного пугает еще ожидаемая заморочка с require(), как выше уже упомянул Mithgol.

    И интересно, почему arrow-функции не могли назвать более привычным именем «lambda-function» :)
    • 0
      >> А модули — не сахар к чему то существующему? Настоящие «модули»?

      Скорее сахар. Например, пример с Math можно было бы реализовать с помощью обычного JavaScript объекта и анонимной функции:

      // Math.js
      
      var Math = {};
      
      Math.sum = function sum(x, y) {
         return x + y;
      }
      
      Math.pi = 3.141593;
      
      (function() {
          // Не видна снаружи
         function internal() {
            ...
         }
      })();
      


      >> И что значит «подгружать из веба»? По спецификации в самом языке какое то встроенное (кроссбраузерное, стандартизированное) средство будет для обращения к удаленному хосту?

      Скорее всего, будет какая-то верхнеуровневая спецификация на загрузчики модулей. А уже индивидуальные реализации ECMAScript будут сами решать, как имплементировать эту спецификацию.

      >> И интересно, почему arrow-функции не могли назвать более привычным именем «lambda-function»

      Потому что технически function() { return 100 } — это тоже лямбда-функция. А () => 100 — это новая форма записи. И ей нужно было дать какое-то более конкретное название
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        Чтобы не читать всё — может тезисно рассказали бы суть?
        • НЛО прилетело и опубликовало эту надпись здесь
          • +1
            Да, начинает смахивать на мешанину из парадигм и возможностей всех языков, какие TC39 только могли вспомнить. Ощущение, как будто пытаются сделать попроще переход из любого другого языка, но хорошо ли от этого будет JavaScript… наверное, время покажет. Но самому как-то печально становится.
            • 0
              Именно так развивается C# — вбирая в себя лучшее отовсюду, но это повод для радости, а не печали) Работать становится удобнее и приятнее.
              • 0
                Да нет. В C# мне как раз нравится консистентность подходов, а здесь начинает ощущаться мешанина и с того что хорошо, и с того что не очень, лишь бы перешедшим с других языков было более привычно.
                • +1
                  А что из перечисленного прямо таки ухудшит язык? Лично я не могу сказать, что совсем бесполезные нововведения, разве что некоторые полезнее других, вот и все.
          • 0
            Забавно. Ну не знаю. По-моему всё это пришло исторически и логически.

            rest — это те же arguments, но с учтёнными ошибками.
            let уже давным давно в фоксе есть, я бы не сказал, что это что-то новенькое.
            значение параметров по-умолчанию — это тоже от такого паттерна:
            function (a) {
              if (a == null) a = 1;
            }
            

            for-of, сокращённое написание лямбды, модули — это всё не просто «перетянуто из других языков». Это всё реально используемые каждый день вещи, которых очень не хватает в JS.

            Я вот читаю топик и понимаю, что буду использовать просто всё, что в нём описано.

            Конечно, новичкам оно врядли понадобится
        • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          Да, я для себя, когда прочитал, выписал именно тезисами, чтобы потом оценить, что отметили здесь, а что нет. Получилось:

          ES6 habrahabr.ru/post/175371/
          * let — блочная область видимости (блок — фигурные скобки)

          * аргументы по умолчанию (сахар)

          * именованные аргументы (очень похоже на 1 хеш вмеесто ряда аргументов; оформлено как кругло-фигурные скобки ({...}) и комбинируется с позиционными аргументами)

          * деструктуризация при присваивании (массивы и хеши), чувствительные и нечувствительные к ошибкам (оператор "?=")

          * обёртка классов

          * модули — require, import, вместо with

          * for-of для собственных свойств

          * yield

          * стрелочные функции; неточное соответствие: не конструкторы, без this, без arguments

          * .bind(): (x, y) => x + y + this.z === function (x, y) { return x + y + this.z }.bind(this)


  • –2
    Новую версию JavaScript уже можно сравнивать с JScript 10.0 от Майкрософт.
  • 0
    Не знаете — есть какие интересные новости по теме?
    • +1
      __proto__ вроде как опять убирают из обязательной секции стандарта и переводят в дополнение, оставляют Object.getPrototypeOf и Object.setPrototypeOf.
      • 0
        А что с стандартизацией и реализацией в браузерах?
    • 0
      Кстати, я тут посмотрел traceur-compiler: traceur-compiler.googlecode.com/git/demo/repl.html

      это штукенция, которая делает из Ecma6 кода Ecma3 код. Он реально дохрена уже умеет. Не то, что полгода назад. Слегка грязноваты классы, не поддерживает let и модули, но for-of, => функции, классы, деструктуризацию, значения по-умолчанию — всё это уже работает. К концу года, к фризу, думаю, будут уже практически работающий код.
  • –2
    let arr = [ "blue", "green" ];
    arr.notAnIndex = 123;
    Array.prototype.protoProp = 456;
    
    for(var x in arr) {
       console.log(x); // Напечатает не blue, green, notAnIndex, protoProp a 0, 1, notAnIndex, protoProp
    }
    

    Да и в целом, как то Вы заблуждаетесь по поводу for..in конструкции: в применении к массивам всегда был способ использовать именно for..in, вместо классического for, совместно с методом hasOwnProperty
    let arr = [ "blue", "green" ];
    arr.notAnIndex = 123;
    Array.prototype.protoProp = 456;
    
    for(var x in arr) {
       if(arr.hasOwnProperty(x)){
            console.log(x); // Напечатает 0, 1, notAnIndex
        }
    }
    

    А что до создания у конкретного экземпляра массива не числового свойства, на подобии arr.notAnIndex = 123;, так это вообще извращение чистой воды и если вдруг у Вас это возникает как «необходимость», значит у Вас проблемы с архитектурой или вообще с концепцией, потому что для этого есть объекты.
    Но, по большому счету, всё равно лучше для массивов использовать классический for(va x = 0; x < arr.length; x++){...
    • 0
      В статье вроде бы про for..of, а не for..in. Это новая конструкция, предназначенная для работы с итераторами. Array в ES6 тоже станет итеруемым объектом. Подробнее здесь и здесь.
      • 0
        В примере в статье неправильно приведено использование именно конструкции for..in
        Я в курсе, что for..of будет работать итеративно по значениям элементов массивов а не по индексам, но изложение с ошибочным примером касательно оператора for..in вводит читателя в заблуждение, что конструкция for..of призвана заменить for..in и решить якобы именно его проблему, что в корне не правильно, потому что for..in в ES6 никуда не денется и всё так же будет использоваться как и в ES5 для итераций по ключам объектов
        Фактически я указал автору на грубую ошибку в статье, которую необходимо исправить.
        Что же касается применения именно for..in к массивам, то описанная проблема никуда не денется и данная конструкция так и останется безопасно применима только к объектам (из соображений что какой то «гений» будет использовать массивы как объекты, создавая там не числовые ключи), а для перебора именно индексов в синхронном цикле, так и останется классический for
        • 0
          Да, вы правы, конечно же, я не обратил внимания :)

          О таких ошибках можно лучше автору в личку отписаться. А то он поправит и ваш комментарий перестанет быть актуальным.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.