JavaScript - прототипы
Одна из непопулярных (но при этом невероятно практичных) возможностей JS - изменение прототипов (иными словами, добавление методов и свойств ко всем объектам определенного класса. А возможность между прочим - удобнейшая( !). Пример использования такой возможности - удобное "прокручивание" массивов.
При написании любого JavaScript’а рано или поздно возникает необходимость обработать все элементы массива. Традиционно это делается через конструкцию for:
for (var i =0; i < myArr.length; i++) {
myArr[i].doSomething();
}
Однако почему бы не сделать для себя небольшое удобство и не листать массив вот так:
while (var element = myArr.next() ) {
var current = element;
}
Причем этот метод будет доступен для любого массива, в том числе для созданных стандартными системными средствами. А все благодаря тому, что у каждого объекта в JavaScript есть т.н. прототип, которому можно присваивать свойства и методы (поскольку формально в JS классов и их наследования нету, методы и свойства объектов можно расширять “анонимно” - простым присвоением снаружи). Чтобы создать наш метод next (по сути - итератор), мы обратимся к свойству prototype встроенного объекта Array. Заодно создадим простой указатель на элемент, используемый в настоящий момент, и еще несколько методов:
myArr.toLast() //"промотать" массив до последнего элемента
myArr.rewind() //перейти в начало массива, аналог функции reset() в PHP
myArr.next() //возвращает следующий элемент массива
myArr.prev() //возвращает предыдущий элемент массива
Итак, приступим:
//Add method to initialize pointer
Array.prototype._checkPointer = function() {
if (typeof(this._pointer) == 'undefined') {
this._pointer = 1;
}
}
//Add method to rewind forward
Array.prototype.rewind = function() {
this._pointer = 1;
}
//Add method to move pointer to the end
Array.prototype.toLast = function() {
this._checkPointer();
this._pointer = this.length +1;
}
//Add method to go to next element
Array.prototype.next = function() {
//check pointer
this._checkPointer();
// return current pointer position minus one
if (this._pointer === this.length +1) {
return false;
} else {
var ind = this._pointer -1;
this._pointer ++;
return this[ind];
}
}
//Add method to go to previous element
Array.prototype.prev = function() {
//check pointer status
this._checkPointer();
//check if we are at the first element
if (this._pointer == 1) {
return false;
} else {
//decrement pointer
this._pointer -=1;
return this[this._pointer -1];
}
}
Таким образом мы присвоим эти методы всем существующим массивам (даже тем, которые были созданы до исполнения этого кода!). Дальнейшие варианты - действий на эту тему - например, функции toTranslit и fromTranslit для каждого объекта String и так далее. BTW - код грязный, несколько минут работы всего.
PHP сосет одним словом… Причем такая возможность должна быть не только в JavaScript для веб-страниц, но и в том JS, которым скриптятся InDesign CS, Director 2004, LiveMotion, Combustion…