Массивы JavaScript: различия между версиями
imported>Supportadmin |
imported>Supportadmin |
||
Строка 44: | Строка 44: | ||
== Авто-длина length == | === Авто-длина length === | ||
Строка 53: | Строка 53: | ||
a[a.length] = "new element" | a[a.length] = "new element" | ||
a.push("new element") | a.push("new element") | ||
== Перебор элементов == | == Перебор элементов == |
Версия от 12:36, 4 августа 2013
Массивы
оригинал:http://javascript.ru/basic/array
Javascript поддерживает два вида структуры "массив":
Ассоциативный массив (хеш), где данные хранятся по произвольному ключу. (Об этом читайте в разделе Объекты.)
Числовой массив Array, где данные хранятся по номерам. Он описан в этой статье.
Javascript - очень гибкий язык, поэтому технически в Array можно хранить произвольные ключи, как в Object. Но лучше использовать типы по назначению.
Для хранения данных по номеру предназначен тип Array.
var arr = new Array() arr.test = 5 arr[1] = "blabla"
В типе Array есть специальные методы, ориентированные именно на работу с числовыми ключами.
Создание и изменение
Есть два эквивалентных способа создания массива:
var a = new Array() var a = []
Или, сразу со значениями
var a = new Array("a", 1, true) var a = ["a", 1, true]
Эти способы работают одинаково, кроме объявления вида new Array(10), когда у конструктора есть единственный аргумент-число.
Такое объявление создаст пустой массив (все элементы undefined) длиной 10. По возможности, не используйте new Array.
Отсчет элементов начинается с нуля:
alert(a[0]) // => "a"
Массив хранит данные по численным ключам, но внутри он использует точно такой же хэш (ту же структуру данных), как и обычный объект, поэтому можно сделать так:
var a = [] a[1] = 1 a[999999] = 2
и массив a будет занимать память, нужную для хранения этих двух соответствий, а не займет длинный непрерывный кусок памяти, как это произошло бы в языке С.
Авто-длина length
У каждого массива есть свойство length, которое автоматом меняется при каждом обновлении массива. Длина массива - это не количество элементов, а максимальный целый ключ + 1:
alert(a.length) // всего 2 элемента, но выведет 1000000
Добавлять новый элемент можно эквивалентными вызовами
a[a.length] = "new element" a.push("new element")
Перебор элементов
Перебор элементов обычно (когда индексы непрерывные) осуществляется простым циклом:
var arr = [ "array", "elements", "here" ] for(var i=0; i<arr.length; i++) { ... сделать что-то с arr[i] ... }
Если индексы - с разрывами, то перебор осуществляется так же, как в объектах:
var arr = [] arr[1] = 123 arr[9999] = 456 for(var i in arr) { if (!arr.hasOwnProperty(i)) continue; ... сделать что-то с arr[i] ... }
push
array.push( elem1, elem2, ... )
Эти элементы будут добавлены в конец массива. Он добавляет элементы, начиная с текущей длины length и возвращает новую, увеличенную длину массива.
Пример: добавление двух элементов // array.length = 2 var array = [ "one", "two" ] // добавить элементы "three", "four" var pushed = array.push("three", "four") // теперь array = [ "one", "two", "three", "four" ] // array.length = 4 // pushed = 4
pop
arrayObj.pop()
Этот метод извлекает последний элемент массива и возвращает его. При этом возвращенный элемент удаляется из массива, а длина массива уменьшается на единицу. Если массив пустой, то метод pop() возвращает значение undefined, при этом массив так и остается пустым.
Этот метод изменяет исходный массив.
myFish = ["angel", "clown", "mandarin", "surgeon"]; popped = myFish.pop(); // теперь popped = "surgeon" // myFish = ["angel", "clown", "mandarin"]
shift
var elem = arrayObj.shift()
Удаляет элемент с индексом 0 и сдвигает остальные элементы на один вниз. Возвращает удаленный элемент
var arr = ["мой","маленький", "массив"] var my = arr.shift() // => "мой" alert(arr[0]) // => "маленький" // теперь arr = ["маленький", "массив"]
unshift
arrayObj.unshift( [elem1[, elem2[, ...[, elemN]]]] )
Аргументы
elem1, elem2, ..., elemN
Добавляет в начало массива элементы и возвращает получившуюся длину.Добавленные элементы сохранят порядок следования. Данный метод изменяет исходный массив.
var arr = ["a", "b"] unshifted = arr.unshift(-2, -1); alert(arr ); // [ -2, -1, "a", "b"] alert("New length: " + unshifted); // 4
slice
slice(begin[, end]) Возвращает подмассив с индексами begin…end.
splice
splice(index, deleteCount[, element1,…, elementN]) Удалить deleteCount элементов, начиная с index, и вставить на их место element1…elementN
Есть и еще много методов:
join reverse ... О них можно почитать на английском, например, в http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array
Организация очереди
/* Queue.js A function to represent a queue Created by Stephen Morley - http://code.stephenmorley.org/ - and released under the terms of the CC0 1.0 Universal legal code: http://creativecommons.org/publicdomain/zero/1.0/legalcode */ /* Creates a new queue. A queue is a first-in-first-out (FIFO) data structure - * items are added to the end of the queue and removed from the front. */ function Queue(){ // initialise the queue and offset var queue = []; var offset = 0; /* Returns the length of the queue. */ this.getLength = function(){ // return the length of the queue return (queue.length - offset); } /* Returns true if the queue is empty, and false otherwise. */ this.isEmpty = function(){ // return whether the queue is empty return (queue.length == 0); } /* Enqueues the specified item. The parameter is: * * item - the item to enqueue */ this.enqueue = function(item){ // enqueue the item queue.push(item); } /* Dequeues an item and returns it. If the queue is empty then undefined is * returned. */ this.dequeue = function(){ // if the queue is empty, return undefined if (queue.length == 0) return undefined; // store the item at the front of the queue var item = queue[offset]; // increment the offset and remove the free space if necessary if (++ offset * 2 >= queue.length){ queue = queue.slice(offset); offset = 0; } // return the dequeued item return item; } /* Returns the item at the front of the queue (without dequeuing it). If the * queue is empty then undefined is returned. */ this.peek = function(){ // return the item at the front of the queue return (queue.length > 0 ? queue[offset] : undefined); } }
Очередь с одновременным выполнением нескольких заданий
Модуль использует Backbone.Events для оповещения о ходе выполнения задач и несколько полезных функций из Underscore. Экспорт объекта выполняется через мой фреймворк.
/** * Queue for simultaneous task execution. * Execution method MUST return the promise object. * * @param limit {Integer} number of simultaneous tasks * @event schedule * @event before * @event after */ (function () { var Task = function (obj, execMethod) { _.extend(this, { id: _.uniqueId("queueitem-"), obj: obj, execMethod: execMethod, active: false }); }; _.extend(Task.prototype, { run: function () { var func, value; this.active = true; func = this.obj[this.execMethod]; if (_.isFunction(func)) { value = func.call(this.obj); } // return promise object return value; } }); function runTasks() { var activeTasks = _.filter(queue, function (task) { return task.active; }); if (queue.length > 0 && activeTasks.length < limit) { // we can run another task var candidate = _.find(queue, function (task) { return !task.active; }); if (candidate) { Q.trigger("before", candidate.obj); var taskDfd = candidate.run(); Q.trigger("after", candidate.obj, taskDfd); if (taskDfd) { taskDfd.always(function () { var i, id = candidate.id; for (i = 0; i < queue.length; i++) { if (queue[i].id === id) { queue.splice(i, 1); break; } } runTasks(); }); } // check tasks one more time setTimeout(runTasks, 500); } } } var queue, limit; var Q = _.extend({ init: function (opts) { queue = []; limit = opts.limit; }, schedule: function (obj, execMethod) { var task = new Task(obj, execMethod); if (queue) { queue.push(task); Q.trigger("schedule", obj); runTasks(); } } }, Backbone.Events); App.namespace("App.Queue", Q); }()); Очередь конфигурируется с помощью одного обязательного параметра limit, который задает количество одновременно выполняемых задач. App.Queue.init({limit: 5}); var message, i; for (i = 0; i < 20; i += 1) { message = new Message("text " + i); App.Queue.schedule(message, "delivery"); }
В этом примере будет сгенерировано 20 объектов сообщений, у которых есть метод delivery, реализующий всю работу по доставке этого сообщения. Они все будут сразу поставлены в очередь, но одновременно отправляться смогут только 5 сообщений.
После добавления задания в очередь генерируется событие schedule, а до и после запуска задачи — before и after соответственно. В событии after в качестве параметра передается promise-объект задачи. Через него можно так же отслеживать окончание её выполнения в другом модуле.
App.Queue.on("after", function (messagePromise) { messagePromise.done(function () { console.log("message " + this.get("id") + " was delivered"); }); messagePromise.fail(function () { console.log("delivering message " + this.get("id") + " was failed"); }); });
Контекстом во всех событиях выступает объект, который ставился в очередь.
Очередь + стек
В массиве есть всё необходимое, чтобы работать с ним как с очередью или со стеком, или и с тем и другим одновременно.
Методы push и pop добавляют или вынимают значение с конца массива
var arr = [3,5,7] arr.push(9) var last = arr.pop() //= 9 var last = arr.pop() // = 7 alert(arr.length) // = 2
Методы shift/unshift делают то же самое, с начала массива.
var arr = [4,6,8] arr.unshift(2) // arr = [2,4,6,8] arr.unshift(0) // arr = [0,2,4,6,8] var last = arr.shift() // last = 0, arr = [2,4,6,8] arr.shift() // arr = [4,6,8]
shift/unshift обычно приводят к перенумерации всего массива. shift сдвигает все элементы на единицу влево, а unshift - вправо. Поэтому на больших массивах эти методы работают медленнее, чем push/pop.