JavaScript — прототипы
Свойство prototype позволяет расширить функциональность встроенных объектов JavaScript (String, Date, Array и др.) путем добавления методов и свойств ко всем объектам определенного класса. Использование свойства prototype рассмотрим на примере «удобного прокручивания” массивов.
При написании любого 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];
}
}
Таким образом мы присвоим эти методы всем существующим массивам (даже тем, которые были созданы до исполнения этого кода!).
(взято с http://live.julik.nl/2004/05/prototypes)
Проанализировав эту публикацию Михил Иванюшин предлагает свой, более удобный и дополненный вариант подобных функций по работе с массивами.
// Демонстрация функции prototype;
// идея найдена тут: http://adobeindesign.ru/2009/03/10/javascript-prototipy/
//
// Модифицированы примеры http://live.julik.nl/2004/05/prototypes,
// т.к. не понравилось, что при инициализации указателя массива ему присваивается значение 1.
// Так было в фортране, но это очень неудобно. Поэтому уже давно индекс первого элемента массива устанавливается равным нулю.
// Добавлено две функции: set — присвоение значения индексу массива, и current — считывание текущего значения массива.
// Изменена концепция функций next и prev: в оригинале они возвращают false при обращении за пределы массива.
// Сейчас возвращаются или последний, или первый элементы массива, и указатель устанавливается равным идексу возвращенного элемента в массиве
// Тестировалось в CS4.
// метод: Инициализация указателя массива
Array.prototype.checkPointer = function() {
if (typeof(this.pointer) == ‘undefined’) {
this.pointer = 0;
}
}
// метод: Встать в начало массива
Array.prototype.rewind = function() {
this.pointer = 0;
}
//метод: Встать в конец массива
Array.prototype.toLast = function() {
this.pointer = this.length -1;
}
// метод: Установить индекс массива
Array.prototype.set = function(value) {
if ((this.length >= value ) && ( value >= 0 )) this.pointer = value;
this.pointer = value;
}
//метод: Выбрать следующий элемент
Array.prototype.next = function() {
this.checkPointer();
i = this.pointer;
i++;
if ( i >= this.length-1 ) {
// если индекс указывает на последний элемент, или за пределы массива,
// то возвращается последний элемент массива; индекс устанавливается равным длине массива, уменьшенном на единицу
i = this.length-1;
}
return this[i];
}
//метод: Выбрать текущий элемент
Array.prototype.current = function() {
this.checkPointer();
return this[this.pointer];
}
//метод: Выбрать предыдущий элемент
Array.prototype.prev = function() {
this.checkPointer();
i = this.pointer;
i—;
if (i <= 0) {
// если индекс указывает на первый элемент, или за пределы массива,
// то возвращается первый элемент массива; индекс устанавливается равным нулю
i = 0;
}
return this[i];
}
//////
with (app) {//
var myArray = [0,1,2,3,4,5,6,7,8,9,10,11,12];
myArray.rewind();
var myFirst = myArray.current(); // 0
var myNext = myArray.next(); // 1
var myNext1 = myArray.next(); // 1
var myNext2 = myArray.next(); // 1
myArray.set(8);
var myNextCurrent = myArray.current(); //8
myArray.toLast();
var myLast = myArray.current(); //12
var myPrev = myArray.prev(); // 11
var myPrev1 = myArray.prev(); // 11
var myPrev2 = myArray.prev(); // 11
a=0;
} //
не менее интересная техника работы с массивами с помощью итераторов:
http://habrahabr.ru/blogs/javascript/28977/
файл по ссылке в конце статьти не загружется, но можно код на developer.mozilla.org
вот пример функции filter
// Array methods
// By Mozilla Developer Center (http://developer.mozilla.org)
if (!Array.prototype.filter) {
/**
* Creates a new array with all elements that
* pass the test implemented by the provided function.
*/
Array.prototype.filter = function(fun /*, thisp*/) {
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in this) {
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}