ECMAscript 5: Строгий режим, JSON, и так далее перевод

Раньше я проанализировал функциональность обьектов и свойств ECMAScript 5. Это огромный новый аспект языка и он заслуживает особого рассмотрения.

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

Строгий режим


Строгий режим является новой особенностью в ECMAScript 5, позволяющей заставить выполняться программу или функцию в «строгом» операционном контексте. Строгий контекст предотвращает возможность выполнения определенных действий и выбрасывает больше исключений (предоставляя также пользователю больше информации, и поддерживая парадигму кодирования пирамидой вниз).

В то время, как ECMAScript 5 обратно совместим с ECMAScript 3, все «особенности» ECMAScript 3, которые «не рекомендуется» сейчас использовать, просто отключены (или выбрасывают исключения) в строгом режиме.

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

Большая часть информации о строгом режиме может быть найдена в спецификации ES5 [PDF] на странице #223.

Нужно отметить, что строгий режим ECMAScript 5 отличается от строгого режима, доступного в Firefox (который может быть включен через about:config, параметр javascript.options.strict). Строгий режим ES5 блокирует совершенно иной набор потенциальных ошибок (тогда как существующий строгий режим Firefox пытается наблюдать за соблюдением некоторых рекомендаций по написанию хорошего кода, но не более того).

Как Вы включаете строгий режим?

Просто. Вставьте этот оператор выше программы, чтобы включить его для целого скрипта:
"use strict";

* This source code was highlighted with Source Code Highlighter.


Или поместите этот оператор в пределах функции, чтобы включить строгий режим только в пределах её контекста.
function imStrict(){
 "use strict";
 // ... your code ...
}

* This source code was highlighted with Source Code Highlighter.


Обратите внимание на синтаксис, который используется, чтобы разрешить строгий режим (мне он нравится!). Это просто строка одним оператором, которая содержит значение «use strict». Никакого нового синтаксиса для определения строгого режима не вводится. Это является огромным плюсом. Это означает, что вы можете включить строгий режим в вашем сценарии — сегодня, — и он будет, в худшем случае, без побочных эффектов в старых браузерах.

Как вы можете отметить из примеров здесь и в предыдущей статье, практически нет новых синтаксических дополнений или изменений в языке в спецификации ECMAScript 5. Это означает, что вы можете написать ваши ES5 скрипты таким образом, что они смогут корректно деградировать для устаревших клиентов — то, чего не было возможным с ECMAScript 4. То, как поддерживается строгий режим, является яркой иллюстрацией этого момента на практике.

А изящный аспект определения строгого режима в рамках функции состоит в том, что теперь вы можете определить вашу JavaScript-библиотеку полностью в строгом режиме, не затрагивая код снаружи.
// Non-strict code...

(function(){
 "use strict";

 // Define your library strictly...
})();

// Non-strict code...


* This source code was highlighted with Source Code Highlighter.

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

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

Переменные и свойства

Попытка присвоить foo = "bar"; там, где переменная 'foo' не была определена, будет терпеть неудачу. Ранее этот код присвоил бы значение к свойству foo глобального объекта (например, window.foo), теперь это только выбросит исключение. Это определенно исключит некоторые раздражающие ошибки.

Любые попытки изменить свойство, чей атрибут «writable» установлен в ложь, удаления свойства, чей атрибут «configurable» установлен в ложь, или добавления свойства к объекту, атрибут «extensible» которого установлен в ложь, закончится по ошибке (эти атрибуты были обсуждены ранее). В обычном режиме никакая ошибка не будет выброшена, когда любое из этих действий будет предпринято, они будут только молча завершаться неудачей.

Удаление переменной, функции или параметра закончится ошибкой.

var foo = "test";
function test(){}

delete foo; // Error
delete test; // Error

function test2(arg) {
  delete arg; // Error
}

* This source code was highlighted with Source Code Highlighter.

Определение свойства более, чем однократно, в одном обьектном литерале, — выбросит исключение.
// Error
{ foo: true, foo: false }

* This source code was highlighted with Source Code Highlighter.


