Предположим, что нам необходимо после загрузки документа проинициализировать создаваемый объект. А вообще, зачем это может потребоваться? Если попытаться выполнить следующий участок кода, то мы обнаружим, что мы не можем напрямую обратиться к объекту App.
var App = (function() {
(function(){
console.log(App); // undefined
})();
return {
version: 0
};
})();
Все правильно: пока объект не реализован, мы не можем обратиться к нему. Конечно, можно поступить проще, например, расположить метод инициализации ниже:
var App = (function() {
return {
version: 0
}
})();
(function(){
console.log(App); // App object
})();
Но в этом случае нарушается логическая связка с реализацией объекта, поэтому этот вариант мы отбрасываем. Далее рассмотрим возможные реализации инициализации на примере стека. Вот один из способов, правда он основан на использовании библиотеки jquery.
var Stack = (function(){
var init = function() {
try {
for (var i = 0; i < 10; i++) {
Stack.push(i);
}
} catch(e) {
console.log(e.message);
}
};
$(document).ready(function(){
init();
});
return {
size: 1024,
pointer: 0,
storage: [],
push: function(item) {
if (this.pointer + 1 > this.size) {
throw new Error("Stack is full");
}
else {
this.storage.push(item);
this.pointer++;
}
},
pop: function() {
if (this.pointer == 0) {
throw new Error("Stack is empty");
}
else {
return this.storage[--this.pointer];
}
},
reset: function() {
this.storage = [];
this.pointer = 0;
}
};
})()
Идея, заключается в том, что сама инициализация начинается только после полной загрузки документа, плюсом данной идеи также является и то, что у нас появляется уверенность в готовности и всех остальных объектов, которые так или иначе могут нам понадобиться. В случае, если мы не собираемся использовать jquery, тогда можно поступить следующим образом
var Stack = (function(){
var init = function() {
try {
for (var i = 0; i < 1025; i++) {
Stack.push(i);
}
} catch(e) {
console.log(e.message); // Stack is full
}
};
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
else if (document.attachEvent) {
document.attachEvent("onreadystatechange", init);
}
return {
size: 1024,
pointer: 0,
storage: [],
push: function(item) {
if (this.pointer + 1 > this.size) {
throw new Error("Stack is full");
}
else {
this.storage.push(item);
this.pointer++;
}
},
pop: function() {
if (this.pointer == 0) {
throw new Error("Stack is empty");
}
else {
return this.storage[--this.pointer];
}
},
reset: function() {
this.storage = [];
this.pointer = 0;
}
};
})()
Здесь мы воспользовались обработчиками событий загрузки документа для различных браузеров (document.addEventListener, document.attachEvent), эти же обработчики использованы в реализации самого метода ready в jquery. Есть еще один способ авто инициализации
var Stack = (function(){
var init = function() {
try {
for (var i = 0; i < 10; i++) {
Stack.push(i);
}
} catch(e) {
console.log(e.message);
}
};
setTimeout(function() {
init();
}, 0);
return {
size: 1024,
pointer: 0,
storage: [],
push: function(item) {
if (this.pointer + 1 > this.size) {
throw new Error("Stack is full");
}
else {
this.storage.push(item);
this.pointer++;
}
},
pop: function() {
if (this.pointer == 0) {
throw new Error("Stack is empty");
}
else {
return this.storage[--this.pointer];
}
},
reset: function() {
this.storage = [];
this.pointer = 0;
}
};
})()
или вот так
var Stack = {
size: 1024,
pointer: 0,
storage: [],
push: function(item) {
if (this.pointer + 1 > this.size) {
throw new Error("Stack is full");
}
else {
this.storage.push(item);
this.pointer++;
}
},
pop: function() {
if (this.pointer == 0) {
throw new Error("Stack is empty");
}
else {
return this.storage[--this.pointer];
}
},
reset: function() {
this.storage = [];
this.pointer = 0;
},
init: (function() {
var init = function() {
try {
for (var i = 0; i < 10; i++) {
Stack.push(i);
}
} catch(e) {
console.log(e.message);
}
return 0;
};
setTimeout(function() {
init();
}, 0);
})()
};
Использование таймера в авто инициализации также дает возможность обращаться к объекту. Для сравнения приведенных выше методов, приведу следующий качественный тест:
var start = new Date().getTime();
$(document).ready(function(){
console.log('ready: ' + (new Date().getTime() - start) + ' ms');
});
setTimeout(function() {
console.log('timer: ' + (new Date().getTime() - start) + ' ms');
}, 0);
console.log('first: ' + (new Date().getTime() - start) + ' ms');
console.log('last: ' + (new Date().getTime() - start) + ' ms');
Результат этого теста выглядит следующим образом:
// FF
first: 1 ms
last: 2 ms
timer: 9 ms
ready: 12 ms
// Chrome
first: 0 ms
last: 0 ms
ready: 4 ms
timer: 23 ms
// Opera
first: 0 ms
last: 0 ms
ready: 0 ms
timer: 23 ms
// IE
first: 0 ms
last: 0 ms
ready: 19 ms
timer: 26 ms
В целом по скорости быстрее начинает выполнение метод ready, в то время как setTimeout запускается позже, это справедливо для IE, Opera, Chrome, а FF показал другие результаты, видимо это зависит от их движка. У вас могут получиться другие значения, но в целом картина схожа.