imported>Supportadmin |
imported>Supportadmin |
Строка 1: |
Строка 1: |
| ==Массивы== | | За последние пару лет, а сейчас январь 2018, в JS появилось столько всего нового и это в стольких местах описано. Пора собрать в кучу весь поток сознания. |
| оригинал:http://javascript.ru/basic/array
| | ==Объявления переменных let и const == |
| ----- | | [https://learn.javascript.ru/let-const Теория] |
| Javascript поддерживает два вида структуры "массив":
| | [https://jsperf.com/let-vs-var-performance/93 Тесты] |
|
| |
|
| Ассоциативный массив (хеш), где данные хранятся по произвольному ключу. (Об этом читайте в разделе [[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
| |
| | |
| Добавляет в начало массива элементы и возвращает получившуюся длину.Добавленные элементы сохранят порядок следования. Данный метод изменяет исходный массив.
| |
| | |
| <nowiki>
| |
| var arr = ["a", "b"]
| |
| unshifted = arr.unshift(-2, -1);
| |
| alert(arr ); // [ -2, -1, "a", "b"]
| |
| alert("New length: " + unshifted); // 4</nowiki>
| |
| | |
| === 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
| |
| | |
| ==Организация очереди==
| |
| | |
| <nowiki>/*
| |
| | |
| 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);
| |
| | |
| }
| |
| | |
| }</nowiki>
| |
| | |
| ==Очередь с одновременным выполнением нескольких заданий==
| |
| | |
| | |
| Модуль использует Backbone.Events для оповещения о ходе выполнения задач и несколько полезных функций из Underscore. Экспорт объекта выполняется через [https://github.com/mistakster/app-skeleton/blob/master/app-skeleton.js мой фреймворк].
| |
| | |
| <nowiki>/**
| |
| * 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");
| |
| }</nowiki>
| |
| | |
| В этом примере будет сгенерировано 20 объектов сообщений, у которых есть метод delivery, реализующий всю работу по доставке этого сообщения. Они все будут сразу поставлены в очередь, но одновременно отправляться смогут только 5 сообщений.
| |
| | |
| После добавления задания в очередь генерируется событие schedule, а до и после запуска задачи — before и after соответственно. В событии after в качестве параметра передается promise-объект задачи. Через него можно так же отслеживать окончание её выполнения в другом модуле.
| |
| | |
| <nowiki>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");
| |
| });
| |
| });</nowiki>
| |
| | |
| Контекстом во всех событиях выступает объект, который ставился в очередь.
| |
| | |
| == Очередь + стек ==
| |
| | |
| | |
| В массиве есть всё необходимое, чтобы работать с ним как с очередью или со стеком, или и с тем и другим одновременно.
| |
| | |
| Методы 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.
| |