eval

Практически любая попытка использовать имя 'eval' запрещено — а это возможность присвоить функцию eval переменной или свойству объекта.
// All generate errors...
obj.eval = ...
obj.foo = eval;
var eval = ...;
for ( var eval in ... ) {}
function eval(){}
function test(eval){}
function(eval){}
new Function("eval")

* This source code was highlighted with Source Code Highlighter.


Кроме того, попытки ввести новые переменные через eval будет заблокированы.
eval("var a = false;");
print( typeof a ); // undefined


* This source code was highlighted with Source Code Highlighter.


Функции

Попытка переписать объект аргументов приведёт к ошибке:
arguments = [...]; // not allowed

* This source code was highlighted with Source Code Highlighter.

Определение нескольких аргументов с одинаковым названием приведет к ошибке
function(Foo, Foo) {} // error

* This source code was highlighted with Source Code Highlighter.


Доступ к arguments.caller и arguments.callee сейчас выбросит исключение. Таким образом, любые анонимные функции, на которые вы хотите сделать ссылку, необходимо будет именовать, например, так:
setTimeout(function later(){
 // do stuff...
 setTimeout( later, 1000 );
}, 1000 );


* This source code was highlighted with Source Code Highlighter.

Свойства arguments и caller других функций больше не существуют — и способность определить их запрещена.
function test(){
 function inner(){
  // Don't exist, either
  test.arguments = ...; // Error
  inner.caller = ...; // Error
 }
}

* This source code was highlighted with Source Code Highlighter.

Наконец, давняя (и очень раздражающая) ошибка была исправлена: Случаи, когда null или undefined принуждены становиться глобальным объектом. Строгий режим теперь препятствует тому, чтобы это случалось, и бросает исключение вместо этого.
(function(){ ... }).call( null ); // Exception

* This source code was highlighted with Source Code Highlighter.


with(){}

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

Изменения, сделанные в строгом режиме ECMAScript 5, несомненно, разнообразны (от навязывания стилистических предпочтений, например, удаления операторов with, до корректного исправления плохих ошибок в языке, как, например, способности к переопределению свойств в обьектных литералах). Будет интересно посмотреть, как люди начнут адаптироваться к этим новшествам и каким образом эти новшества изменят развитие JavaScript.

Я хотел бы заметить, что я достаточно уверен, что jQuery уже сейчас совместим со строгим режимом ES5. Как только станет доступной реализация этого языка (так, чтобы это утверждение могло быть проверено), я с радостью переключу jQuery для работы исключительно в строгом режиме.


JSON


Второй важной особенностью языка является добавление родной поддержки JSON в сам язык.

Я настаивал на этом шаге в течение долгого времени, и я очень рад видеть его, наконец, в спецификации.

В ближайшем времени, ПОЖАЛУЙСТА, начинайте миграцию ваших JSON-приложений на json2.js от Крокфорда. Он полностью совместим со спецификацией ECMAScript 5 и грациозно переключается на родную (более быструю!) реализацию, если она существует.

На самом деле, я вчера закоммитил изменение jQuery, чтобы использовать метод JSON.parse, если он существует, тем более что теперь этот метод наконец специфицирован.

Существуют два основных метода для обработки JSON: JSON.parse (который преобразует строку JSON в объект JavaScript) и JSON.stringify (который преобразовывает объект JavaScript в сериализованную строку).

JSON.parse( text )

Преобразует сериализованную строку JSON в объект JavaScript
var obj = JSON.parse('{"name":"John"}');
// Prints 'John'
print( obj.name );


* This source code was highlighted with Source Code Highlighter.


JSON.parse( text, translate )

Использует функцию трансляции для конвертации значений или их полного удаления.
function translate(key, value) {
 if ( key === "name" ) {
  return value + " Resig";
 }
}

var obj = JSON.parse('{"name":"John","last":"Resig"}', translate);
// Prints 'John Resig'
print( obj.name );

// Undefined
print( obj.last );

* This source code was highlighted with Source Code Highlighter.


JSON.stringify( obj )

