9. Nearly all of the books about
JavaScript are quite awful. They
contain errors, poor examples,
and promote bad practices.
— Douglas Crockford,
senior JavaScript Architect at Yahoo!
http://javascript.crockford.com/
29. Функции являются объектами
var snaffle = steal;
snaffle(―Cow‖);
//‖Cow‖
snaffle.call(null, ―Calf‖);
//‖Calf‖
snaffle.apply(null, [ ―Calf‖ ]);
//‖Calf‖
30. Возвращаемое значение
• Все функции возвращают значение
• Если функция ничего не возвращает
явным образом, возвращается undefined
• Функции могут возвращать объекты,
включая другие функции
31. Вызов метода с нужной областью
видимости
При вызове moo this ссылается на
указанную область видимости scope
function moo() {
this.BigSaucerEyes();
};
moo.call( scope, arg1, arg2, …);
moo.apply( scope, [arg1, arg2, …] );
32. Тут начинается магия
Область видимости «по умолчанию» — Window
var UFO = function UFO() {
this.name = ―FO‖;
return this; // посмотрим, что это за this
};
UFO // UFO()
UFO() // Window… Oops!!! Window.name is ―FO‖
new UFO() // Object name=―FO‖
33. Тут продолжается магия
var ufo = new UFO() эквивалентно
var ufo = {};
UFO.call(ufo, null)
ufo // Object name=―FO‖
Если this возвращается вручную внутри
конструктора (return this), тогда можно писать
var ufo = UFO.call({}, null);
34. Замыкания (Closures)
• Соседние функции
• Вложенные функции имеют доступ к
локальным переменным даже после
выполнения внешней функции
35. Замыкания (Closures)
function outer()
{
var count = 1;
function inner() { count++; };
return inner;
}
var myClosure = outer();
myClosure(); // count == 2
myClosure(); // count == 3
36. Функции-конструкторы
• При вызове с оператором new функции
возвращают объект, обозначаемый как
this
• Этот объект можно изменять перед
передачей из фунции
43. Встроенные конструкторы
• Object
• Array
• Function
• RegExp
• Number
• String
• Boolean
• Date
• Error, SyntaxError, ReferenceError, …
44. Эффективность
использования
Хорошо Плохо
var o = {}; var o = new Object();
var a = []; var a = new Array();
var re = /[a-z]/gmi; var re = new RegExp(‗[a-z]‘, ‗gmi‘);
var fn = function(a, b) {
var fn = new Function(‗a, b‘, ‗return
return a+b;
a+b‘);
}
45. Статические свойства и
методы
Функции — объекты.
Свойства и методы конструктора —
работают как статические.
UFO.COUNT = ―100500‖;
UFO.getCount = function() {
return UFO.COUNT;
};
46. Private-члены
function UFO(name) {
var _name = name; // private variable
this.getName = function() {
return _name;
};
};
var ufo= new UFO(―Mars UFO‖);
alert( ufo.getName() );
47. Private-члены
function UFO(name) {
var _name = name;
// private method
var _fixName = function() {
return _name.toUpperCase();
};
this.getName = function() {
return _fixName();
};
};
48. Namespace
if (typeof FlyingObjects== ―undefined‖) {
FlyingObjects = {};
}
if (typeof FlyingObjects.Undefined ==
―undefined‖) {
FlyingObjects.Undefined = {};
}
FlyingObjects.Undefined.UFO = function() {};
var smallUFO = new FlyingObjects.Undefined.UFO;
60. Использование prototype
stealCow() — метод объекта prototype, но
ведет себя так, как будто является методом
самого объекта ufo
ufo.hasOwnProperty(‗name‘);
// true
ufo.hasOwnProperty(‗stealCow‘);
// false
ufo.prototype.hasOwnProperty(‗stealCow‘);
// true
61. Привязка свойств и методов
// к объекту this
function Cow(name) {
this.moo = function() { alert(―Moo‖) };
};
// к объекту prototype
function Cow(name) {};
Cow.prototype.moo =
function () { alert(―Moo‖) };
};
65. __proto__
Объекты имеют «секретную» ссылку на
прототип конструктора, который их создал
__proto__ может не поддерживаться в
некоторых браузерах
var UFO = function(){};
var ufo = new UFO;
ufo.__proto__ == UFO.prototype //true
69. Наращивание prototype
• Затрагивает все новые объекты
• Затрагивает все созданные объекты(!)
• Позволяет модифицировать
существующие объекты
String.prototype.trim = function() {
return this.replace(/^s+/, ―‖);
};
alert(― ufo‖.trim());
73. Замена prototype
UFO.prototype = new FlyingObject;
var ufo = new UFO();
ufo.name = ―Mars UFO‖;
ufo.round; // true
ufo.getName(); // ―Mars UFO‖
74. Вызов «superclass»-
конструктора
function FlyingObject(name) {
this.name = name;
}
function UFO(name) {
// super(name)
FlyingObject.call( this, name );
this.stealCow = function() {};
};
UFO.prototype = new FlyingObject;
75. Переопределение методов
function UFO(){};
UFO.prototype.stealCow = function() { /*Steal a Cow*/ };
function MegaUFO(){};
MegaUFO.prototype = new Dow;
MegaUFO.prototype. stealCow = function() {
// super.stealCow();
UFO.prototype.stealCow.call(this);
alert(―Yahoo!‖);
};
76. Абстрактные «классы»
function UFO() {
if (this._id == UFO._id) {
throw new Error(―No UFOs, please!‖);
}
}
UFO._id = ―UFO‖;
UFO.prototype._id = ―UFO‖;
var ufo = new UFO(); // Error
77. Улучшение наследования
При использовании абстрактного класса
появляется ошибка
MegaUFO.prototype = new UFO; // Error
Решение: использовать пустой
порождающий объект для создания
наследования
86. Передача функций как
параметров
function moo(m) {
return m + ―moo‖;
}
function twice(fn) {
return function(x) {
return fn(fn(x));
}
}
var moomoo = twice(moo);
moomoo(―Save your bodies‖);
87. Хранение функций в таблице
var mooTable = {
―+moo‖: function(x) { return x + ―Moo!‖; },
―+mo2‖: function(x) { return x + ―Moo-Moo!‖; }
};
mooTable[―+moo‖](―UFOs!‖);
mooTable[―+mo2‖](―Fresh Grass!‖);
88. Построение реестра
var mooTable = {};
function register(name, fn) { FnTable[name] = fn; }
function makeMoomer(moo) {
return function(x) { return x + moo; }
}
register(―+moo‖, makeMoomer(―Moo!‖));
register(―+mo2‖, makeMoomer(―Moo-Moo!‖));
mooTable[―+moo‖](―UFOs!‖);
mooTable[―+mo2‖](―Fresh Grass!‖);
89. Ручные стражи
for (var cow in cows)
steal(cow);
function callIfFat(fn) {
return function(x) {
return isFat(x) ? fn(x) : undefined;
}
}
var stealFat = callIfFat(steal);
for (var cow in cows)
stealFat(cow);
90. Guard Construction
function guard(fn ,g) {
return function(x) {
return g(x) ? fn(x) : undefined;
}
}
var stealFat = guard(steal, isFat);
for (var cow in cows)
stealFat(cow);
92. «Кража» методов
var ufo = {
shine: function() {
this.shiny = true;
}
};
var cow = {};
ufo.shine(); // ufo is shiny
ufo.shine.call(cow); // cow is shiny!
ufo.shine.apply(cow, []); // cow is shiny!
Это лучше, чем
cow.shine = ufo.shine;
cow.shine();
93. arguments
arguments – специальное свойство внутри функции, но это не Array!
// не работает!
function joinInHerd() {
var herd = arguments.join(―, ―);
}
// «кража» метода у Array
function joinInHerd() {
var herd = [].join.call(arguments, ―, ―);
}
// вытаскивание метода из prototype
function joinInHerd() {
var herd = Array.prototype.join.call(arguments, ―, ―);
}
94. Наращивание prototype
Function.prototype.twice = function() {
var fn = this;
return function() {
return fn.call(this, fn.apply(this, arguments));
};
}
function moo(x) { return x + ―Moo!‖; }
var mo2 = moo.twice();
mo2(―Ufos!!!‖);
95. Анонимные функции
var UFO = function(name){
Анонимная
this.name = name; функция
this.getName = function() {
return this.name;
}; $&*# | function
};
UFO.name // ―‖ UFO | function
97. Анонимные функции
Анонимные функции позволяют
ограничить область видимости и область
выполнения — idempotent function
function() {
var cow = { name: ―Cow‖ };
stealCow (cow);
}();
98. bind
function shine() {
this.shiny = true;
}
shine(); // Window is shiny
y = shine.bind(cow);
y(); // cow is shiny
99. bind (prototypejs)
function bind(context) {
if (arguments.length < 2 &&
Object.isUndefined(arguments[0]))
return this;
var __method = this, args = slice.call(arguments, 1);
return function() {
var a = merge(args, arguments);
return __method.apply(context, a);
}
}