I have a module where when each function is executed, it reassigns the value of the variable. This variable is stored in the constructor as I want to use it across modules. How can I do this without repeating myself?
function FormatText(data) {
this._data = data;
}
FormatText.prototype.toDowncase = function() {
return this._data = this._data.toLowerCase();
};
FormatText.prototype.deleteWords = function() {
return this._data = this._data.replace(/\W/g, " ");
};
FormatText.prototype.splitWords = function() {
return this._data = this._data.split(/\s+/);
};
FormatText.prototype.filterEntries = function() {
return this._data = this._data.filter(v => !!v);
};
FormatText.prototype.countWords = function() {
return this._data = this._data.reduce((dict, v) => {dict[v] = v in dict ? dict[v] + 1 : 1; return dict}, {});
}
module.exports = FormatText;
Related
I have a function, which calls another function and so on like
var fn1 = function() { return 'bar'; };
var fn2 = function() {
return fn1;
};
var fn3 = function() {
return fn2;
};
now this can keep on going.
Therefore I would like to recursively call a method, till I get a string/value i.e. the innermost return statement.
I tried like this:
function p (val){
var res = val;
while(typeof(res)=="function"){res = p()}
return res;
}
and calling it like p(fn2); but it doesn't seem to work. What am I missing.
You need to reassign the res (or val) inside the loop, then return it (don't return the p) at the end:
var fn1 = function() {
return 'bar';
};
var fn2 = function() {
return fn1;
};
var fn3 = function() {
return fn2;
};
function p(val) {
while (typeof val === "function") {
val = val();
}
return val;
}
console.log(p(fn3));
You can try this:
var fn1 = function() {
return 'bar';
};
var fn2 = function() {
return fn1;
};
var fn3 = function() {
return fn2;
};
function p(val) {
if (typeof val === "function") {
return p(val())
}
return val;
}
console.log(p(fn3));
I have the following code:
var tableRequiredList = [];
var requireListPath = [
'./slimShady.js',
'./chickaChicka.js'
];
var getRequires = function() {
for (var i = 0; i < requireListPath.length; i++) {
((requireNamePath) => {
try {
console.log("INSIDE LOOP RESULT", i, require(requireNamePath)().getName()); // Outputs correct result for the index ("ChickaChicka")
tableRequiredList.push({ "name": requireNamePath, "theReq": require(requireNamePath)() });
// tableRequiredList.push({ "name": requireNamePath, "theReq": ((thePath) => { return require(thePath)(); })(requireNamePath) }); // This also doesn't seem to work.
} catch(err) {
console.log("Error importing: ", requireNamePath, " Error reported: ", err);
}
})(requireListPath[i]);
};
console.log("NAME", tableRequiredList[0].name); // Outputs the correct result ("slimShady.js")
console.log("FUNC NAME", tableRequiredList[0].theReq.getName()); // Always outputs the last item in requireListPath list ("ChickaChicka")
};
getRequires();
Example Module 1 - slimShady.js
((module) => {
module.exports = {};
var exampleModuleName1 = function() {
this.getName = function() {
return 'myNameIsSlimShady';
};
return this;
};
module.exports = exampleModuleName1;
})(module);
Example Module 2 - chickaChicka.js
((module) => {
module.exports = {};
var exampleModuleName2 = function() {
this.getName = function() {
return 'ChickaChicka';
};
return this;
};
module.exports = exampleModuleName2;
})(module);
Why does it output:
INSIDE LOOP RESULT 0 myNameIsSlimShady
INSIDE LOOP RESULT 1 ChickaChicka
NAME ./slimShady.js
FUNC NAME ChickaChicka
When it should be outputting the first index of the tableRequiredList array? This seems to only happen with require(). I have tried using map and forEach, along with the closure example above. All have the same results.
Thanks to #liliscent, I figured it out.
Just needed to change modules to this:
((module) => {
module.exports = {};
var exampleModuleName2 = function() {
var retr = {};
retr.getName = function() {
return 'ChickaChicka';
};
return retr;
};
module.exports = exampleModuleName2;
})(module);
I learn how to code in javascript. I have always error: "Cannot read property 'filter' of undefined". What am I doing wrong here and why?
I have to build A class with Singleton pattern and B class which will be observer of A class.
I have to add some instances of B class to A as subscribers (observers) and unsubscribe any of it when random value I from A class is bigger than random value P from B class.
var A = (function()
{
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
var i = 0;
let observers = new Array();
function CheckIfGreaterThanI(observer)
{
console.log("CHECKING");
return observer.getP() > this.getI();
}
return {
subscribe: function(observer)
{
console.log("DODAJĘ");
observers.push(observer);
},
unsubscribe: function(observerss)
{
console.log("USUWAM");
for(i=0;i<observerss.length;i++)
{
var index = this.observers.indexOf(observerss[i])
if (~index)
{
this.observers.splice(index, 1);
}
}
},
notify: function()
{
for(let observer of observers)
{
observer.update();
}
},
getI: function()
{
return this.i;
},
setI: function(value)
{
this.i = value;
this.notify();
///THAT'S THE PLACE WHERE ERROR RISES
var observersToUnsubscribe = this.observers.filter(this.CheckIfGreaterThanI);
this.unsubscribe(observersToUnsubscribe);
}
};
};
return
{
// Get the Singleton instance if one exists
// or create one if it doesn't
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();
function B (name,value,a) //observer
{
this.Name = name;
this.P = value;
this.A = a;
}
B.prototype =
{
constructor:B,
getName : function()
{
return this.Name;
},
getP : function()
{
return this.P;
},
update : function()
{
if(A.getInstance().getI()<this.P)
{
console.log("OK - " + this.Name);
}
}
};
for(i=0;i<10;i++)
{
var bObject = new B(i,Math.random(),A.getInstance());
A.getInstance().subscribe(bObject);
}
var ChangeIValue = function()
{
A.getInstance().setI(Math.random());
}
setTimeout(function run()
{
ChangeIValue();
setTimeout(run,1000);
}
, 1000);
OK, I resolved this problem alone and there were many mistakes behind it, so I added my solution for that:
var A = (function()
{
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
var i = 0;
var observers =[];
function CheckIfGreaterThanI(observer)
{
return observer.getP() > i;
}
return {
subscribe: function(observer)
{
observers.push(observer);
},
unsubscribe: function(observersToUnsubscribe)
{
for(let observer of observersToUnsubscribe)
{
var index = observers.indexOf(observer);
if(index!=-1)
{
observers.splice(index,1);
}
}
},
notify: function()
{
for(let observer of observers)
{
observer.update();
}
},
getI: function()
{
return i;
},
setI: function(value)
{
i = value;
this.notify();
var observersToUnsubscribe = observers.filter(CheckIfGreaterThanI);
this.unsubscribe(observersToUnsubscribe);
return;
}
};
};
return {
// Get the Singleton instance if one exists
// or create one if it doesn't
getInstance: function ()
{
if ( !instance )
{
instance = init();
}
return instance;
}
};
})();
function B (name,value,a) //observer
{
this.Name = name;
this.P = value;
this.A = a;
this.getName = function()
{
return this.Name;
};
this.getP = function()
{
return this.P;
};
this.update = function()
{
if(A.getInstance().getI()<this.P)
{
console.log("OK - " + this.Name);
}
};
};
for(j=0;j<10;j++)
{
var bObject = new B(j,Math.random(),A.getInstance());
A.getInstance().subscribe(bObject);
}
var ChangeIValue = function()
{
A.getInstance().setI(Math.random());
}
setTimeout(function run()
{
ChangeIValue();
setTimeout(run,1000);
}
, 1000);
I have a sealed object with an array member on which I want to prevent direct pushes.
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d; }
});
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // pushed = sadness
How can I prevent the push?
UPDATE:
Thanks for all the thoughts. I eventually need the JSON to send to the server. It looks like I might need to use an object for the array then figure out a way to generate and return the JSON needed, or change _something to use .slice(). Will play and report.
you could override the push method:
var _d = [];
_d.__proto__.push = function() { return this.length; }
and when you need to use it in your module, call Array.prototype.push:
_b.addD = function (newD) {
Array.prototype.push.call(_d, newD);
};
I haven't done any performance tests on this, but this certainly helps to protect your array.
(function(undefined) {
var protectedArrays = [];
protectArray = function protectArray(arr) {
protectedArrays.push(arr);
return getPrivateUpdater(arr);
}
var isProtected = function(arr) {
return protectedArrays.indexOf(arr)>-1;
}
var getPrivateUpdater = function(arr) {
var ret = {};
Object.keys(funcBackups).forEach(function(funcName) {
ret[funcName] = funcBackups[funcName].bind(arr);
});
return ret;
}
var returnsNewArray = ['Array.prototype.splice'];
var returnsOriginalArray = ['Array.prototype.fill','Array.prototype.reverse','Array.prototype.copyWithin','Array.prototype.sort'];
var returnsLength = ['Array.prototype.push','Array.prototype.unshift'];
var returnsValue = ['Array.prototype.shift','Array.prototype.pop'];
var funcBackups = {};
overwriteFuncs(returnsNewArray, function() { return []; });
overwriteFuncs(returnsOriginalArray, function() { return this; });
overwriteFuncs(returnsLength, function() { return this.length; });
overwriteFuncs(returnsValue, function() { return undefined; });
function overwriteFuncs(funcs, ret) {
for(var i=0,c=funcs.length;i<c;i++)
{
var func = funcs[i];
var funcParts = func.split('.');
var obj = window;
for(var j=0,l=funcParts.length;j<l;j++)
{
(function() {
var part = funcParts[j];
if(j!=l-1) obj = obj[part];
else if(typeof obj[part] === "function")
{
var funcBk = obj[part];
funcBackups[funcBk.name] = funcBk;
obj[part] = renameFunction(funcBk.name, function() {
if(isProtected(this)) return ret.apply(this, arguments);
else return funcBk.apply(this,arguments);
});
}
})();
}
}
}
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
})();
You would use it like so:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal
This way, you can internally keep a copy of the interface that isn't made global to allow your helper funcs to modify the array as normal, but any attempt to use .push .splice etc will fail, either directly, or using the .bind(myArr,arg) method.
It's still not completely watertight, but a pretty good protector. You could potentially use the Object.defineProperty method to generate protected properties for the first 900 indexes, but I'm not sure of the implications of this. There is also the method Object.preventExtensions() but I'm unaware of a way to undo this effect when you need to change it yourself
Thank you, dandavis!
I used the slice method:
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d.slice(); } // UPDATED
});
_b.updateC = function (newValue) {
_c = newValue;
};
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // no more update = happiness
This allows me to protect from direct push calls enforcing some logic.
I'm trying to extend an Abstract object.
var Abstract = function() { code = 'Abstract'; };
Abstract.prototype.getCode = function() { return code; };
Abstract.prototype.getC = function() { return c; };
var ItemA = function() { code = 'ItemA'; c = 'a'; };
ItemA.prototype = Object.create(Abstract.prototype);
ItemA.prototype.constructor = ItemA;
var ItemB = function() { code = 'ItemB'; };
ItemB.prototype = Object.create(Abstract.prototype);
ItemB.prototype.constructor = ItemB;
var b = new ItemB();
console.log(b.getCode());
var a = new ItemA();
console.log(b.getCode());
console.log(b.getC());
The result:
ItemB
ItemA
a
Is there any particular reason why I'm getting ItemA's scope in ItemB instance? How can I fix it?
It is because you are using global variables. Fix it by using this keyword:
var Abstract = function() { this.code = 'Abstract'; };
Abstract.prototype.getCode = function() { return this.code; };
Abstract.prototype.getC = function() { return this.c; };
var ItemA = function() { this.code = 'ItemA'; this.c = 'a'; };
ItemA.prototype = Object.create(Abstract.prototype);
ItemA.prototype.constructor = ItemA;
var ItemB = function() { this.code = 'ItemB'; };
ItemB.prototype = Object.create(Abstract.prototype);
ItemB.prototype.constructor = ItemB;
Although in this case ItemB.getC() will return undefined.