Преобразовывает объект JavaScript в сериализованную строку
var str = JSON.stringify({ name: "John" });
// Prints {"name":"John"}
print( str );


* This source code was highlighted with Source Code Highlighter.


JSON.stringify( obj, [«white», «list»])

Сериализует только специфицированный «белый список» свойств.
var list = ["name"];
var str = JSON.stringify({name: "John", last: "Resig"}, list);
// Prints {"name":"John"}
print( str );


* This source code was highlighted with Source Code Highlighter.


JSON.stringify( obj, translate )

Сериализует обьект с использованием транслирующей функции.
function translate(key, value) {
 if ( key === "name" ) {
  return value + " Resig";
 }
}

var str = JSON.stringify({"name":"John","last":"Resig"}, translate);
// Prints {"name":"John Resig"}
print( str );

* This source code was highlighted with Source Code Highlighter.


JSON.stringify( obj, null, 2 )

Добавляет указанное число пробелов при выводе, равномерно.
var str = JSON.stringify({ name: "John" }, null, 2);
// Prints:
// {
//  "name": "John"
// }
print( str );


* This source code was highlighted with Source Code Highlighter.


JSON.stringify( obj, null, "\t" )

Использует указанную строку для выполнения табуляции.
var str = JSON.stringify({ name: "John" }, null, "\t");
// Prints:
// {\n\t"name": "John"\n}
print( str );


* This source code was highlighted with Source Code Highlighter.


Также несколько новых универсальных методов были добавлены к некоторым из базовых объектов, но, искренне, они не так интересны. Результаты для String, Boolean, и Number эквивалентны запросу.valueOf(), и результат для Date эквивалентен вызову .toISOString().
// Yawn...
String.prototype.toJSON
Boolean.prototype.toJSON
Number.prototype.toJSON
Date.prototype.toJSON

* This source code was highlighted with Source Code Highlighter.


.bind()


Приветствуемое дополнение к языку — встроенный метод .bind () для того, чтобы реализовать контекст функции (фактически идентичный реализации .bind в библиотеке Prototype.js).

Function.prototype.bind (thisArg, arg1, arg2....)

Задает значение 'this' указанной функции равное специфицированному объекту — и передаёт функции любые указанные параметры.
var obj = {
 method: function(name){
  this.name = name;
 }
};

setTimeout( obj.method.bind(obj, "John"), 100 );

* This source code was highlighted with Source Code Highlighter.

Учитывая, как долго эта функция (и его эквиваленты) существует в разных библиотеках, это отрадное дополнение к языку.

Date


Даты теперь способны и парсить, и выводить себя в формате ISO. Спасибо.

Конструктор Даты теперь пытается сперва анализировать дату, как будто она была отформатирована по стандарту ISO, и только затем переходит к другим форматам, которые он понимает.

Дополнительно, у объектов даты теперь есть новый метод .toISOString (), который выводит дату в формате ISO.
var date = new Date("2009-05-21T16:06:05.000TZ");

// Prints 2009-05-21T16:06:05.000TZ
print( date.toISOString() );

* This source code was highlighted with Source Code Highlighter.


.trim()


Родной, встроенный метод .trim () теперь включен для строк. Работает тождественно ко всем другим методам trim — но с потенциалом, чтобы, возможно, работать быстрее.

Стивен Левитан обсудил метод trim более подробно.

Массив


Расширения для массивов JavaScript, похоже, наконец формально определены. Они включают в себя следующие методы: indexOf, lastIndexOf, every, some, forEach, map, filter, reduce и reduceRight.

Дополнительно добавлен новый метод Array.isArray, обеспечивая функциональные возможности, очень похожие следующему:
Array.isArray = function( array ) {
 return Object.prototype.toString.call( array ) === "[object Array]";
};


* This source code was highlighted with Source Code Highlighter.


В целом, я думаю, что ECMAScript 5 делает интересное предложение. Это не громадный прыжок, который обещал ECMAScript 4, но это — серия великолепных усовершенствований, которая сокращает количество очевидных ошибок, делая язык более безопасным и быстрым. Я с нетерпением жду, когда некоторые реализации станут публично доступными.
+39
23 мая 2009, 15:16
32
akzhan 15,8

