О себе
Александр Кучеренко
• В DataArt 1,5 месяца
• Занимаюсь программированием 7+ лет
• За это время писал на: PHP, JavaScript,
ActionScript3, C#, Java(Android), Objective-C
Поговорим о JavaScript
1. Объекты в JavaScript, лямбды,
замыкания.
2. Deferred & Promises.
3. Библиотека Q.
С чего начиналось
С чего все начиналось:
• Ajax
• Web 2.0
• jQuery
Что сейчас
• Полноценные веб приложения (GoogleDoc, eyeOs, FirefoxOS,
ChromeOS)
• Мобильные приложения (PhoneGap, jQuery Mobile, Sencha
Touch)
• Серверный JavaScript (Node JS)
• Инструменты (MongoDB, JSON, NPM, Bower, Grunt)
• Тестирование: Buster.js, Karma, TestSwarm, JsTestDriver, YUI Yeti,
Jasmine, QUnit, Sinon
• 3D графика WebGL
Базовые типы
Элементарные
• Number
• Boolean
• String
• Null
• undefined
String
Array
Date
Объекты
Function
…
Number
• Float64 - 8 байт
• console.log(0.1+0.2)
> 0.3 ?
> 0.30000000000000004
• BCMath for JavaScript
• 0.1234.toFixed(2) = 0.12
Number
• При операциях с Number - никогда не происходят
ошибки. Зато могут быть возвращены специальные
значения
• 1/0 = Number.POSITIVE_INFINITY (плюс бесконечность)
• -1/0 = Number.NEGATIVE_INFINITY (минус бесконечность)
• Положительная бесконечность
Number.POSITIVE_INFINITY больше любого Number, и
даже больше самой себя.
Number
• NaN - особый результат
• Любая математическая операция с NaN дает NaN:
– NaN + 1 = NaN
• NaN не равен сам себе:
– NaN == NaN // false
• Можно проверить с помощью функции isNaN:
– isNaN(NaN) // true
String
• Строки в javascript - полностью юникодные
• Кавычки двойные и одинарные работают одинаково
• Можно указывать юникодные символы через
uXXXX:
• Встроены регулярные выражения, методы
replace/match:
"превед медвед".replace(/(.*?)s(.*)/, "$2, $1!") // => медвед, превед!
Boolean
• False
– false
– null
– undefined
– “”
– 0
– Number.NaN
• True – все остальное
– “0” (В PHP FALSE)
– “false”
undefined
• При попытке доступа к глобальной переменной undefined (если
она не изменена).
• Неявный возврат из функции при отсутствии в ней оператора
return.
• Из операторов return, которые ничего не возвращают.
• В результате поиска несуществующего свойства у объекта (и
доступа к нему).
• Параметры, которые не были переданы в функцию явно.
• При доступе ко всему, чьим значением является undefined.
undefined
• undefined — это тип с единственным возможным
значением: undefined
• Не являясь константой, она не является и ключевым
словом. Можно с лёгкостью переопределить
// Happy debugging suckers ...
undefined = true;
(function(something, foo, undefined) {
// в локальной области видимости `undefined`
// снова ссылается на правильное значене.
})('Hello World', 42);
NULL
• Используется во внутренних механизмах
JavaScript (например для определения
конца цепочки прототипов за счёт
присваивания Foo.prototype = null)
Объекты
• В JavaScript всё ведет себя, как объект, лишь
за двумя исключениями — NULL и
UNDEFINED.
• Почему у примитивов можно вызвать
методы?
Объекты и примитивы
var number = 2;
// Можно вызвать метод
console.log(number.toString()); // -> 2
// Попробуем задать свойство
number.newProperty = 3;
console.log(number.newProperty); // -> undefined
// Если нельзя, но сильно хочется, то - можно
Number.prototype.newProperty = 3;
console.log(number.newProperty); // -> 3
Function
• Функции в JavaScript тоже являются
объектами
Пример №1:
foo(); // сработает, т.к. функция будет создана до выполнения кода
function foo() {}
Пример №2:
foo; // 'undefined'
foo(); // вызовет TypeError
var foo = function() {};
Область видимости
Пример №1:
function test() { // область видимости
for(var i = 0; i < 10; i++) { // не область видимости
// считаем
}
console.log(i); // 10
}
Хотя JavaScript нормально понимает синтаксис двух фигурных скобок,
окружающих блок, он не поддерживает блочную область видимости; всё что
остаётся на этот случай в языке — область видимости функций.
Как работает this
1. Глобальная область видимости
Когда мы используем this в глобальной области, она будет просто ссылаться
на глобальный объект.
Различают ровно пять вариантов того, к чему привязывается this в языке.
4. Вызов конструктора
new foo();
Если перед вызовом функции присутствует ключевое слово new то данная
функция будет действовать как конструктор. Внутри такой функции this будет
указывать на новосозданный Object.
2. Вызов функции
foo(); // Тут this также ссылается на глобальный объект
3. Вызов метода
test.foo(); // Тут this также ссылается на глобальный объект.
Как работает this
5. Переопределение this
Переопределить this можно с помощью методов apply, call и bind
Пример №1:
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // массив развернётся в a = 1, b = 2, c = 3
foo.call(bar, 1, 2, 3); // аналогично
Как работает this
Пример самой распространённой ошибки:
Foo.method = function() {
function test() {
// this ???
}
test();
}
Как работает this
Пример самой распространённой ошибки:
Foo.method = function() {
function test() {
// this ссылается на глобальный объект
}
test();
}
Как работает this
Достойно выходим из ситуации:
Foo.method = function() {
var that = this;
function test() {
// Здесь используем that вместо this
}
test();
}
Как работает this
А что если…
var test = someObject.methodTest;
test();
Как работает this
А что если…
var test = someObject.methodTest;
test();
Следуя первому правилу test вызывается как обычная функция; следовательно
this внутри него больше не ссылается на someObject
Хотя позднее связывание this на первый взгляд может показаться плохой идеей,
но на самом деле именно благодаря этому работает наследование прототипов.
Замыкания
Замыкание в JavaScript:
function outerFn(myArg) {
var myVar = 42;
function innerFn() {
// имеет доступ к myVar и myArg
}
}
Замыкания
Замыкание в PHP:
function getNumber() {
$id = 42;
return function() use ($id){
return $id*2;
};
}
Замыкания
Классика:
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}
, 1000);}
Замыкания
• Каждое выполнение функции хранит все
переменные в специальном объекте с
кодовым именем [[scope]], который нельзя
получить в явном виде, но он есть
• Каждый вызов var... - всего лишь создает
новое свойство этого объекта, а любое
упоминание переменной - первым делом
ищется в свойствах этого объекта
Замыкания
Обычное выполнение функции без замыкания:
function sum(x,y) {
// неявно создался объект [[scope]]
...
// в [[scope]] записалось свойство z
var z;
// нашли переменную в [[scope]], [[scope]].z = x+y
z = x+y;
// нашли переменную в [[scope]], return [[scope]].z
return z;
// функция закончилась,
// [[scope]] никому больше не нужен и умирает вместе с z
}
Замыкания
Замыкание - это когда объект локальных
переменных [[scope]] внешней функции
остается жить после ее завершения.
Внутренняя функция может обратиться к
нему в любой момент и получить
переменную внешней функции.
Замыкания
Выполнение функции с замыканием:
function addHideHandler(sourceId, targetId) {
// создан объект [[scope]] со свойствами sourceId, targetId
// записать в [[scope]] свойство sourceNode
var sourceNode = document.getElementById(sourceId);
// записать в [[scope]] свойство handler
var handler = function() {
var targetNode = document.getElementById(targetId);
targetNode.style.display = 'none';
};
sourceNode.onclick = handler;
// функция закончила выполнение
// (***) и тут - самое интересное!
}
Замыкания
При запуске функции все происходит стандартно:
1. создается [[scope]]
2. туда записываются локальные переменные
3. внутренняя функция получает ссылку на [[scope]]
Но в самом конце - внутренняя функция присваивается sourceNode.onclick.
Внешняя функция закончила свою работу, но внутренняя - может запуститься
когда-нибудь потом.
Интерпретатор javascript не проводит анализ - понадобятся ли внутренней
функции переменные из внешней, и какие переменные могут быть нужны.
Вместо этого он просто оставляет весь [[scope]] внешней функции в живых.
Чтобы когда внутренняя функция запустится, если она вдруг не найдет какую-либо
переменную в своем [[scope]] - она могла обратиться к [[scope]] внешней функции
и нашла бы ее там.
Замыкания
Пример:
function makeShout() {
var phrase = "Превед!”;
var shout = function() {
alert(phrase);
}
phrase = "Готово!";
return shout;
}
shout = makeShout();
shout(); // что выдаст?
Замыкания
Пример:
function makeShout() {
var phrase = "Превед!”;
var shout = function() {
alert(phrase);
}
phrase = "Готово!";
return shout;
}
shout = makeShout();
shout();
1. создается [[scope]]
2. В [[scope]] пишется: phrase="Превед!”
3. В [[scope]] пишется: shout=..функция..
4. При создании функция shout получает
ссылку на [[scope]] внешней функции
5. [[scope]].phrase меняется на новое значение
"Готово!”
Внутри makeShout()
Замыкания
Пример:
function makeShout() {
var phrase = "Превед!”;
var shout = function() {
alert(phrase);
}
phrase = "Готово!";
return shout;
}
shout = makeShout();
shout();
1. Создается свой собственный объект
[[scope2]]
2. Ищется phrase в [[scope2]] - не найден
3. Ищется phrase в [[scope]] внешней функции -
найдено значение "Готово!”
4. alert("Готово!")
При запуске shout()
То есть, внутренняя функция получает
последнее значение внешних
переменных.
Замыкания
Счетчик:
function makeCounter() {
var numberOfCalls = 0;
return function() {
return ++numberOfCalls;
}
}
var counter1 = makeCounter();
console.log(counter1()); // -> 1
console.log(counter1()); // -> 2
console.log(counter1()); // -> 3
var counter2 = makeCounter();
console.log(counter2()); // -> 1
console.log(counter2()); // -> 2
lambda-функции VS
анонимные функции
• Согласно wiki синонимы
• Есть подозрение что замешан python
lambda х, у: х+у
Почему асинхронность это
сложно?
Callback hell in action
getUser(params["id"], function(err,user) {
if(!user) return res.send(404);
getProfile(user, function(err,profile) {
if(err) return res.send(500);
if(profile) {
update(user,profile,params,function(err) {
if(err) return res.send(500);
res.send(profile);
})
} else {
create(user,params,function(err,profile) {
if(err) return res.send(500);
res.send(profile);
})
}
})
});
Это можно поправить
getUser(params["id"],gotUser);
function gotUser(err,user) {
if(!user) return res.send(404);
// don't inline closure, use bind
getProfile(user,saveProfile.bind(this,user));
}
function saveProfile(user,err,profile) {
if(err) return res.send(500);
if(profile) {
update(user,profile,params,saved);
} else {
create(user,params,saved);
}
}
Выполнение
параллельных задач
var updatedA = false;
var updatedB = false;
updateA(function() {
if(updatedB) done()
updatedA = true;
})
updateB(function() {
if(updatedA) done()
updatedB = true;
})
Когда задач много
var files = [a,b,c,d];
var filtered = [];
var done = 0;
files.forEach(function(file){
something(file, function(passed) {
if(!passed) return;
filtered.push(f);
done += 1;
if(done == files.length) cb();
})
});
Deferred and Promises
Deferred — это отложенный результат,
который станет известен через некоторое
время.
Deferred and Promises
readFile("file.txt", function (err, result) {
// continue here…
});
// becomes
var promiseForResult = readFile("file.txt");
Deferred and Promises
1. Создать Deferred объект
2. При завершении
асинхронного метода
перевести Deferred объект в
нужное состояние
3. Передать Deferred.promise
объект из текущей функции
куда-то, где его состояние
будут отслеживать.
function readFile(fileName){
var deferred = Q.defer();
readFileAsync(fileName, function(error, result){
if(error){
deferred.reject(error);
}else{
deferred.resolve(result);
}
});
return deferred.promise;
}
Инструкция
Почему при возврате из функции
передается не сам Deferred объект, а
именно Promise?
Deferred and Promises
• Deferred объект — это всего лишь хранилище состояния
асинхронной функции. Таких состояний обычно несколько:
– pending — ожидание завершения процесса
– rejected — процесс закончен падением
– resolved — процесс закончен успешно
• Кроме того у Deferred объекта есть ряд методов, которые могут
менять его состояние. Например, метод .resolve().
• По состоянию Deferred объекта мы можем судить, закончен ли
процесс, состояние которого мы отслеживаем.
Deferred and Promises
• Обработчики выполняются последовательно
• Если обработчик «выполнения»/«ошибки» добавляется
к уже «выполненному»/«отменённому» объекту, то он
будет вызван немедленно.
• Повторный вызов resolve/reject не приводт к изменению
состояния и повторному вызову обработчиков, а просто
игнорируется (и не важно, что было вызвано до этого
resolve() или reject()).
• Хотя promises появились в jQuery 1.5 лучше их не юзать
Библиотека Q
• Установка: npm, bower, NuGet
• Модули для: Node.js, CommonJS, AMD,
microjs
• Понимает промисы: jQuery, Dojo, When.js,
WinJS
• Множество сторонних модулей
• mongoose-q, mongo-q
Библиотека Q
• .then, .done, .catch(fail), .finally(fin)
readFile("file.txt")
.then(function(contentOfFile){
// Do something with content
})
.catch(function(error){
// Handle error
})
.finally(function(){
// Call always
})
.done();
Библиотека Q
• .then – выполняем последовательно
readFile("file.txt")
.then(function(contentOfFile){
// Do something with contentOfFile
return readFile("file2.txt")
})
.then(unction(contentOfFile2){
// Do something with contentOfFile2
return readFile("file3.txt")
})
.catch(function(error){
// Error handle
})
.done()
Библиотека Q
• .then – выполняем последовательно
readFile("file.txt")
.then(readFile("file2.txt"))
.then(readFile("file3.txt"))
.catch(function(error){
// Error handle for file, file2 and file3
})
.then(readFile("file4.txt"))
.then(readFile("file5.txt"))
.catch(function(error){
// Error handle for file4 and file5
})
.done()
Библиотека Q
• .when, .all – выполняем параллельно
Q.when(readFile("file.txt"), readFile("file2.txt"))
.catch()
.done()
Q.all([readFile("file.txt"), readFile("file2.txt”])
.catch()
.done()
Библиотека Q
• .spread
Q.all([readFile("file.txt"), readFile("file2.txt”])
.spread(function(contentOfFile, contentOfFile2){
// Do something with contentOfFile1-2
})
.catch()
.done()
getUsername()
.then(function (username) {
return [username, getUser(username)];
})
.spread(function (username, user) {
// do something
})
.catch()
.done();
Библиотека Q
Sequences
var funcs = [foo, bar, baz, qux];
funcs.reduce(Q.when, Q());
Q in Node.js
// 1
Q.nfcall(FS.readFile, "foo.txt", "utf-8");
// 2
var readFile = Q.denodeify(FS.readFile);
return readFile("foo.txt", "utf-8");
// 3
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", deferred.makeNodeResolver());
return deferred.promise;
Q and jQuery
Q(jQuery.ajax("foobar.html”))
.then(function (data) {
// on success
})
.catch()
.done()
Вопросы
Ссылочки
Полезно почитать:
• http://bonsaiden.github.io/JavaScript-Garden/
NO MORE PYRAMIDS
• http://timruffles.github.io/reject-js-2013-talk/#/
Lib Q
• https://github.com/kriskowal/q
Мой Github:
• https://github.com/AlexTiTanium

More Related Content

PPTX
Bytecode
PPTX
PDF
Объектно-ориентированное программирование. Лекция 5 и 6
PDF
C++ refelection and cats
PDF
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4
PDF
Михаил Давыдов: JavaScript. Базовые знания
PDF
Михаил Давыдов - JavaScript. Базовые знания
PDF
Объектно-ориентированное программирование. Лекции 9 и 10
Bytecode
Объектно-ориентированное программирование. Лекция 5 и 6
C++ refelection and cats
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4
Михаил Давыдов: JavaScript. Базовые знания
Михаил Давыдов - JavaScript. Базовые знания
Объектно-ориентированное программирование. Лекции 9 и 10

What's hot (20)

PDF
Борис Сазонов, RAII потоки и CancellationToken в C++
PDF
Михаил Давыдов — JavaScript: Базовые знания
PDF
Объектно-ориентированное программирование. Лекция 7 и 8.
PPTX
Современный статический анализ кода: что умеет он, чего не умели линтеры
PPTX
Александр Фокин, Рефлексия в C++
PDF
Инструментируй это
PPTX
Владимир Горбенко «Использование блоков в Objective-C»
PPTX
функции в Java script
PDF
JPoint 2015 - Javassist на службе Java-разработчика
PDF
JavaScript Базовый. Занятие 03.
PDF
Лекция 13. Многопоточность и GIL
PPTX
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
PDF
Шишки, набитые за 15 лет использования акторов в C++
PDF
C++ осень 2012 лекция 9
PDF
Лекция 9. Модули, пакеты и система импорта.
PDF
Лекция 11. Тестирование.
PDF
C++ Базовый. Занятие 02.
PPTX
C#. От основ к эффективному коду
PDF
JavaScript Базовый. Занятие 02.
PDF
Фундаментальные основы разработки под iOS. Павел Тайкало
Борис Сазонов, RAII потоки и CancellationToken в C++
Михаил Давыдов — JavaScript: Базовые знания
Объектно-ориентированное программирование. Лекция 7 и 8.
Современный статический анализ кода: что умеет он, чего не умели линтеры
Александр Фокин, Рефлексия в C++
Инструментируй это
Владимир Горбенко «Использование блоков в Objective-C»
функции в Java script
JPoint 2015 - Javassist на службе Java-разработчика
JavaScript Базовый. Занятие 03.
Лекция 13. Многопоточность и GIL
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Шишки, набитые за 15 лет использования акторов в C++
C++ осень 2012 лекция 9
Лекция 9. Модули, пакеты и система импорта.
Лекция 11. Тестирование.
C++ Базовый. Занятие 02.
C#. От основ к эффективному коду
JavaScript Базовый. Занятие 02.
Фундаментальные основы разработки под iOS. Павел Тайкало
Ad

Similar to Поговорим о JavaScript, основы и современные тенденции развития языка (20)

PPTX
Javascript functions
PPTX
Denys Samoylenko ''JS learning lifehacks: common programmer's mistake''
PDF
JavaScript. Loops and functions (in russian)
PPT
Подробная презентация JavaScript 6 в 1
PPT
Подробная презентация JavaScript 6 в 1
PDF
Михаил Давыдов - Транспорт, ajax
PDF
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScript
PDF
Web internship java script
PDF
Как пройти собеседование по js? И зачем? | Odessa Frontend Meetup #4
PDF
JavaScript. Basics (in russian)
PPTX
Javascript 1
PPT
Javascript
PDF
Solit 2014, EcmaScript 6 in Action, Трухин Юрий
PDF
Ecma script 6 in action
PPT
ООП в JavaScript
PPTX
OOP in JavaScript - Presentation by Eugene Kalosha
PPTX
course js day 2
PDF
new JavaScript
PDF
Обзор ES2015(ES6)
Javascript functions
Denys Samoylenko ''JS learning lifehacks: common programmer's mistake''
JavaScript. Loops and functions (in russian)
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1
Михаил Давыдов - Транспорт, ajax
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScript
Web internship java script
Как пройти собеседование по js? И зачем? | Odessa Frontend Meetup #4
JavaScript. Basics (in russian)
Javascript 1
Javascript
Solit 2014, EcmaScript 6 in Action, Трухин Юрий
Ecma script 6 in action
ООП в JavaScript
OOP in JavaScript - Presentation by Eugene Kalosha
course js day 2
new JavaScript
Обзор ES2015(ES6)
Ad

Поговорим о JavaScript, основы и современные тенденции развития языка

  • 1. О себе Александр Кучеренко • В DataArt 1,5 месяца • Занимаюсь программированием 7+ лет • За это время писал на: PHP, JavaScript, ActionScript3, C#, Java(Android), Objective-C
  • 2. Поговорим о JavaScript 1. Объекты в JavaScript, лямбды, замыкания. 2. Deferred & Promises. 3. Библиотека Q.
  • 3. С чего начиналось С чего все начиналось: • Ajax • Web 2.0 • jQuery
  • 4. Что сейчас • Полноценные веб приложения (GoogleDoc, eyeOs, FirefoxOS, ChromeOS) • Мобильные приложения (PhoneGap, jQuery Mobile, Sencha Touch) • Серверный JavaScript (Node JS) • Инструменты (MongoDB, JSON, NPM, Bower, Grunt) • Тестирование: Buster.js, Karma, TestSwarm, JsTestDriver, YUI Yeti, Jasmine, QUnit, Sinon • 3D графика WebGL
  • 5. Базовые типы Элементарные • Number • Boolean • String • Null • undefined String Array Date Объекты Function …
  • 6. Number • Float64 - 8 байт • console.log(0.1+0.2) > 0.3 ? > 0.30000000000000004 • BCMath for JavaScript • 0.1234.toFixed(2) = 0.12
  • 7. Number • При операциях с Number - никогда не происходят ошибки. Зато могут быть возвращены специальные значения • 1/0 = Number.POSITIVE_INFINITY (плюс бесконечность) • -1/0 = Number.NEGATIVE_INFINITY (минус бесконечность) • Положительная бесконечность Number.POSITIVE_INFINITY больше любого Number, и даже больше самой себя.
  • 8. Number • NaN - особый результат • Любая математическая операция с NaN дает NaN: – NaN + 1 = NaN • NaN не равен сам себе: – NaN == NaN // false • Можно проверить с помощью функции isNaN: – isNaN(NaN) // true
  • 9. String • Строки в javascript - полностью юникодные • Кавычки двойные и одинарные работают одинаково • Можно указывать юникодные символы через uXXXX: • Встроены регулярные выражения, методы replace/match: "превед медвед".replace(/(.*?)s(.*)/, "$2, $1!") // => медвед, превед!
  • 10. Boolean • False – false – null – undefined – “” – 0 – Number.NaN • True – все остальное – “0” (В PHP FALSE) – “false”
  • 11. undefined • При попытке доступа к глобальной переменной undefined (если она не изменена). • Неявный возврат из функции при отсутствии в ней оператора return. • Из операторов return, которые ничего не возвращают. • В результате поиска несуществующего свойства у объекта (и доступа к нему). • Параметры, которые не были переданы в функцию явно. • При доступе ко всему, чьим значением является undefined.
  • 12. undefined • undefined — это тип с единственным возможным значением: undefined • Не являясь константой, она не является и ключевым словом. Можно с лёгкостью переопределить // Happy debugging suckers ... undefined = true; (function(something, foo, undefined) { // в локальной области видимости `undefined` // снова ссылается на правильное значене. })('Hello World', 42);
  • 13. NULL • Используется во внутренних механизмах JavaScript (например для определения конца цепочки прототипов за счёт присваивания Foo.prototype = null)
  • 14. Объекты • В JavaScript всё ведет себя, как объект, лишь за двумя исключениями — NULL и UNDEFINED. • Почему у примитивов можно вызвать методы?
  • 15. Объекты и примитивы var number = 2; // Можно вызвать метод console.log(number.toString()); // -> 2 // Попробуем задать свойство number.newProperty = 3; console.log(number.newProperty); // -> undefined // Если нельзя, но сильно хочется, то - можно Number.prototype.newProperty = 3; console.log(number.newProperty); // -> 3
  • 16. Function • Функции в JavaScript тоже являются объектами Пример №1: foo(); // сработает, т.к. функция будет создана до выполнения кода function foo() {} Пример №2: foo; // 'undefined' foo(); // вызовет TypeError var foo = function() {};
  • 17. Область видимости Пример №1: function test() { // область видимости for(var i = 0; i < 10; i++) { // не область видимости // считаем } console.log(i); // 10 } Хотя JavaScript нормально понимает синтаксис двух фигурных скобок, окружающих блок, он не поддерживает блочную область видимости; всё что остаётся на этот случай в языке — область видимости функций.
  • 18. Как работает this 1. Глобальная область видимости Когда мы используем this в глобальной области, она будет просто ссылаться на глобальный объект. Различают ровно пять вариантов того, к чему привязывается this в языке. 4. Вызов конструктора new foo(); Если перед вызовом функции присутствует ключевое слово new то данная функция будет действовать как конструктор. Внутри такой функции this будет указывать на новосозданный Object. 2. Вызов функции foo(); // Тут this также ссылается на глобальный объект 3. Вызов метода test.foo(); // Тут this также ссылается на глобальный объект.
  • 19. Как работает this 5. Переопределение this Переопределить this можно с помощью методов apply, call и bind Пример №1: function foo(a, b, c) {} var bar = {}; foo.apply(bar, [1, 2, 3]); // массив развернётся в a = 1, b = 2, c = 3 foo.call(bar, 1, 2, 3); // аналогично
  • 20. Как работает this Пример самой распространённой ошибки: Foo.method = function() { function test() { // this ??? } test(); }
  • 21. Как работает this Пример самой распространённой ошибки: Foo.method = function() { function test() { // this ссылается на глобальный объект } test(); }
  • 22. Как работает this Достойно выходим из ситуации: Foo.method = function() { var that = this; function test() { // Здесь используем that вместо this } test(); }
  • 23. Как работает this А что если… var test = someObject.methodTest; test();
  • 24. Как работает this А что если… var test = someObject.methodTest; test(); Следуя первому правилу test вызывается как обычная функция; следовательно this внутри него больше не ссылается на someObject Хотя позднее связывание this на первый взгляд может показаться плохой идеей, но на самом деле именно благодаря этому работает наследование прототипов.
  • 25. Замыкания Замыкание в JavaScript: function outerFn(myArg) { var myVar = 42; function innerFn() { // имеет доступ к myVar и myArg } }
  • 26. Замыкания Замыкание в PHP: function getNumber() { $id = 42; return function() use ($id){ return $id*2; }; }
  • 27. Замыкания Классика: for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); } , 1000);}
  • 28. Замыкания • Каждое выполнение функции хранит все переменные в специальном объекте с кодовым именем [[scope]], который нельзя получить в явном виде, но он есть • Каждый вызов var... - всего лишь создает новое свойство этого объекта, а любое упоминание переменной - первым делом ищется в свойствах этого объекта
  • 29. Замыкания Обычное выполнение функции без замыкания: function sum(x,y) { // неявно создался объект [[scope]] ... // в [[scope]] записалось свойство z var z; // нашли переменную в [[scope]], [[scope]].z = x+y z = x+y; // нашли переменную в [[scope]], return [[scope]].z return z; // функция закончилась, // [[scope]] никому больше не нужен и умирает вместе с z }
  • 30. Замыкания Замыкание - это когда объект локальных переменных [[scope]] внешней функции остается жить после ее завершения. Внутренняя функция может обратиться к нему в любой момент и получить переменную внешней функции.
  • 31. Замыкания Выполнение функции с замыканием: function addHideHandler(sourceId, targetId) { // создан объект [[scope]] со свойствами sourceId, targetId // записать в [[scope]] свойство sourceNode var sourceNode = document.getElementById(sourceId); // записать в [[scope]] свойство handler var handler = function() { var targetNode = document.getElementById(targetId); targetNode.style.display = 'none'; }; sourceNode.onclick = handler; // функция закончила выполнение // (***) и тут - самое интересное! }
  • 32. Замыкания При запуске функции все происходит стандартно: 1. создается [[scope]] 2. туда записываются локальные переменные 3. внутренняя функция получает ссылку на [[scope]] Но в самом конце - внутренняя функция присваивается sourceNode.onclick. Внешняя функция закончила свою работу, но внутренняя - может запуститься когда-нибудь потом. Интерпретатор javascript не проводит анализ - понадобятся ли внутренней функции переменные из внешней, и какие переменные могут быть нужны. Вместо этого он просто оставляет весь [[scope]] внешней функции в живых. Чтобы когда внутренняя функция запустится, если она вдруг не найдет какую-либо переменную в своем [[scope]] - она могла обратиться к [[scope]] внешней функции и нашла бы ее там.
  • 33. Замыкания Пример: function makeShout() { var phrase = "Превед!”; var shout = function() { alert(phrase); } phrase = "Готово!"; return shout; } shout = makeShout(); shout(); // что выдаст?
  • 34. Замыкания Пример: function makeShout() { var phrase = "Превед!”; var shout = function() { alert(phrase); } phrase = "Готово!"; return shout; } shout = makeShout(); shout(); 1. создается [[scope]] 2. В [[scope]] пишется: phrase="Превед!” 3. В [[scope]] пишется: shout=..функция.. 4. При создании функция shout получает ссылку на [[scope]] внешней функции 5. [[scope]].phrase меняется на новое значение "Готово!” Внутри makeShout()
  • 35. Замыкания Пример: function makeShout() { var phrase = "Превед!”; var shout = function() { alert(phrase); } phrase = "Готово!"; return shout; } shout = makeShout(); shout(); 1. Создается свой собственный объект [[scope2]] 2. Ищется phrase в [[scope2]] - не найден 3. Ищется phrase в [[scope]] внешней функции - найдено значение "Готово!” 4. alert("Готово!") При запуске shout() То есть, внутренняя функция получает последнее значение внешних переменных.
  • 36. Замыкания Счетчик: function makeCounter() { var numberOfCalls = 0; return function() { return ++numberOfCalls; } } var counter1 = makeCounter(); console.log(counter1()); // -> 1 console.log(counter1()); // -> 2 console.log(counter1()); // -> 3 var counter2 = makeCounter(); console.log(counter2()); // -> 1 console.log(counter2()); // -> 2
  • 37. lambda-функции VS анонимные функции • Согласно wiki синонимы • Есть подозрение что замешан python lambda х, у: х+у
  • 39. Callback hell in action getUser(params["id"], function(err,user) { if(!user) return res.send(404); getProfile(user, function(err,profile) { if(err) return res.send(500); if(profile) { update(user,profile,params,function(err) { if(err) return res.send(500); res.send(profile); }) } else { create(user,params,function(err,profile) { if(err) return res.send(500); res.send(profile); }) } }) });
  • 40. Это можно поправить getUser(params["id"],gotUser); function gotUser(err,user) { if(!user) return res.send(404); // don't inline closure, use bind getProfile(user,saveProfile.bind(this,user)); } function saveProfile(user,err,profile) { if(err) return res.send(500); if(profile) { update(user,profile,params,saved); } else { create(user,params,saved); } }
  • 41. Выполнение параллельных задач var updatedA = false; var updatedB = false; updateA(function() { if(updatedB) done() updatedA = true; }) updateB(function() { if(updatedA) done() updatedB = true; })
  • 42. Когда задач много var files = [a,b,c,d]; var filtered = []; var done = 0; files.forEach(function(file){ something(file, function(passed) { if(!passed) return; filtered.push(f); done += 1; if(done == files.length) cb(); }) });
  • 43. Deferred and Promises Deferred — это отложенный результат, который станет известен через некоторое время.
  • 44. Deferred and Promises readFile("file.txt", function (err, result) { // continue here… }); // becomes var promiseForResult = readFile("file.txt");
  • 45. Deferred and Promises 1. Создать Deferred объект 2. При завершении асинхронного метода перевести Deferred объект в нужное состояние 3. Передать Deferred.promise объект из текущей функции куда-то, где его состояние будут отслеживать. function readFile(fileName){ var deferred = Q.defer(); readFileAsync(fileName, function(error, result){ if(error){ deferred.reject(error); }else{ deferred.resolve(result); } }); return deferred.promise; } Инструкция Почему при возврате из функции передается не сам Deferred объект, а именно Promise?
  • 46. Deferred and Promises • Deferred объект — это всего лишь хранилище состояния асинхронной функции. Таких состояний обычно несколько: – pending — ожидание завершения процесса – rejected — процесс закончен падением – resolved — процесс закончен успешно • Кроме того у Deferred объекта есть ряд методов, которые могут менять его состояние. Например, метод .resolve(). • По состоянию Deferred объекта мы можем судить, закончен ли процесс, состояние которого мы отслеживаем.
  • 47. Deferred and Promises • Обработчики выполняются последовательно • Если обработчик «выполнения»/«ошибки» добавляется к уже «выполненному»/«отменённому» объекту, то он будет вызван немедленно. • Повторный вызов resolve/reject не приводт к изменению состояния и повторному вызову обработчиков, а просто игнорируется (и не важно, что было вызвано до этого resolve() или reject()). • Хотя promises появились в jQuery 1.5 лучше их не юзать
  • 48. Библиотека Q • Установка: npm, bower, NuGet • Модули для: Node.js, CommonJS, AMD, microjs • Понимает промисы: jQuery, Dojo, When.js, WinJS • Множество сторонних модулей • mongoose-q, mongo-q
  • 49. Библиотека Q • .then, .done, .catch(fail), .finally(fin) readFile("file.txt") .then(function(contentOfFile){ // Do something with content }) .catch(function(error){ // Handle error }) .finally(function(){ // Call always }) .done();
  • 50. Библиотека Q • .then – выполняем последовательно readFile("file.txt") .then(function(contentOfFile){ // Do something with contentOfFile return readFile("file2.txt") }) .then(unction(contentOfFile2){ // Do something with contentOfFile2 return readFile("file3.txt") }) .catch(function(error){ // Error handle }) .done()
  • 51. Библиотека Q • .then – выполняем последовательно readFile("file.txt") .then(readFile("file2.txt")) .then(readFile("file3.txt")) .catch(function(error){ // Error handle for file, file2 and file3 }) .then(readFile("file4.txt")) .then(readFile("file5.txt")) .catch(function(error){ // Error handle for file4 and file5 }) .done()
  • 52. Библиотека Q • .when, .all – выполняем параллельно Q.when(readFile("file.txt"), readFile("file2.txt")) .catch() .done() Q.all([readFile("file.txt"), readFile("file2.txt”]) .catch() .done()
  • 53. Библиотека Q • .spread Q.all([readFile("file.txt"), readFile("file2.txt”]) .spread(function(contentOfFile, contentOfFile2){ // Do something with contentOfFile1-2 }) .catch() .done() getUsername() .then(function (username) { return [username, getUser(username)]; }) .spread(function (username, user) { // do something }) .catch() .done();
  • 54. Библиотека Q Sequences var funcs = [foo, bar, baz, qux]; funcs.reduce(Q.when, Q());
  • 55. Q in Node.js // 1 Q.nfcall(FS.readFile, "foo.txt", "utf-8"); // 2 var readFile = Q.denodeify(FS.readFile); return readFile("foo.txt", "utf-8"); // 3 var deferred = Q.defer(); FS.readFile("foo.txt", "utf-8", deferred.makeNodeResolver()); return deferred.promise;
  • 56. Q and jQuery Q(jQuery.ajax("foobar.html”)) .then(function (data) { // on success }) .catch() .done()
  • 58. Ссылочки Полезно почитать: • http://bonsaiden.github.io/JavaScript-Garden/ NO MORE PYRAMIDS • http://timruffles.github.io/reject-js-2013-talk/#/ Lib Q • https://github.com/kriskowal/q Мой Github: • https://github.com/AlexTiTanium