4. 4
Statement
• Блочное выражение
– if (){}, try{}catch(e){}, function a(){}
• Директива интерпретатору
– return, throw, break, continue, var, …
• Может включать другие блочные выражения
• Может включать выражения
• Не возвращает значение
• Не может быть аргументом Expression
• Можно сделать из Expression – Expression;
http://es5.github.com/#x12
5. 5
Expression
• Оператор
– С одним аргументом typeof, !, (), ++, --, new, +,…
– С двумя ==, ===, >, <, instanceof, +, -,…
– С тремя a?b:c,…
– Вызов функции
– Оператор запятая
• Может включать другие операторы
• Не может включать Statement
• Возвращает значение
• Может быть в составе Statement
http://es5.github.com/#x11
7. 7
Приведение типов
• Зависит от оператора
– Оператор имеет определенный алгоритм
• Зависит от типа аргументов
• Внутренние функции JavaScript
– ToNumber, ToString, ToBoolean, ToObject
8. 8
Сильно перегружен: сложение чисел, конкатенация строк
"2" + 3; // "23"
2 + 3; // 5
Пример: оператор + и примитивы
// Что происходит в внутренностях JavaScript
a = ToPrimitive(a);
b = ToPrimitive(b);
if (Type(a) === "String" ||
Type(b) === "String") {
return Concat(ToString(a), ToString(b));
} else {
return ToNumber(2) + ToNumber(3);
}
http://es5.github.com/#x11.6.1
10. 10
Применяется тот же алгоритм
Вся «магия» в ToString({})
"2" + {}; // "2[object Object]"
Пример: оператор + объект
Concat(ToString("2"), ToString({}));
ToString({}) ->
ToPrimitive({}, "String")
ToPrimitive({}, "String") ->
({}).[[DefaultValue]]("String")
http://es5.github.com/#x8.12.8
11. 11
Применяется тот же алгоритм
Вся «магия» в ToString({})
Пример: оператор + объект
if (IsCallable({}.toString)) {
return ({}).toString();
} else if (IsCallable({}.valueOf)) {
return ({}). valueOf();
} else {
throw new TypeError();
}
http://es5.github.com/#x8.12.8
19. 19
На самом деле Function в
JavaScript – это Object со
скрытым полем [[Call]]
http://es5.github.com/#x13.2
20. 20
- Это Statement
- Инициализируется во время входа в контекст
- Объявляется в блоке функции или в глобальном блоке
a(); // OK
function a() {
b(); // OK
function b() {
}
}
a();
Function Declaration/Definition
http://es5.github.com/#x13
21. 21
- Это тоже Statement
- Инициализируется во время входа в контекст или в рантайме
- По стандарту такая запись недопустима
if (true) {
function a() {
return 1;
}
} else {
function a() {
return 2;
}
}
a(); // Firefox – 1, Others - 2
Conditional Function Declaration
22. 22
- При использовании строгого режима тут будет SyntaxError
"use strict";
if (true) {
function a() {
return 1;
}
} else {
function a() {
return 2;
}
}
// SyntaxError
// Use Function Expression!
CFD+Strict Mode
23. 23
- Это expression
- Инициализируется в рантайме
- Объявляется где угодно
a(); // error
var a = function () {
b(); // error
var b = function () {};
b(); // ok
};
a(); // ok
Function Expression
http://es5.github.com/#x11.2.5
24. 24
- Это тот же Function Expression
- Можно обратиться к себе по своему имени
- Имя доступно только в своем блоке (кроме старых IE)
(function timer() {
setTimeout(timer, 1000);
console.log(+new Date);
}());
typeof timer; // undefined, Old IE -
function
Named Function Expression
25. 25
- Это тот же Function Expression
- Мы даем понять интерпретатору, что этот код - Function Expression
- IEFE позволяет эмулировать блочную область видимости
function (){}(); // SyntaxError
!function (){}(); // OK
+function (){}(); // OK
*function (){}(); // OK
(function (){}()); // OK
[function (){}()]; // OK
var a = function (){}();
var a = (function (){}()); // The best
IEFE
26. Область видимости
Определяется во время создания функции
Не меняется при передаче функции
Образует цепочку областей видимости
Лексическая
Образует «замыкание»
27. 27
var a = 1;
function foo() {
var c = 2;
function bar(e) {
return a + c + e;
}
return bar(3);
}
foo(); // 6
Область видимости
http://es5.github.com/#x10.3
http://es5.github.com/#x10.2
29. Вызов функции и this
this – основная грабля в JavaScript
Прямой вызов
Вызов через c оператором точка и []
Вызов через new
Вызов через call, apply, bind
31. 31
() – это оператор вызова функции
this всегда undefined но он трансформируется в global
В строгом режиме всегда undefined (трансформации нет)
function a() {
console.log(this);
}
a(); // window (undefined -> window)
function b() {
"use strict";
console.log(this);
}
b(); // undefined
Прямой вызов – через оператор ()
32. 32
Это Expression
this – объект от которого был получена эта функция
var foo = {
bar: function () {
console.log(this);
}
};
foo.bar(); // foo
var baz = {};
baz.bar = foo.bar;
baz.bar(); // baz
var fooBar = foo.bar;
fooBar(); // ???
Вызов функции и оператор . и []
http://es5.github.com/#x11.2.1
33. 33
Это Expression
new – это еще один способ вызова функции
Каждая функция может быть конструктором
this – пустой объект со ссылкой на prototype вызываемой функции
var A = function () {
console.log(this);
console.log(
this.__proto__ === A.prototype
);
};
new A(); // Object, true
Оператор new
http://es5.github.com/#x11.2.2
34. 34
Это способ управлять значением this
this – объект, который вы передаете
var a = function (a, b) {
console.log(this, a, b);
};
a.call([]); // [], undefined, …
a.call([], 1, 2); // [], 1, 2
a.apply([], [1, 2]); // [], 1, 2
Call, apply
http://es5.github.com/#x15.3.4.4
http://es5.github.com/#x15.3.4.3
35. 35
Это способ подменять this без вызова функции
this – объект, который вы передаете
var a = function () {
console.log(this);
};
var b = a.bind({});
b(); // {}
Bind
http://es5.github.com/#x15.3.4.5
MDN Function#bind http://clck.ru/2EeTx
37. 37
Передача значения в функцию
• Значения передаются по ссылке
• Можно менять «поля» переданного объекта
• Примитив менять нельзя
• Можно переписать ссылку без потери
объекта
38. 38
arguments
• Как и this появляется при вызове
• Это не Array
• Содержит список всех аргументов
– arguments[0]…
• Содержит ссылку на вызывающий конекст
– arguments.caller
– Deprecated!
• Содержит ссылку на себя
– arguments.calle
http://es5.github.com/#x10.6
41. 41
Сказка о мутантах
• В далекой-далекой галактике
• Нет привычного нам наследования
• Есть телепатическое наследование
– "Телегенез"
• Действующие лица:
– Дедушка
– Отец
– Сын
49. 49
Мутанты и JavaScript
Size,
Age
Color
Объект
Свойства
прототипа
Собственные
свойства
Делегирование
Цепочка прототипов
50. 50
Собственные свойства и прототип
• Собственные свойства
• Свойства прототипа
• Любой объект имеет ссылку на прототип
– И примитив также*
– Имеет с рождения
– По умолчанию – Object.prototype
• Делегирование
– Мы можем пользоваться функциями прототипа не имея собственных
• Цепочка прототипов
– Каждый прототип это тот же объект
– Который также может иметь прототип
– У прототипа прототипа также может быть прототип
51. 51
prototype и __proto__
• prototype – свойство функции
– Оно есть у функции с рождения
– По умолчанию это пустой объект
• __proto__ – ссылка на prototype у объекта
– Во многих движках JavaScript оно скрыто
– Определяется во время работы оператора new
http://es5.github.com/#x15.3.5.2
http://es5.github.com/#x8.6.2
53. 53
Работа оператора new
• new(Constructor, arguments):*!
• Получает на вход 2 операнда
– Функция должна иметь свойство prototype
• Создает временный объект (obj)
• Добавляет свойство __proto__
– obj.__proto__ = Constructor.prototype
• Вызывает конструктор над объектом
– Constructor.apply(obj, arguments)
• Конструктор вернул примитив. Результат obj
• Иначе то, что вернул конструктор
54. 54
function myNew(Constructor, args) {
if (typeof Constructor !== "function") {
throw new TypeError();
}
if (typeof Constructor.prototype === "undefined") {
throw new TypeError();
}
var obj = {
__proto__: Constructor.prototype
};
var result = Constructor.apply(obj, args);
if (typeof result === "object" && result !== null ||
typeof result === "function") {
return result;
}
return obj;
}
Оператор new в коде
55. 55
Цепочка прототипов
// Конструктор Grandfather
var Grandfather = function () {};
Grandfather.prototype.color = 'green';
// Конструктор Father
var Father = function () {};
typeof Father.prototype === 'object';
// Для цепочки нам нужно получить вот это
Father.prototype = {
__proto__: Grandfather.prototype
};
56. 56
Строим цепочку прототипов явно
// Конструктор Father
var Father = function () {};
Father.prototype = new Grandfather();
// Как помним, это аналогично:
Father.prototype = {
__proto__: Grandfather.prototype
};
58. 58
Оператор . и []
• Выполняет поиск свойства
• Использует цепочку прототипов
• Ищет в собственных свойствах
• Затем рекурсивно по ссылке __proto__
• Если __proto__ null – возвратит undefined
http://es5.github.com/#x11.2.1
59. 59
var Foo = function () {
// Собственное свойство
this.b = 146;
};
Foo.prototype.bar = function () {
console.log(this);
};
Foo.prototype.a = 123;
Оператор . и []
60. 60
var foo = new Foo();
foo.__ptoto__ === Foo.prototype;
Оператор . и []
61. 61
Оператор . и []
foo
b 146
__proto__ object
Foo.prototype
bar function
a 123
__proto__ object
Object.prototype
__proto__ null
http://es5.github.com/#x4.2.1
68. Strict Mode
На самоподготовку
- выделите отличия от обычного режима
- всегда ли стоит применять Strict Mode?
- в каком месте кода стоит объявлять SM?
http://es5.github.com/#x10.1.1