Это прекрасное время для JavaScript. Он не только становится гораздо более уважаемым языком, но и стремительно растет — как по популярности, так и по возможностям. Поскольку все больше браузеров начинают реализовывать функции стандарта ECMAScript 5-го издания, JavaScript становится еще более мощной платформой для разработки. В этом уроке мы поговорим о новых доступных вам методах.
Что такое ECMAScript 5?
ECMAScript — это официальное название того, что мы все называем JavaScript. Это не значит, что мы не правы; просто имя «JavaScript» является торговой маркой Oracle; поэтому Ecma International (первоначально Европейская ассоциация производителей компьютеров — отсюда ECMA) использует термин «ECMAScript» для обозначения стандарта JavaScript. Последней версией этого стандарта является 5-е издание, и он был утвержден чуть более года назад (3 декабря 2009 г.). Он включает в себя огромное количество отличных дополнений, и некоторые из них начинают появляться в браузерах. Реализации ECMAScript 5 называются JavaScript 1.8.5.
В этом руководстве мы рассмотрим функции JavaScript 1.8.5, которые доступны нам в бета-версиях Firefox 4. Вы будете рады обнаружить, что большинство последних версий других браузеров также имеют их. , , кроме одного. На этот раз это Opera, так как IE9 включил многие из них.
Функция 1: Object.create
Этот метод очень важен; это действительно очищает прототип наследования. Ранее (в ECMAScript 3rd edition), чтобы создать объект и установить его прототип, вы должны сделать что-то вроде этого:
01
02
03
04
05
06
07
08
09
10
11
12
|
function Cat(name) {
this.name = name;
this.paws = 4;
this.hungry = false;
this.eaten = [];
}
Cat.prototype = {
constructor : Cat,
play : function () { this.hungry = true;
feed : function (food) { this.eaten.push(food);
speak : function () { return «Meow» }
};
|
Я единственный, кто считает странным иметь прототип вне функции конструктора? И наследование становится еще сложнее. С Object.create
все становится намного проще. Выше может быть закодировано так:
01
02
03
04
05
06
07
08
09
10
11
|
var dog = {
name : «dog»,
paws : 4,
hungry : false,
eaten : null,
play : function () { this.hungry = true;
feed : function (food) { if (!this.eaten) { this.eaten = [];
speak : function () { return «Woof!»
};
var my_dog = Object.create(dog);
|
Здесь происходит следующее: я object.create
, передавая ему объект для использования в качестве прототипа нового объекта, который возвращает Object.create
. При использовании Object.create
мне не нужно беспокоиться об определении прототипа отдельно. На самом деле, у меня гораздо больше гибкости, чтобы решить, как создавать и наследовать объекты. Например, я не могу поместить eaten
массив в прототип, потому что массив является ссылочным значением, поэтому каждый объект, созданный из dog
будет совместно использовать этот массив. Я решил проверить его перед использованием здесь, но если бы я хотел обернуть Object.create(dog)
в функцию make_dog
, я мог бы назначить его там так же легко.
Вот что хорошо в Object.create
; Вы можете выбрать, как это сделать.
Есть второй параметр, который принимает Object.create
; это объект дескриптора свойств. Это немного сложно, но это также часть следующей функции, которую мы рассмотрим, поэтому давайте проверим это.
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Safari 5
- Chrome 5+
Функция 2: Object.defineProperty
Если у вас есть объект, для которого вы хотите определить свойство, вы, вероятно, сделаете это следующим образом:
1
|
my_dog.age = 2;
|
Это все еще отлично работает в ES5, но если вам нужен более детальный элемент управления, вы можете получить его с Object.defineProperty
. Первый параметр — это объект, которому вы назначаете свойство. Второй параметр — это имя свойства в виде строки. Последнее свойство является объектом дескриптора. Вот как это работает. Это (очевидно) объект, и он может иметь комбинацию следующих свойств, которые описывают добавляемое нами свойство:
- значение : используйте это, чтобы установить значение свойства. По умолчанию
undefined
. - доступный для записи : используйте это логическое значение, чтобы определить, является ли это переменной только для чтения. Если это доступно для записи, это
true
. По умолчаниюfalse
. - настраиваемый : используйте это логическое значение, чтобы определить, можно ли изменить тип (значение или метод) этого свойства или свойство можно удалить. Если это настраивается, это
true
. По умолчаниюfalse
. - enumerable : используйте это логическое значение, чтобы определить, включено ли это свойство при перечислении свойств объекта (цикл for-in или метод keys). По умолчанию
false
. - get : используйте это, чтобы определить пользовательский метод получения. По умолчанию
undefined
. - set : используйте это для определения пользовательского метода установки. По умолчанию
undefined
.
Обратите внимание, что значения по умолчанию для указанных выше логических параметров являются обратными старым стандартам obj.prop = val
. Кроме того, знайте, что вы не можете определить value
или writable
когда определены get
или set
, и наоборот.
Итак, как бы вы использовали это? Попробуй это:
01
02
03
04
05
06
07
08
09
10
|
// assume my_dog from above
Object.defineProperty(my_dog, «age», {
set : function (age) { this.human_years = age * 7;
get : function () { return this.human_years / 7;
enumerable : true
});
my_dog.age = 2;
my_dog.human_years;
|
Помимо того, что собачьи годы на самом деле не являются 7 человеческими годами , вы должны заметить, что мы не установили value
или не writable
здесь, потому что мы используем get
и set
. Эти функции никогда не доступны напрямую. Они «магически» запускаются за кулисами, когда вы назначаете или запрашиваете свойство. В этом примере я использую эти функции, чтобы держать age
и human_years
в состоянии «sync». Если вы не хотите, чтобы значение «other» было доступно, вы можете использовать анонимную, самопризывающуюся функцию, чтобы скрыть ее с помощью closure:
01
02
03
04
05
06
07
08
09
10
|
Object.defineProperty(my_dog, «age», (function () {
var human_years;
return {
set : function (age) { human_years = age * 7;
get : function () { return human_years / 7;
enumerable : true
};
}()));
|
Конечно, ничто не мешает вам делать что-то глупое внутри get
или set
, так что используйте это с умом.
Вы можете использовать форму объекта дескриптора свойства для добавления свойств к объектам с помощью Object.create
. Сделайте это следующим образом:
01
02
03
04
05
06
07
08
09
10
|
var your_dog = Object.create(dog, {
age : {
get : function () { /* .
set : function () { /* .
enumerable: true
},
gender : {
value : «female»
}
});
|
Просто используйте имя свойства как свойство объекта дескриптора; затем установите атрибуты через объект в значении.
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Safari 5
- Chrome 5+
Функция 3: Object.defineProperties
Если вы хотите определить несколько свойств одновременно, вы можете использовать объект дескрипторов свойств так же, как с Object.create
чтобы определить их, используя Object.defineProperties
.
01
02
03
04
05
06
07
08
09
10
|
Object.defineProperties(my_dog, {
age : {
get : function () { /* .
set : function () { /* .
enumerable: true
},
gender : {
value : «female»
}
});
|
Вы должны заметить — в редком случае, когда вы не используете литерал объекта в качестве второго параметра, — что будут использоваться только перечисляемые свойства объекта свойств.
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Safari 5
- Chrome 5+
Функция 4: Object.getOwnPropertyDescriptor
Если вы когда-нибудь захотите узнать особенности свойства, вы можете использовать эту функцию Object.getOwnPropertyDescriptor
. Принять к сведению «свой»; это работает только со свойствами самого объекта, а не его цепочки прототипов.
1
2
3
|
var person = { name : «Joe» };
Object.getOwnPropertyDescriptor(person, «name»);
|
Как видите, это работает со свойствами, установленными как старым, так и новым способом. Object.getOwnPropertyDescriptor
принимает два параметра: объект и имя свойства в виде строки.
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 8+
- Safari 5
- Chrome 5+
Функция 5: Object.keys
Всегда хотел получить все ключи объекта? Теперь вы можете легко сделать это с помощью Object.keys
. Передайте этой функции объект, и он вернет массив всех перечисляемых свойств этого объекта. Вы также можете передать ему массив, и вы получите обратно массив индексов.
1
2
3
|
var horse = { name : «Ed», age : 4, job : «jumping», owner : «Jim» };
var horse_keys = Object.keys(horse);
|
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Safari 5
- Chrome 5+
Функция 6: Object.getOwnPropertyNames
Этот похож на Object.keys
, за исключением того, что он включает в себя все свойства — даже те, которые не перечисляются. По более длинному названию функции вы можете сказать, что они препятствуют его использованию. Обычно вам нужны keys
.
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Safari 5
- Chrome 5+
Функция 7: Object.preventExtensions / Object.isExtensible
Если вы когда-либо хотели создать функцию, которая не принимает новые параметры, вы можете сделать это сейчас. Запустите ваш объект через Object.preventExtensions
, и он будет отклонять все попытки добавления новых параметров. Эта функция идет рука об руку с Object.isExtensible
, который возвращает true
если вы можете расширить объект, и false
если вы не можете.
01
02
03
04
05
06
07
08
09
10
11
|
var product = { name : «Foobar», rating : 3.5 };
Object.isExtensible(product);
Object.preventExtentions(product);
Object.isExtensible(product);
product.price = «$10.00»;
product.price;
|
Следует отметить, что все свойства объекта во время запуска Object.preventExtensions
все еще могут быть изменены или удалены (при условии, что их атрибуты позволяют это).
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Chrome 6+
Функция 8: Object.seal / Object.isSealed
Запечатывание объекта — один шаг от предотвращения расширений. Запечатанный объект не позволит вам добавлять или удалять свойства или изменять свойства со значения (например, строки) на метод доступа (метод) или наоборот. Конечно, вы все равно сможете читать и писать свойства. Вы можете узнать, запечатан ли объект, используя Object.isSealed
.
01
02
03
04
05
06
07
08
09
10
11
|
var pet = { name : «Browser», type : «dog» };
Object.seal(pet);
pet.name = «Oreo»;
pet.age = 2;
pet.type = function () { /**/ };
delete pet.name;
|
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Chrome 6+
Функция 9: Object.freeze / Object.isFrozen
Заморозка это еще один шаг вперед. Замороженный объект не может быть изменен никаким образом; это только для чтения. Вы можете проверить замороженность объекта с помощью, как вы уже догадались, Object.isFrozen
.
1
2
3
4
5
|
var obj = { greeting : «Hi!»
Object.freeze(obj);
Object.isFrozen(obj);
|
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Chrome 6+
Функция 10: Array.isArray
Можно подумать, что было бы не сложно определить, является ли данная переменная массивом. В конце концов, все остальное прекрасно работает с оператором typeof
. Однако JavaScript-массивы противоречивы. Они на самом деле ближе к объектам, похожим на массивы (хотя мы обычно используем этот термин для обозначения таких вещей, как arguments
и NodeList
) Эта функция дает вам 100% уверенность в том, что вы работаете с массивом. Передайте ему переменную, и она возвращает логическое значение.
1
2
3
|
var names = [«Collis», «Cyan»];
Array.isArray(names);
|
Подробнее о том, зачем нам нужна эта функция, смотрите документы, ссылки на которые приведены ниже.
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Safari 5
- Chrome 5+
- Опера 10.5+
Функция 11: Date.prototype.toJSON
Это не так уж и много, но если вы когда-нибудь захотите сохранить даты в формате JSON, это может оказаться полезным. У объектов Date теперь есть функция toJSON
, которая преобразует дату в toJSON
дату JSON.
1
|
new Date().toJSON();
|
Функция 12: Function.prototype.bind
Вы, вероятно, знакомы с использованием call
и apply
чтобы переназначить значение this
в функции .
1
2
3
4
|
var arr1 = [«1», «2», «3»],
arr2 = [«4», «5», «6»];
Array.prototype.push.apply(arr1, arr2);
|
Эти методы позволяют вам изменить значение this
внутри функции. Если вы хотите делать что-то подобное часто, Function.prototype.bind
возвращает новую функцию с this
привязкой к тому, что вы передаете, так что вы можете сохранить ее в переменной.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
var tooltip = { text: «Click here to . . . » },
overlay = { text: «Please enter the number of attendees» };
function show_text () {
// really, do something more useful here
console.log(this.text);
}
tooltip.show = show_text.bind(tooltip);
tooltip.show();
overlay.show = show_text.bind(overlay);
overlay.show();
|
Конечно, это может быть не самый практичный пример, но он дает вам идею!
- MDN Документация
- Поддержка браузера
- Firefox 4
- Internet Explorer 9
- Chrome 7+
Но подождите, это еще не все …
Это функции ECMAScript 5th Edition (или JavaScript 1.8.5), которые были добавлены в бета-версии Firefox 4. Есть несколько других изменений в JavaScript, которые они также реализуют, что вы можете проверить в примечаниях к выпуску .
Однако есть несколько функций ECMAScipt 5, которые уже поддерживаются в Firefox 3 и некоторых других браузерах. Вы играли с любым из них?
- Object.getPrototypeOf
- String.prototype.trim
- Array.prototype.indexOf
- Array.prototype.lastIndexOf
- Array.prototype.every
- Array.prototype.some
- Array.prototype.forEach
- Array.prototype.map
- Array.prototype.filter
- Array.prototype.reduce
- Array.prototype.reduceRight
Примечание: они связаны с их документацией MDN.
Если вы хотите узнать, какие браузеры и версии поддерживают эти функции, вы можете проверить эту таблицу совместимости, составленную Юрием Зайцевым (Kangax) . Приятной особенностью большинства этих функций является то, что если браузер не поддерживает их, вы можете добавить поддержку, например, так:
1
2
3
4
5
6
7
8
|
if (typeof Object.create !== ‘function’) {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
// Courtesy of Douglas Crockford: http://javascript.crockford.com/prototypal.html
|
Какие функции ECMAScript 5 вы используете?
Множество новых функций, которые мы рассмотрели здесь, на самом деле — лишь малая часть достоинства, добавленного к стандарту ECMAScript в 5-м издании. Есть ли какие-то другие функции, которые вы с нетерпением ожидаете использовать, или, может быть, даже сейчас используете? Давайте здесь это в комментариях!