Java Script: различия между версиями
imported>Supportadmin |
imported>Supportadmin Нет описания правки |
||
Строка 149: | Строка 149: | ||
Здесь мы наглядно убеждаемся, что функция f, созданная как метод глобального объекта window, сама оказывается объектом, у которого могут быть свои собственные свойства и методы! | Здесь мы наглядно убеждаемся, что функция f, созданная как метод глобального объекта window, сама оказывается объектом, у которого могут быть свои собственные свойства и методы! | ||
<span style="color:darkgreen">'''Вывод'''</span> | |||
Для того, что бы объект вел себя предсказуемо (это исключает долгую логическую отладку) объекты <span style="color:darkgreen">'''''НАДО СОЗДАВАТЬ ТОЛЬКО ЯВНЫМ СПОСОБОМ'''''</span> | Для того, что бы объект вел себя предсказуемо (это исключает долгую логическую отладку) объекты <span style="color:darkgreen">'''''НАДО СОЗДАВАТЬ ТОЛЬКО ЯВНЫМ СПОСОБОМ'''''</span> | ||
Версия от 11:39, 4 августа 2013
Операторы
В ECMAScript имеются как операторы, использующие в качестве названий ключевые слова, так и операторы, использующие в качестве названий знаки препинания.
Классификация операторов
По убыванию приоритета операторы ECMAScript можно разбить в следующие группы:
- . (доступ к свойству),[] (доступ к свойству),() (вызов функции), new (создание нового объекта),
- ++ (инкремент), -- (декремент), - (унарный минус), + (унарный плюс), ~ (поразрядное дополнение), ! (логическое дополнение), delete (удаление свойства), typeof (определение примитивного типа данных), void (возврат неопределённого значения),
- * (умножение), / (деление), % (остаток от деления),
- + (сложение), - (вычитание), + (конкатенация строк),
- << (сдвиг влево), >> (сдвиг вправо с расширением знакового разряда), >>> (сдвиг вправо с дополнением нулями),
- < (меньше), <= (меньше или равно), > (больше), >= (больше или равно), instanceof (проверка типа объекта), in (проверка наличия свойства),
- == (проверка на равенство), != (проверка на неравенство), === (проверка на идентичность), !== (проверка на неидентичность),
- & (поразрядная конъюнкция),
- ^ (поразрядное сложение по модулю 2),
- | (поразрядная дизъюнкция),
- && (конъюнкция),
- || (дизъюнкция),
- ?: (тернарная условная операция),
- = (присваивание), *=, /=, +=, -=, <<=, >>=, >>>=, &=, ^=, |= (присваивание с операцией),
- , (множественное вычисление)[17].
Операторы ++, --, -, +, ~, !, delete, typeof, void, ?:, =, *=, /=, +=, -=, <<=, >=, >>>=, &=, ^=, |= правоассоциативны (то есть для них a op b op c эквивалентно a op (b op c)). Остальные операторы ECMAScript левоассоциативныe.
По арности операторы ECMAScript делятся на следующие группы:
- унарные (delete, void, typeof, ++, --, - (унарный минус), + (унарный плюс), ~, !, new),
- бинарные (., [], (), *, /, %, + (сложение), - (вычитание), + (конкатенация строк), <<, >>, >>>, <, <=, >, >=, instanceof, in, ==, !=, ===, !==, &, ^, |, &&, ||, =, *=, /=, +=, -=, <<=, >=, >>>=, &=, ^=, |=, ,),
- тернарные (?:),
- операторы, не имеющие фиксированного количества операндов (()).
По положению знака операции относительно операндов операторы ECMAScript делятся на следующие группы:
- префиксные (например, new, ++ (префиксный инкремент),
- инфиксные (например, +, -),
- постфиксные (например, ++ (постфиксный инкремент), -- (постфиксный декремент).
Также операторы классифицируются по типу операндов и по характеру осуществляемого действия.
Особенности операторов ECMAScript
В ECMAScript нет оператора, позволяющего проверить, относится ли свойство непосредственно к объекту или является унаследованным.
Такая проверка осуществляется с помощью метода hasOwnProperty(). В связи с тем, что данный метод не является оператором, он может быть переписан любым другим свойством.
Оператор + является единственным арифметическим оператором в языке, который перегружен для строковых аргументов. Если хотя бы один из операндов — строка, + действует как конкатенатор, в противном случае выполняется сложение.
В отличие от языков, где void является типом данных, в ECMAScript это оператор, возвращающий значение undefined.
Оператор == осуществляет проверку на равенство по алгоритму, состоящему из 10 шагов, подразумевающего в ряде случаев преобразование типов, что, в конечном счёте, может привести к неочевидным результатам.
Пример результатов работы == (во всех перечисленных случаях значением оператора === с теми же аргументами будет false):
alert("NaN" == NaN); // false alert(NaN == NaN); // false alert(true == 1); // true alert(true == 42); // false alert(null == 0); // false alert(0 == ""); // true alert("" == 0); // true alert("false" == false); // false alert(false == 0); // true alert(undefined == false); // false alert(null == false); // false alert(undefined == null); // true alert(" \t\r\n " == 0); // true
Объекты.
первоисточник понимания http://karaboz.ru/?p=5
var <имя_объекта> = new <Тип_объекта> ('Привет мир');
Это типичный пример. Ключевые слова:
- var - создает локальную переменную, не принадлежащую объекту window
- new - создает новую область видимости, отличную от области видимости window.
Пример создания объектов разных типов:
var num = new Number(12345.6789); | var num = 12345.6789; |
var c = new Boolean(true); | var bul = true; |
var fun = new Function('x', 'var p = x'); | var fun = function(x){var p = x} |
var arr = new Array('a', 'b', 'c'); | var arr = ['a', 'b', 'c']; |
var obj = new Object(); | var obj = {}; |
Ограничения Следующий код показывает равенство двух переменных (объектов класса String):
var str1 = 'karaboz'; var str2 = new String('karaboz'); alert(str1 == str2); // выводит true
при попытке определить новый пользовательский метод для str1 мы получим ошибку:
str1.tell = function(){ alert(this);} str1.tell(); // выводит ошибку 'str1.tell is not a function'
При этом, для str2 все сработает, как мы и ожидаем:
str2.tell = function(){ alert(this);} str2.tell(); // выводит 'karaboz'
Это ограничение, наложенное JavaScript на переменные (объекты), созданные через строковые, числовые и булевы литералы, тем не менее, не распространяется на объекты, созданные через литералы функции, массива или объекта. Т.е. переменным (объектам), содержащим в себе функцию, или массив, или объект можно напрямую присваивать пользовательские свойства и методы:
var s = 'futurico'; // создаем новое свойство s объекта window (window.s) var f = function(){ // создаем новый метод f объекта window (window.f) alert(this == window); // выводит true alert(this.s); // выводит 'futurico' } f(); // вызываем метод f объекта window (window.f())
f.s = 'karaboz'; // создаем новое свойство s объекта window.f (window.f.s) f.m = function(){ // создаем новый метод m объекта window.f (window.f.m) alert(this == f); // выводит true alert(this.s); // выводит 'karaboz' } f.m(); // вызываем метод m объекта window.f (window.f.m())
Здесь мы наглядно убеждаемся, что функция f, созданная как метод глобального объекта window, сама оказывается объектом, у которого могут быть свои собственные свойства и методы!
Это ограничение, наложенное JavaScript на переменные (объекты), созданные через строковые, числовые и булевы литералы, тем не менее, не распространяется на объекты, созданные через литералы функции, массива или объекта. Т.е. переменным (объектам), содержащим в себе функцию, или массив, или объект можно напрямую присваивать пользовательские свойства и методы:
var s = 'futurico'; // создаем новое свойство s объекта window (window.s) var f = function(){ // создаем новый метод f объекта window (window.f) alert(this == window); // выводит true alert(this.s); // выводит 'futurico' } f(); // вызываем метод f объекта window (window.f())
f.s = 'karaboz'; // создаем новое свойство s объекта window.f (window.f.s) f.m = function(){ // создаем новый метод m объекта window.f (window.f.m) alert(this == f); // выводит true alert(this.s); // выводит 'karaboz' } f.m(); // вызываем метод m объекта window.f (window.f.m())
Здесь мы наглядно убеждаемся, что функция f, созданная как метод глобального объекта window, сама оказывается объектом, у которого могут быть свои собственные свойства и методы!
Вывод
Для того, что бы объект вел себя предсказуемо (это исключает долгую логическую отладку) объекты НАДО СОЗДАВАТЬ ТОЛЬКО ЯВНЫМ СПОСОБОМ
Своийства объекта
первоисточник для понимания http://javascript.ru/tutorial/object/intro
Пусть существует такой объект:
var stroka = new Object('Привет мир');
Добавим свойство объекту:
stroka.property ="Новое свойство объекта"
Удаление метода
delete
Методы объекта
Пусть существует такой объект:
var stroka = new String ('Привет мир');
Добавим этому объекту метод:
stroka.tell = function(){alert(this)}; //область видимости this указывает на объект, которому принадлежит данный метод
Вызовем этот метод:
stroka.tell(); //выведет Привет мир
Волшебная переменная arguments
Переменная, доступная внутри функции и содержащая аргументы и ссылку на саму функцию. Вы можете обращаться к аргументу по номеру, начиная от 0. При этом arguments содержит не объявленные, а реально переданные аргументы.
Следующий пример выведет реально переданные три аргумента, несмотря на то, что в функции их всего два.
function func(a,b) { alert(arguments[0]) alert(arguments[1]) alert(arguments[2]) } func(1,2,3)
Кроме цифровых индексов, у arguments есть свойство length, такое же как у массива.
Благодаря этому можно вызывать функции с переменным числом параметров. В следующем примере функция возвращает сумму всех аргументов.
Пример: сумма аргументов
function sum() { var s = 0 for(var i=0; i<arguments.length; i++) s += arguments[i] return s }
Несмотря на доступ по индексу и наличие свойства length, arguments не является массивом, т.е не принадлежит типу Array.
Поэтому для arguments нельзя напрямую вызвать методы этого класса:
arguments.pop() // ошибка !
Можно, однако, вызвать методы Array через apply/call:
var args = Array.prototype.slice.call(arguments)
Ссылка на функцию arguments.callee
Кроме аргументов, arguments содержит ссылку на выполняющуюся функцию.
Ее можно использовать для задания и чтения статических свойств.
В следующем примере для этого используется статическое свойство called.
Пример: подсчет количества выполнений
function func() { arguments.callee.called++ } func.called = 0; func() func() alert(func.called) // 2
Массивы
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
Организация очереди
/* 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"); }); });
Контекстом во всех событиях выступает объект, который ставился в очередь.
Крайне полезная информация
Это надо обработать
Случайное перемешивание массива
Javascript наследование для чайников
Операторы, их особенности в JS
JavaScript Comparison and Logical Operators
«Лапша» из callback-ов — будьте проще
Как избавиться от пристрастия к синхронности
Спагетти в последовательном вызове асинхронных функций. Теория и практика
javascript - XMLHttpRequest в цикле javascript - XMLHttpRequest подробный анализ примера
Полезные трюки
http://habrahabr.ru/post/155093/
Node.js
process.nextTick(callback) - Гарантированно вызовет функцию callback в следующем цикле eventloop