Skip to content

Instantly share code, notes, and snippets.

@jaandrle
Last active September 10, 2018 11:35
Show Gist options
  • Save jaandrle/fb22361631477f55d16d6758e6a2a3f8 to your computer and use it in GitHub Desktop.
Save jaandrle/fb22361631477f55d16d6758e6a2a3f8 to your computer and use it in GitHub Desktop.
JavaScritpt - Software design pattern

JavaScritpt - Software design pattern

Some snippets which are used by me.

Classes inspired by Douglas Crockfords

PubSub Patterm

Functor Implementation

Array async loops

Optimizing debugMode

document.createDocumentFragment()

//Copyright 2009 Nicholas C. Zakas. All rights reserved.
//MIT Licensed
function timedChunk(items, process, context, callback){
var todo = items.concat(); //create a clone of the original
setTimeout(function(){
var start = +new Date();
do {
process.call(context, todo.shift());
} while (todo.length > 0 && (+new Date() - start < 50));
if (todo.length > 0){
setTimeout(arguments.callee, 25);
} else {
callback(items);
}
}, 25);
}
/*
* Let us denote by DC-Classes this implementation
*
* About class implementation:
* - notation used by Douglas Crockfords (http://jdem.cz/d7err3)
* - it means Classes_ClassName(...) is constructor of the class
* - ... and returns Object.freeze() => place for methods
* * */
/* For stand-allone */
function Classes_ClassName(def= {}){
//params for constructor (Classes_ClassName itself)
const {param1= "default_value", paramECT} = def;
//"this" implementation
let _this= {};
//private
let private_var= "PRIVATE";
function private_fun(){console.log("PRIVATE")}
//public
_this.public_fun= function(){console.log("PUBLIC")};
//cunstructor returns
return Object.freeze(_this);
}
//instance
const instance_Classes_ClassName= Classes_ClassName();
instance_Classes_ClassName.public_fun();
/* For group */
const Classes={
ClassName: function(def= {}){
//params for constructor (Classes.ClassName itself)
const {param1= "ddefault_value", paramECT} = def;
//"this" implementation
let _this= {};
//private
let private_var= "PRIVATE";
function private_fun(){console.log("PRIVATE")}
//public
_this.public_fun= function(){console.log("PUBLIC")};
//cunstructor returns
return Object.freeze(_this);
},
Another: function(def= {}){}
};
//instance
const instance2_Classes_ClassName= Classes.ClassName();
instance2_Classes_ClassName.public_fun();
var Classes= {
Parent: function(def={}){
let _this= {};
_this.a= function(){console.log("A");};
_this.b= function(){console.log("B");};
return Object.freeze(_this);
},
Child: function(def={}){
const { a, b }= this.Parent(def); //prevent banana "problem"
let _this= {a,b};
_this.a= function(){console.log("AA");};
_this.c= function(){console.log("C");};
return Object.freeze(_this);
}
};
var child= Classes.Child();
const child_keys= Object.keys(child);
for(let i=0, i_length= child_keys.length; i<i_length; i++){
child[child_keys[i]]();
}
const Classes= {
ClassName: (function(){
let _static= {};
_static.staticMethod= function(param= "STATIC METHOD"){ console.log(param); };
_static.create= function(def={}){
const {param= "default"}= def;
let _this= {};
_this.method= function(){ _static.staticMethod("INSTANCE METHOD") };
return Object.freeze(_this);
};
return Object.freeze(_static);
})()
};
/* Examples */
Classes.ClassName.staticMethod();
const instance= Classes.ClassName.create();
instance.method();
// 1x
var doSomething = debugMode ?
function(value){
process(value);
} :
function(value){
try {
process(value);
} catch (ex){
log(1, "doSomething(): " + ex.message);
}
};
// vs Nx
function doSomething(){/* ... */ if(debugMode){ /* ... */ } /* ... */}
// Auto replacing
//by Nicholas C. Zakas (MIT Licensed)
function productionize(object){
var name,
method;
for (name in object){
method = object[name];
if (typeof method == "function"){
object[name] = function(name, method){
return function(){
try {
return method.apply(this, arguments);
} catch (ex) {
log(1, name + "(): " + ex.message);
}
};
}(name, method);
}
}
}
var system = {
fail: function(){
throw new Error("Oops!");
}
};
function log(severity, message){
alert(severity + ":" + message);
}
if (!debugMode){
productionize(system);
}
system.fail(); //error is trapped!
// Funkcionální programování v JavaScriptu
/* demonstrace ukazkou:
*
* - klasicky:
* var input= 20;
* if(typeof input!=="undefined"&&input!==null){
* input+= 1;
* input*= 2;
* }
* console.log(input); // =42
*
* - funkcionalne:
* $F(20).chain(
* $F.is_defined,
* prictiJednicku,
* vynasobDvemi
* )
* .then(console.log); // =42
*
* - Proc funkcionalne:
* * tzv. self-commented, tedy nazvy funkci slouzi zaroven k vysvetleni, co delaji - v komplikovanejsich pripadech vyrazne zjednodusuji pochopeni kodu
* * nuti programovat po mensich kouscich, ale za to vice obecneji (mene je nekdy vice)
* * tyto male kousky (tzv. pure functions) dokaze srozumitelne sretezit a vytvaret tak funkce komplikovanejsi, ale stale srozumitelne
* * tahle moje implementace take sjednocuje syntaxy s asynchronnimi funkcemi: asyncFCE(parametry).then(fce, ktera se zavola po vykonani asyncFCE).catch(fce, ktera se zavola pokud asyncFCE selze)
*
* - Proc ne:
* * v praxi casto nelze takto specificky ulohu rozkouskovat, coz nevadi primo, ale ztraci se "self-commented" vyhoda
* * v praxi muze byt projekt preplnen mraky malych fci
* * muze vest k situaci, kdy v konkretnim pripade se vola fakticky vice prikazu, nez kdyby se programovalo "namiru"
* */
// definice Functoru - technicka cast, lze preskocit na radek 82
const $F= value=>({
chain: function(...args){ // zajistuje volani fci v retizku
const value_bak= value;
for(let i= 0, i_length= args.length; i < i_length; i++){
value= args[i](value);
if(value===$F.cancel){
value= value_bak;
this.fail= i;
break;
}
}
let out= $F(value);
out.fail= this.fail;
return out;
},
fail: -1, // paramater pro oznaceni zda a kde v retizku Functor spadl
then: function(f){if(!~this.fail)f(value);return this;}, // fce, ktera se provede po uspesnem splneni retizku
catch: function(f){if(!!~this.fail)f(this.fail);return this;}, // fce, ktera se provede po neuspesnem splneni retizku
valueOf: ()=>value, // metoda, pro ziskani hodnoty z Functoru
toString: ()=>`Functor(${value})`, // metoda, pro zprovozneni nativniho chovani JS (typicky insatnceof, ...)
[Symbol.iterator]: ()=>{ // metoda, pro zprovozneni nativniho chovani JS (typicky oparator ...)
let first= true;
return ({
next: ()=>{
if (first) {
first= false;
return ({
done: false,
value
});
}
return ({
done: true
});
}
});
},
constructor: $F // handler pro operator new
});
Object.assign($F, {
cancel: Symbol("$F.cancel"), // definice symbolu pro preruseni retizku
trace: x=>{console.log(x);return x;}, // funkce pro zobrazeni hodnoty v retizku aniz by byl prerusen
is_defined: x=>{if(typeof x!=="undefined"&&x!==null) return x; else return $F.cancel;}, // funkce zkontroluje zda je input definovan, pokud ne prerusi retizek a zavola catch
toString: ()=>'Functor', // metoda pro zprovozneni nativniho chovani JS (typicky insatnceof, ...)
is: x=>typeof x.chain === 'function' // metoda pro zjisteni zda je input Functor
});
// vlastni pouziti
const prictiJednicku= n=>n + 1;
const vynasobDvemi= n=>n * 2;
var ukazka= input=>$F(input).chain(
$F.trace, // vypise aktualni hodnotu
$F.is_defined, // zkontroluje, zda je aktualni hodnota definovana
$F.trace, // vypise aktualni hodnotu
prictiJednicku, // k aktualni hodnote pricte jednicku
vynasobDvemi // aktualni hodnotu vyasobi dvemi
).then(
console.log // vypise pokud uspech
).catch(
console.error // vypise pokud neuspech
);
console.log("ukazka(20) ... klasicka operace s cisly a zavola se then");
ukazka(20);
console.log("ukazka(undefined) ... neprovedese vse za $F.is_defined a zavola se catch s indexem fce u ktere prikaz selhal");
ukazka();
console.log("ukazka('') ... pretypuje se na cislo a zavola se then");
ukazka("");
function Classes_PubSub(def={}){
const {
uniqueName= function(){return (new Date()).toJSON();},
debug= false
} = def;
const topics= new Map();
let _this= {};
_this.subscribe= function(topic, listener, subscriber_name){
if(!topics.has(topic)) topics.set(topic, new Map());
const id= typeof subscriber_name==="string" ? subscriber_name : uniqueName();
if(!topics.get(topic).has(id)) topics.get(topic).set(id, listener);
return {
remove: function(){
topics.get(topic).delete(id);
if(!topics.get(topic).size) topics.delete(topic);
}
};
};
_this.publish_= function(topic, info){
return new Promise(function(resolve,reject){
setTimeout(function(){
if(topics.has(topic)){
topics.get(topic).forEach(function(listener){listener(info || {});});
resolve();
} else {
reject("Topic '"+topic+"' not found!");
}
},0);
});
};
if(debug){
_this.print= function(){
console.log(topics);
};
}
return Object.freeze(_this);
}
/* Examples */
const events= Classes_PubSub({debug: true});
const ev_1= "ST/ST", ev_2= "ST/ST2", ev_3= "ST3/ST";
var to_remove= events.subscribe(ev_1, info=>onPublish(1, info));
var to_remove2= events.subscribe(ev_1, info=>onPublish(2, info));
var to_remove3= events.subscribe(ev_1, info=>onPublish(3, info));
to_remove.remove();to_remove2.remove();
for(let i= 1; i < 3; i++){
events.subscribe(ev_2, info=>onPublish(i, info));
}
for(let i= 1; i < 3; i++){
events.subscribe(ev_3, info=>onPublish(i, info));
}
events.publish_(ev_1, {info: "A"}).catch(()=>{});
events.publish_(ev_2, {info: "B"});
events.publish_(ev_3, {info: "C"});
function onPublish(i,info){
console.log(i+": "+JSON.stringify(info));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment