Ich arbeite seit einiger Zeit an einem JS-Modulmuster, um die steigenden Anforderungen "irgendeiner Website" zu erfüllen. Im Wesentlichen brauche ich nur eine gute Möglichkeit, Skripte zu gruppieren / zu kapseln, zusammen mit der gelegentlichen Notwendigkeit von OO-Mustern.
Ich habe eine Struktur, die gut funktioniert, aber ich bin mit bestimmten Teilen davon nicht zufrieden... also bin ich dabei, sie umzugestalten. Hier ist das aktualisierte Muster:
(function (global) {
var M = {
VERSION: 1.0
};
global.M = M;
//jQ document.ready()
global.onload = function(){
console.log('M VERSION: %s', M.VERSION);
var main = new M.Main();
};
M.Main = function(){
var _class1;
var _class2;
var _class3;
function _init(){
_class1 = new M.Class('foo','baz');
console.log('_class1.param2: %s', _class1.getParam() ); //works
_class2 = new M.OtherClass('faz','boo');
_class2.setParam('Boozaz');
console.log('_class2.param2: %s', _class2.getParam() ); //works
_class3 = new M.Class('fuz','boz')
console.log('_class3.param2: %s', _class3.getParam() ); //works
_class3.prototype = new M.Super();
console.log('_class3.__param: %s', _class3.prototype.getProtected() ) //works
}
_init();
return true;
};
M.Super = function(){
var __param = 'jQ';
M.Super.API = {
getProtected: function(){ return __param }
}
return M.Super.API;
}
M.Class = function( p1, p2){
var _param1;
var _param2;
function _init(){
_param1 = p1;
_param2 = p2;
}
function _getParam(){
return _param2;
}
function _setParam(e){
_param2 = e;
}
M.Class.API = {
getParam: function(){ return _getParam(); },
setParam: function(e){ _setParam(e) },
publicMethod: function(){... }
}
publicMethod() //fails
this.publicMethod() //fails, this scopes to DOM window
M.Class.API.publicMethod() // works, but is kludgy
_init();
return M.Class.API;
};
})(typeof window === 'undefined'? this: window);
Dies erzeugt eine zufriedenstellende DOM-Struktur (bei Inspektion durch Firebug) - aber ich verliere den Umfang this
in einem bestimmten Bereich = Aufruf der "öffentlichen" Methoden des zurückgegebenen Objekts intern.
publicMethod() //fails
this.publicMethod() //fails, this scopes to DOM window
M.Class.API.publicMethod() // works, but kludgy syntax
In der vorherigen Iteration dieses Musters ist das "class"-Objekt selbstausführend, und der Verweis auf this
wird beibehalten:
M.Class = function( p1, p2){
var _param1;
var _param2;
var _root;
function _init(){
_root = this; //this gets referenced for later usage
_param1 = p1;
_param2 = p2;
}
function _getParam(){
return _param2;
}
function _setParam(e){
_param2 = e;
}
M.Class.API = {
init: function(){ _init(); },
getParam: function(){ return _getParam(); },
setParam: function(e){ _setParam(e) },
}
console.log('getParam, internal:%s', _root.getParam() ) //success
return M.Class.API;
}();
M.Class.init();
In dem umgestalteten Muster möchte ich diese "Klassen" jedoch per instanziieren new
, um mehr Kontrolle über die Ausführungsreihenfolge zu erlangen.
Ich habe viele, viele Artikel zu dem ziemlich verwirrenden Thema des lexikalischen Umfangs in js gelesen... bin aber zu keinen Schlussfolgerungen gekommen.
Wie sollte ich den Umfang von this
in meinem aktualisierten Modulmuster beibehalten?
Lösung des Problems
Dies ist eine dieser philosophischen Fragen, die sich jeder stellt, wenn er eine Bibliothek oder ein Modul schreibt: Sollen Funktionen das Containerobjekt mit diesem oder dem Variablennamen referenzieren? Die Antwort lautet: Es kommt darauf an.
Wenn Sie wissen, dass die Funktion immer mit dem richtigen Wert von this aufgerufen wird (z. B. eine Methode auf einem Prototyp), dann verwenden Sie this. Wenn die Funktion jedoch auf andere Weise aufgerufen werden könnte, verwenden Sie den Variablennamen. Wenn Sie sich zu einem späteren Zeitpunkt entscheiden, den Namen zu ändern, ist dies eine ziemlich einfache Übung zum Suchen und Ersetzen. Und der Aufruf von myLib.utils.someFn ist für mich viel klarer als der Aufruf von this.someFn. Und wenn Sie das Gefühl haben, dass es zu viel Tippen ist, können Sie jederzeit dorthin zurückkehren var sF = myLib.utils.someFn
und von dort aus fortfahren.
Bearbeiten
Um Ihre Fragen zu beantworten:
publicMethod() //fails
Es gibt keine publicMethod
Kennung im aktuellen Bereich, es wird fehlschlagen.
this.publicMethod() //fails, this scopes to DOM window
Wenn der Aufruf M.Class() war, dann ist dies ein Verweis auf M. Wenn Sie window erhalten, rufen Sie die Funktion auf andere Weise auf.
M.Class.API.publicMethod() // works, but is kludgy
Denn so hast du es eingerichtet. Wenn es Ihnen nicht gefällt, richten Sie es anders ein.
Zuletzt:
)(typeof window === 'undefined'? this: window);
scheint eine dieser mystischen Beschwörungen zu sein, die sich im Internet zu verbreiten scheinen. Was ist der Zweck? Wenn die Absicht darin besteht, eine Referenz auf das globale Objekt an die Funktion zu übergeben, dann:
)(this);
ist überall ausreichend. Der Zweck des Obigen besteht darin, sicherzustellen, dass die Funktion einen Verweis auf das globale Objekt hat, da das Verweisen auf das Fenster zu einem anderen Objekt aufgelöst werden könnte. Das Einbeziehen von Logik, die in das globale Objekt passen kann oder nicht, scheint ein Rückschritt zu sein. In welchem Szenario ist es vorzuziehen, auf die (möglicherweise neu zugewiesene) Fenstereigenschaft des globalen Objekts statt auf das globale Objekt selbst zu verweisen?
Keine Kommentare:
Kommentar veröffentlichen