GOOGLE ADS

Sonntag, 1. Mai 2022

Javascript-Modulmuster - Verlust des Umfangs davon

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 thisin 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 thiswird 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 thisin 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.someFnund von dort aus fortfahren.

Bearbeiten

Um Ihre Fragen zu beantworten:

publicMethod() //fails

Es gibt keine publicMethodKennung 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

Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...