комментарии (40)

0
Ueasley #
А как быстро такие изменения вступают в силу, обычно?
0
akzhan #
Некоторые нововведения поддерживаются уже в IE8, Safari 4, Chrome 2, Opera 9.6 и в Firefox 3.5.
0
ant99 #
Ключевое слово — «некоторые».
+1
akzhan #
Ключевое слово — уже сейчас.

Более того, можно уже сейчас писать согласно строгому режиму, не потеряв совместимости с ES3.
+1
akzhan #
Кстати, скорее всего первая реализация ECMAscript станет доступной в Rhino.

raphscallion.com/blog/entries/2009/05/13/progress.html
0
SowingSadness #
Интересно и когда же он начнется поддерживаться броузерами и wsh? -))
0
akzhan #
Думаю, через год. Самым непредсказзуемой является реализацию этого языка в IE, так как выходит он редко.
0
bolk #
В IE8 есть реализация JSON.
+2
Octane #
Чем им так arguments.callee не угодил, было же удобно рекурсию анонимных функций делать или вообще использовать функцию, как объект, доступный по этой ссылке :-/
0
akzhan #
Видмо, для улучшения читаемости кода.
0
linuxoid #
А уж как удобно было делать call stack через callee и caller…
0
4pcbr #
не включать strict mode никто не запрещал: )
0
akzhan #
Кстати, нашёл интересный фидбэк:

webreflection.blogspot.com/2009/05/ecmascript-5-do-not-remove.html
–2
alekciy #
>Строгий режим ES5 жалуется на полностью другой набор
> потенциальных ошибок (тогда как существующий строгий
>режим Firefox пытается наблюдать за соблюдением некоторых
> хороших практик, но не более того).

Местами очень сильно напоминает native google translete ;)
0
akzhan #
Местами я не знал, как перевести близко к тексту и не так неудобоваримо )))
–2
dinamyte #
Строгий режим сейчас необходим Ecmascript как Маргарет Тетчер была нужна Великобритании в своё время.
0
akzhan #
Скажите это тем, кто пишет на Perl…

Лично я любой Perl-скрипт предваряю
use strict;
use warnings;
–2
dinamyte #
Вот объясните, будьте добры: причём тут Perl и как он относится к Ecmascript?
0
akzhan #
Разве вы не видите сходства ситуаций?

use strict в Perl стал путём к использованию ужасного скриптового языка в более серьёзных целях.

Здесь — то же самое.
0
akzhan #
немного философии можно прочесть тут:
dklab.ru/chicken/perl6/1.html#cont2
–2
tenshi #
в яваскрипт добавили поддержку javascript object notation… потрясно XDDDD

а стрикт так вообще убивает… %-\
0
ScuFF #
Всегда считал что JSON итак поддерживается. Если скормить в eval Json-строку, то он вернет объект. Разве нет? Почему существуют специальные библиотеки парсинга? Что значить нативная поддержка? Объясните, пожалуйста.
0
azproduction #
Нативный == встроенный.
Библиотеки обеспечивают удобный интерфейс для работы, валидацию. Теперь все это будет встроено.
Поюсы: нативная валидация, нативные Array.toJSON() Object.toJSON() и т.п, прирост в скорости работы.
+1
akzhan #
проблема с eval состоит только в том, что она способна принять не только JSON.

Фактически это означает дыру в безопасности при получении JSON из внешних источников.
0
razetdinov #
Сравните eval("alert('xss')") и JSON.parse("alert('xss')").
0
sunnybear #
спасибо, нашел быструю имплементацию trim. Может быть, ее стоит включить в YASS…
function trim12 (str) {
	var	str = str.replace(/^\s\s*/, ''),
		ws = /\s/,
		i = str.length;
	while (ws.test(str.charAt(--i)));
	return str.slice(0, i + 1);
}
0
bolk #
Нафига делать \s\s*? Просто \s+ сделать нельзя?

