return the innermost return statement in js - javascript

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));

Related

What is the difference between IIFE and function expresstion?

I get confuse about function while doing study javascript.
I think that's same thing about function.
What the difference?
var getCode = function() {
apiCode = '0]Eal(eh&2';
return function() {
return apiCode;
};
}
var getCode = (function() {
apiCode = '0]Eal(eh&2';
return function() {
return apiCode;
};
}();
It's the same difference as between f and f(). The former is a function (assuming f refers to a function), the latter is a function call.
The "II" part in IIFE means "immediately invoked", i.e. you don't just have a function expression, you immediately call it by putting () after it.
var getCode = function() {
apiCode = '0]Eal(eh&2';
return function() {
return apiCode;
};
}
This assigns function() { apiCode = '0]Eal(eh&2'; return function() { return apiCode; }; } to getCode.
var getCode = (function() {
apiCode = '0]Eal(eh&2';
return function() {
return apiCode;
};
}();
Here we have function () { ... }(), so this immediately calls the outer function and assigns the return value to getCode, which is function() { return apiCode; }.
Perhaps a simpler example:
var x = function () { return 42; }; // x is a function that, when called, returns 42
var y = function () { return 42; }(); // y is 42
Simply put, an IIFE executes the function once and puts the returning value to the variable.
E.g;
let res = (function sum(){
return 1+2;
})();
console.log(res);
On the other hand, function expression just holds a reference to the function and needs to be invoked.
E.g.;
let res = function sum(){
return 1+2;
};
console.log(res());

How can I modify the behavior of every function in an object?

Right now I have an object, such as this Pen.
The prototype of the class contains a series of functions and other properties.
var Pen = function(){
this.inkColor = 'red';
this.write = function(text){
document.write(text);
}
this.refill = function(){
console.log('refilling');
}
this.getInkColor = function(){
return this.inkColor;
}
};
var pen = new Pen();
pen.write(pen.getInkColor() + ': Hello');
Is there away to avoid modifying the Pen class, but change the behavior of every function it has, such as print a log before the actual function call?
this.write = function(text){
// do something first
document.write(text);
}
this.refill = function(){
// do something first
console.log('refilling');
}
this.getInkColor = function(){
// do something first
return this.inkColor;
}
You can wrap your pen in a Proxy and define an appropriate handler.
var Pen = function(){
this.inkColor = 'red';
this.write = function(text){
document.write(text);
}
this.refill = function(){
console.log('refilling');
}
this.getInkColor = function(){
return this.inkColor;
}
};
var handler = {
get: function(target, name) {
return name in target ? function (...args) {console.log('Hello World'); return target[name](args)} : undefined;
}
};
var pen = new Pen();
var p = new Proxy(pen, handler);
p.write(p.getInkColor() + ': Hello');
You can replace the functions with wrappers that call the original and also do something else. For instance:
Object.keys(pen).forEach(name => {
const originalFunction = pen[name];
if (typeof originalFunction === "function") {
pen[name] = function(...args) {
console.log(name, args);
return originalFunction.apply(this, args);
};
}
});
That replaces all functions on pen (only its own, not ones it inherits) with wrappers that first do a console.log then call the original.
Live Example:
var Pen = function(){
this.inkColor = 'red';
this.write = function(text){
// used console.log instead of document.write
console.log(text);
}
this.refill = function(){
console.log('refilling');
}
this.getInkColor = function(){
return this.inkColor;
}
};
var pen = new Pen();
Object.keys(pen).forEach(name => {
const originalFunction = pen[name];
if (typeof originalFunction === "function") {
pen[name] = function(...args) {
console.log(name, args);
return originalFunction.apply(this, args);
};
}
});
pen.write(pen.getInkColor() + ': Hello');
You can tweak that to handle functions inherited from the prototype, or inherited only from Pen.prototype (you don't have anything on Pen.prototype at present), etc.
You could write a function that returns another function:
function doSomethingFirst(somethingToDoFirstFn, thingToDoAfterFn) {
return function() {
somethingToDoFirstFn.apply(null, arguments);
thingToDoAfterFn.apply(null, arguments);
}
}
var Pen = function(){
// code
this.refill = doSomethingFirst(function(){
console.log('somethingFirst');
}, function() {
console.log('refilling');
})
// code
};

Facing issues writing a JavaScript memoization function

I am trying to write a memoization function, but keep getting the following error.
Error - "TypeError: getNthFibonacciNo is not a function
at dabebimaya.js:28:38
at https://static.jsbin.com/js/prod/runner-4.1.4.min.js:1:13924
at https://static.jsbin.com/js/prod/runner-4.1.4.min.js:1:10866"
How can I find this error in my code? I have tried googling the error with no avail. Please point out any additional errors too if possible.
function memoize(fn) {
var cache = {};
if (cache[arguments[0]]!==undefined) {
return cache[arguments[0]];
}
else {
var value = fn.apply(this, arguments);
cache[arguments[0]] = value;
return value;
}
}
var getNthFibonacciNo = memoize(function(n){
//1,1,2,3,5,8,13,21,34
if(i<=2)
return 1;
var fib = [0,1,1];
for(var i=3;i<=n;i++) {
fib[i] = fib[i-2]+fib[i-1];
}
return fib[n];
});
console.log(getNthFibonacciNo(7));
Your memoize function isn't returning a function.
function memoize(fn) {
var cache = {};
return function() {
if (cache[arguments[0]]!==undefined) {
return cache[arguments[0]];
}
else {
var value = fn.apply(this, arguments);
cache[arguments[0]] = value;
return value;
}
}
}
now returns a function so that it can be called multiple times.
Usage
function test(a) {
console.log('calling test', a);
return a + 1;
}
const memoized = memoize(test);
memoized(1); // prints calling test and returns 2
memoized(1); // returns 2
memoized(2); // prints calling test and returns 3
I managed to fix my code after suggestions by AnilRedshift. Below is the fixed code.
function memoize(fn) {
var cache = {};
return function() {
var key = JSON.stringify(arguments);
if (cache[key]) {
console.log('cache used');
return cache[key];
}
else {
var value = fn.apply(this, arguments);
cache[key] = value;
console.log('cache not used');
return value;
}
};
}
var fibonacciMemoized = memoize(function(n) {
//1,1,2,3,5,8,13,21,34
if(i<=2)
return 1;
var fib = [0,1,1];
for(var i=3;i<=n;i++) {
fib[i] = fibonacciMemoized(i-2)+fibonacciMemoized(i-1);
}
return fib[n];
});
console.log(fibonacciMemoized(7));
console.log(fibonacciMemoized(9));

How to avoid DRY by keep re-assigning variable

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;

JavaScript: Prevent Array.push()

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.

Categories