Utrzymuję jakiś starszy kod i zauważyłem, że używany jest następujący wzorzec do definiowania obiektów:
var MyObject = {};
(function (root) {
root.myFunction = function (foo) {
//do something
};
})(MyObject);
Czy ma to jakiś cel? Czy jest to równoważne wykonaniu następujących czynności?
var MyObject = {
myFunction : function (foo) {
//do something
};
};
Nie mam zamiaru podejmować świętych poszukiwań refaktoryzacji całego kodu według własnych upodobań, ale naprawdę chciałbym zrozumieć powód tego okrężnego sposobu definiowania obiektów.
Dzięki!
javascript
javascript-objects
Sebastián Vansteenkiste
źródło
źródło
myFunction
można było użyć pewnych zmiennych zdefiniowanych poza sobą, które nie byłyby dostępne z zewnątrz. Zobacz moją odpowiedźOdpowiedzi:
Nazywa się to wzorcem modułu http://toddmotto.com/mastering-the-module-pattern/
Głównym powodem jest tworzenie prawdziwie prywatnych metod i zmiennych. W twoim przypadku nie ma to znaczenia, ponieważ nie ukrywa żadnych szczegółów implementacji.
Oto przykład, w którym sensowne jest użycie wzorca modułu.
var MyNameSpace = {}; (function(ns){ // The value variable is hidden from the outside world var value = 0; // So is this function function adder(num) { return num + 1; } ns.getNext = function () { return value = adder(value); } })(MyNameSpace); var id = MyNameSpace.getNext(); // 1 var otherId = MyNameSpace.getNext(); // 2 var otherId = MyNameSpace.getNext(); // 3
Natomiast gdybyś użył tylko prostego przedmiotu
adder
ivalue
stałbyś się publicznyvar MyNameSpace = { value: 0, adder: function(num) { return num + 1; }, getNext: function() { return this.value = this.adder(this.value); } }
I możesz to złamać, robiąc takie rzeczy
MyNameSpace.getNext(); // 1 MyNameSpace.value = 0; MyNameSpace.getNext(); // 1 again delete MyNameSpace.adder; MyNameSpace.getNext(); // error undefined is not a function
Ale z wersją modułu
MyNameSpace.getNext(); // 1 // Is not affecting the internal value, it's creating a new property MyNameSpace.value = 0; MyNameSpace.getNext(); // 2, yessss // Is not deleting anything delete MyNameSpace.adder; MyNameSpace.getNext(); // no problemo, outputs 3
źródło
ns.getNext: function () {
się nie skompiluje.delete MyNameSpace.getNext
.:)
Celem jest ograniczenie dostępności funkcji w domknięciu, aby uniemożliwić innym skryptom wykonywanie na nim kodu. Owijając go wokół zamknięcia , przedefiniowujesz zakres wykonania dla całego kodu wewnątrz zamknięcia i skutecznie tworzysz zakres prywatny. Zobacz ten artykuł, aby uzyskać więcej informacji:
http://lupomontero.com/using-javascript-closures-to-create-private-scopes/
Z artykułu:
Kod:
var MyObject = {}; (function (root) { function myPrivateFunction() { return "I can only be called from within the closure"; } root.myFunction = function (foo) { //do something }; myPrivateFunction(); // returns "I can only be called from within the closure" })(MyObject); myPrivateFunction(); // throws error - undefined is not a function
źródło
myFunction
nie ma zakresu globalnego w drugiej wersji. Celem jest w rzeczywistości zapewnienie zakresu, w którym można by zdefiniować wewnętrzne funkcje pomocnicze.myFunction
należy do zakresu globalnego, ponieważ jest zdefiniowany w obiekcie globalnymmyObject
. W drugiej wersji można było wykonać dowolny inny kod w aplikacjimyFunction
. W pierwszej wersji tylko kod w zamknięciu ma dostęp domyFunction
myFunction
może być wykonane tylko jakoMyObject.myFunction()
, tak samo jak pierwsza wersja.Zalety:
utrzymuje zmienne w zakresie prywatnym.
możesz rozszerzyć funkcjonalność istniejącego obiektu.
wydajność jest zwiększona.
Myślę, że powyższe trzy proste punkty wystarczą, aby przestrzegać tych zasad. A żeby było to proste, to nic innego jak pisanie funkcji wewnętrznych.
źródło
W konkretnym przypadku, który pokazujesz, nie ma znaczącej różnicy pod względem funkcjonalności lub widoczności.
Jest prawdopodobne, że oryginalny programista przyjął to podejście jako rodzaj szablonu pozwalającego mu zdefiniować prywatne zmienne, które mogą być użyte w definicji rzeczy takich jak
myFunction
:var MyObject = {}; (function(root) { var seconds_per_day = 24 * 60 * 60; // <-- private variable root.myFunction = function(foo) { return seconds_per_day; }; })(MyObject);
Pozwala to uniknąć obliczeń za
seconds_per_day
każdym razem, gdy wywoływana jest funkcja, jednocześnie chroniąc ją przed zanieczyszczeniem zakresu globalnego.Jednak nic zasadniczo nie różni się od tego i po prostu mówimy
var MyObject = function() { var seconds_per_day = 24 * 60 * 60; return { myFunction: function(foo) { return seconds_per_day; } }; }();
Oryginalny koder mógł preferować możliwość dodawania funkcji do obiektu przy użyciu deklaratywnej składni programu
root.myFunction = function
, zamiast składni obiektu / właściwościmyFunction: function
. Ale ta różnica jest głównie kwestią preferencji.Jednak struktura przyjęta przez oryginalnego kodera ma tę zaletę, że właściwości / metody można łatwo dodać w innym miejscu kodu:
var MyObject = {}; (function(root) { var seconds_per_day = 24 * 60 * 60; root.myFunction = function(foo) { return seconds_per_day; }; })(MyObject); (function(root) { var another_private_variable = Math.pi; root.myFunction2 = function(bar) { }; })(MyObject);
Podsumowując, nie ma potrzeby przyjmowania tego podejścia, jeśli nie jest to konieczne, ale nie ma też potrzeby, aby go zmieniać, ponieważ działa ono doskonale i faktycznie ma pewne zalety.
źródło
Pierwszy wzorzec może być użyty jako moduł, który pobiera obiekt i zwraca ten obiekt z pewnymi modyfikacjami. Innymi słowy, możesz zdefiniować takie moduły w następujący sposób.
var module = function (root) { root.myFunction = function (foo) { //do something }; }
I używaj go jak:
var obj = {}; module(obj);
Zatem zaletą może być możliwość ponownego wykorzystania tego modułu do późniejszych zastosowań.
W pierwszym wzorcu możesz zdefiniować zakres prywatny do przechowywania twoich prywatnych rzeczy, takich jak prywatne właściwości i metody. Na przykład rozważ ten fragment:
(function (root) { // A private property var factor = 3; root.multiply = function (foo) { return foo * factor; }; })(MyObject);
Ten wzorzec może służyć do dodawania metody lub właściwości do wszystkich typów obiektów, takich jak tablice, literały obiektów, funkcje.
function sum(a, b) { return a + b; } (function (root) { // A private property var factor = 3; root.multiply = function (foo) { return foo * factor; }; })(sum); console.log(sum(1, 2)); // 3 console.log(sum.multiply(4)); // 12
Moim zdaniem główną zaletą może być ta druga (stworzenie zakresu prywatnego)
źródło
Ten wzorzec zapewnia zakres, w którym można zdefiniować funkcje pomocnicze, które nie są widoczne w zakresie globalnym:
(function (root) { function doFoo() { ... }; root.myFunction = function (foo) { //do something doFoo(); //do something else }; })(MyObject);
doFoo
jest lokalna dla funkcji anonimowej, nie można się do niej odwoływać z zewnątrz.źródło