кроме того, кто мешает сделать просто str.replace(/^\s+/, '').replace(/\s+$/, '')
+1
sunnybear #
по ссылке 12 способов. Этот самый быстрый во всех браузерах :)
0
bolk #
OMG :) Цикл быстрее регулярки, надо же!
0
sunnybear #
да, while рулит :) хотя, я думаю, это какой-то косяк со стороны разработчиков браузеров :)
0
bolk #
Да уж пожалуй. Кстати, интересно как поменяется таблица, если испытания проводить на IE8, Chromium2, FF3.5 и Opera 10a…
0
lahmatiy #
Мне кажется тут нет никакого косяка со стороны разработчиков браузеров :)
Дело в том, что регулярные выражения всегда обрабатывают строку начиная с ее начала, таким образом пока обработка дойдет до финальной серии пробельных символов будет проделано немало «работы»: когда встречается пробельный символ, то дальше набираются другие «пробелы» пока не встретится конец строки или непробельный символ. В первом случае будет «совпадение», во втором переход к поиску следующего пробельного символа. С точки зрения оптимизации было бы логично для данного выражения делать просмотр строки с конца, но так как регулярные этого не умеют (по крайней мере в JS — нет просмотра с конца), то быстрее будет проделать это «самому» перебирая символы с конца. Регулярные выражения основаны на конечных автоматах, и не имеют особых оптимизаций и частных случаев.
While имеет смысл для строк содержащих большое количество пробельных групп (один и более пробельный символ). Для пустых строк и строк содержащих только пробельные символы регулярное выражение может оказаться быстрее (если не брать в расчет проверку длины для случая пустой строки), так как перебор символов написанный не на JS будет значительно быстрее.
–3
4pcbr #
А зачем публиковать машинный перевод статьи? о_О
0
akzhan #
Если можете сделать лучше, сделайте :)

Критиковать проще, чем переводить.
+1
4pcbr #
Мне нравится читать качественный перевод, вот и все. И мне нравится хабр именно качественным контентом.

Резиг опубликовал статью 21 мая в 9 утра примерно. Вы извините, но ваш перевод соответствует 10 утра того же дня; )
0
alexshelkov #
А они живут в одних и тех же часовых поясах =)?

По сабжу, перевод нормальный, вполне читаемый. Главное другое, Javascript(ECMAscript) пожалуй мой самый любимый язык и приятно что он развивается. Очень много интересных и действительно полезных новшеств, одни изменения в объектах чего стоят…
–1
4pcbr #
Давайте попросим Резига кросспостить на хабр, че нам ломаный перевод читать: )
0
akzhan #
Если можете сделать лучше, — сделайте.

Если хотите, попробуйте машинный перевод и сравните с моим.

Я не профессиональный переводчик. Но я перевожу интересные материалы, а вы?
0
4pcbr #
ок, сравнил случайно выбранную фразу:

ES5's strict mode complains about a completely different set of potential errors (whereas Firefox's existing strict mode tries to enforce some good practices, only). (с) J.Resig, subscribe post, 21.05.09

Строгий режим ES5 жалуется на полностью другой набор потенциальных ошибок (тогда как существующий строгий режим Firefox пытается наблюдать за соблюдением некоторых хороших практик, но не более того). (с)akzhan

ES5 в строгом режиме жалуется совершенно иной набор возможных ошибок (а Firefox существующих строгого режима пытается обеспечить хорошие практики, только). © Google translate

мой вариант перевода: ES5 в режиме strict mode указывает на совершенно иные потенциальные ошибки (FF в свою очередь ссылается на рекомендации написания хорошего кода)

-> Но я перевожу интересные материалы, а вы?
Я здесь далеко не самый активный юзер, но уважаю всех пользователей этого сообщества. Потому и высказался против перевода такого качества. Минусуйте на здоровье, я лишь пытаюсь быть объективным.
0
akzhan #
Любые исправления — приветствуются. Поправлю.

Судя по реакции большинства посетителей Хабра, всё же моя работа была принята положительно.

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