Java Script

Материал из support.qbpro.ru

Операторы

В 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 Гарден

Модульный подход в JavaScript

Случайное перемешивание массива

Javascript наследование для чайников

Операторы, их особенности в JS

JavaScript Comparison and Logical Operators

Путь асинхронного самурая

«Лапша» из callback-ов — будьте проще

Как избавиться от пристрастия к синхронности

Спагетти в последовательном вызове асинхронных функций. Теория и практика

javascript - XMLHttpRequest в цикле javascript - XMLHttpRequest подробный анализ примера

Многопоточный яваскрипт

Полезные трюки

http://habrahabr.ru/post/155093/

Node.js

process.nextTick(callback) - Гарантированно вызовет функцию callback в следующем цикле eventloop