Pull to refresh

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

Reading time9 min
Views6.9K
Original author: John Resig
Раньше я проанализировал функциональность обьектов и свойств 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, но это — серия великолепных усовершенствований, которая сокращает количество очевидных ошибок, делая язык более безопасным и быстрым. Я с нетерпением жду, когда некоторые реализации станут публично доступными.
Tags:
Hubs:
Total votes 41: ↑40 and ↓1+39
Comments40

Articles