The code that I am practicing with is where I have a function called InReverse. This function accepts a function as an argument and returns a function. When the function returned is invoked, it reverses the order of the arguments.
When the returned functions are returned:
const catDog = ('cat', 'dog') => returns ('dog cat')
What I have rewritten out so far is:
function inReverse (func) {
return function (...arguments) {
return arguments.map((element) => {
element.reverse();
});
}
}
Any guidance would be appreciated!
You need to simply call the input function inside the newly created anonymous function.
For example this works:
function inReverse(f) {
return function () {
let args = [...arguments].reverse();
return f.apply(this, args);
}
}
So for example if you have subtract function like this:
function subtract(a, b) {
return a-b;
}
subtract(1, 10); will be -9 as expected.
and inReverse(subtract)(1, 10) will be 9 as expected.
Not sure why you're using map, just call reverse right on the arguments array. Also you weren't calling func:
function inReverse(func) {
return function(...args) {
return func(...args.reverse());
};
}
(Notice that arguments is a reserved identifier in strict mode, you should name your parameter for something else)
Not sure, why you are using map method, just use reverse method in your function right on the arguments. Reference : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse?retiredLocale=id
Just reverse the arguments, and use func.apply(this, arr)
function inReverse(func) {
return function() {
var args = Array.prototype.slice.call(arguments)
args = args.reverse();
return func.apply(this, args);
}
}
function div(a, b) {
return a / b
}
console.log(div(1, 2))
console.log(inReverse(div)(1, 2))
Related
i don't know how to call something like: let r = fun().func1(2).func2(2), without the use of new keyword. I know it via new keyword, something like let r = new fun().func1(2), but can I implement it with the syntax above.
Each function could return an object containing a function:
function fun() {
return {func1(num1) {
return {func2(num2) {
return num1 * num2;
}}
}}
}
let r = fun().func1(2).func2(2);
console.log(r);
You could build a fluent interface by returning an object with the function, you need. To get a result, you need to specify a function which returns a value instead of an object, or implement a toString or valueOf function.
const
fun = (result = 0) => {
const functions = {
add (value) {
result += value;
return functions;
},
multiply (value) {
result *= value;
return functions;
},
ans () {
return result;
}
}
return functions;
};
console.log(fun().add(2).multiply(3).ans());
There is a function in a javascript library I want to override for my own use case, I want to use most of the code from the function but add some extra functionality. In my console I can access the function by doing, somelibrary.CharCounter.prototype.count this function takes an argument of text.
I have tried the following,
somelibrary.CharCounter.prototype.count = (function(_super, text) {
return function(_super, apply) {
console.log("overwriting", text);
return _super.apply(this, arguments);
};
})(somelibrary.CharCounter.prototype.count)
On the above I get the the console.log as I would expect, but I also get this error,
Uncaught typeerror: _super.apply is not a function
Obvioulsy I am doing something wrong, all I want to do is ovveride the function so it returns something different to it's original method.
You have to pass _super to the outer function only and make the inner function accept the "super" arguments:
Array.prototype.slice = (function(_super) {
return function(x, y) {
console.log("overwriting", x, y);
return _super.apply(this, arguments);
};
})(Array.prototype.slice);
console.log([1,2,3,4,5,6].slice(1,3))
To avoid repetitions, you might want to define a generic function:
function override(obj, method, fn) {
let prev = obj[method]
obj[method] = function (...args) {
return fn.call(
this,
prev.bind(this),
...args,
)
}
}
override(Array.prototype, 'slice', function (_super, x, y) {
console.log("overwriting", x, y);
return _super(x, y + 1)
})
console.log([1,2,3,4,5,6].slice(1,3))
You can use a Proxy for this. Here is a demo on proxying Math.sin:
Math.sin = new Proxy(Math.sin, {
apply: function(original, thisArg, args) {
console.log(`Executing ${original.name}(${args.join()})`);
return original.apply(thisArg, args);
}
});
console.log(Math.sin(2));
Maybe slightly more readable solution:
somelibrary.CharCounter.prototype.foo = (function () {
var _super = somelibrary.CharCounter.prototype.foo;
return function (text) {
console.log("overwriting", text);
return _super.apply(this, arguments);
}
})();
It is also possible to define generic extendFunction() function for overriding functions:
function extendFunction(superFunc, overridingFunc) {
return function () {
overridingFunc.call(this, superFunc, arguments);
}
}
somelibrary.CharCounter.prototype.foo = extendFunction(
somelibrary.CharCounter.prototype.foo,
function (superFunc, args) {
console.log("overwriting", args);
return superFunc.apply(this, args);
}
);
I'm re-creating functions from the underscore library but I'm running into a roadblock while trying to implement the _.reject() function. For the purposes of this question, I'll include the code I've written for three functions: _.each(), _.filter(), and _.reject().
_.each = function(collection, iterator) {
if (Array.isArray(collection)) {
for (var i = 0; i < collection.length; i++) {
iterator(collection[i], i, collection);
}
} else {
for (var i in collection) {
iterator(collection[i], i, collection);
}
}
};
_.filter = function(collection, test) {
var results = [];
_.each(collection, function(i) {
if (test(i)) {
results.push(i);
}
})
return results;
};
And here's the code for the function that I'm getting a problem with, the _.reject() method, along with the isEven() function that I'm passing in as the test argument.
_.reject = function(collection, test) {
return _.filter(collection, !test);
};
var isEven = function(x) {
if (x % 2 === 0) return true;
return false;
};
According to MDN's page on Expressions and Operators, the Logical NOT (!) operator Returns false if its single operand can be converted to true; otherwise, returns true.
But when I run the following code _.reject([1,2,3], isEven) I get an error saying that test is not a function. Why am I unable to use the ! operator while invoking a function (e.g., _.filter([1,2,3], !isEven))?
When you refer to a function, rather than calling it, you're referring to the function's object reference:
function foo() {
alert("Hi there");
}
var f = foo; // <== Getting the function's reference, not calling it
f(); // <== Now we call it
So !isEven would be negating the function reference. Since isEven is a non-null reference, it's truthy; and so !isEven is false. Not what you want. :-)
Your reject could be written with a function that calls test and inverts its return value:
_.reject = function(collection, test) {
return _.filter(collection, function(e) { return !test(e); });
};
Or if you want to go the functional programming approach, you can write a function that, when called, will return a new function that negates the return value:
function not(f) {
return function() {
return !f.apply(this, arguments);
};
}
Then anywhere you want to invert a callback's meaning, you'd just use invert:
_.reject = function(collection, test) {
return _.filter(collection, not(test));
};
Why am I unable to use the ! operator while invoking a function (e.g., _.filter([1,2,3], !isEven))?
Note that you are actually not invoking isEven, you are merely referencing it. As you said, ! "Returns false if its single operand can be converted to true; otherwise, returns true."
isEven is a reference to a function, i.e. an object. Objects convert to true, hence !test results in false:
_.filter([1,2,3], false))
Now you are passing a Boolean instead of a function to _.filter, hence the error message "test is not a function".
Instead, you have to pass a function that negates the result of the test function:
_.filter([1,2,3], function() {
return !test.apply(this, arguments);
});
You cannot negate a function. It's a meaningless thing to do (unless you really want the value false without typing it). Instead you want to negate the function's return value. I suspect what you want is something like so
_.reject = function(collection, test) {
return _.filter(collection, function(e) { return !test(e); });
}
I have this spec from Jasmine.js which tests a once function. I'm not sure how to implement such a function though.
/* Functions that decorate other functions. These functions return a version of the function
with some changed behavior. */
// Given a function, return a new function will only run once, no matter how many times it's called
describe("once", function() {
it("should only increment num one time", function() {
var num = 0;
var increment = once(function() {
num++;
});
increment();
increment();
expect(num).toEqual(1);
});
});
I don't quite understand what should I do here. I know I should make a function once(myFunction) {} but other than that, I am stuck. I figure out this has something to do with closures, still can't my head around it.
If you prefer not to use UnderscoreJS, you can implement a simpler "once" function yourself like this:
var once = function (func) {
var result;
return function () {
if (func) {
result = func.apply(this, arguments);
func = null;
}
return result;
}
};
When you pass your function as the argument to this once function (as the parameter as 'func'), it returns a function that can only be called once.
It accomplishes this feat, in short, by creating a results variable and assigning that variable the results of calling your function with its supplied arguments--but only the first time it is run. Otherwise, when the function is invoked subsequent times, it will never enter your if statement (because the func variable was set to null in the first invocation) and the value referenced by the results variable (set during the first invocation and accessed via closure) will be returned.
Copied from the UnderscoreJS source:
_.once = function(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
};
};
http://underscorejs.org/docs/underscore.html
Very, very minimal
const once = fn => (...args) => {
if (!fn) return;
fn(...args);
fn = null;
};
(Old school version)
function once(fn) {
return function() {
if (!fn) return;
fn.apply(null, arguments);
fn = null;
}
}
function asArray(quasiArray, start) {
var result = [];
for (var i = (start || 0); i < quasiArray.length; i++)
result.push(quasiArray[i]);
return result;
}
function partial(func) {
var fixedArgs = asArray(arguments, 1);
return function(){
return func.apply(null, fixedArgs.concat(asArray(arguments)));
};
}
function compose(func1, func2) {
return function() {
return func1(func2.apply(null, arguments));
};
}
var isUndefined = partial(op["==="], undefined);
var isDefined = compose(op["!"], isUndefined);
show(isDefined(Math.PI));
show(isDefined(Math.PIE));
Why can't the function compose simply return:
func1(func2);
and give the proper output. I thought the partial function which is stored in the variable isUndefined already returns func.apply(null, [fixed, arguments])
var op = {
"+": function(a, b){return a + b;},
"==": function(a, b){return a == b;},
"===": function(a, b){return a === b;},
"!": function(a){return !a;}
/* and so on */
};
Both partial and compose are higher-order functions.
isUndefined will return a function that, when invoked, will invoke the originally passed function with the original arguments plus any new arguments passed at invocation.
To answer your question, you'd be calling apply on the function returned from partial which will in turn, call apply on the function originally passed to partial.
You want compose to return a function that when called, will return the result of calling the first function passed the second function as an argument (with the second function passed the arguments passed to the compose invocation). If compose returned func1(func2), then you'd assign the result of the invocation to the variable isDefined.
EDIT:
Now that we have op, let's try to decompose this:
var isUndefined = partial(op["==="], undefined);
this is equivalent to
var isUndefined = partial(function(a, b){return a === b;}, undefined);
isUndefined is assigned a function that, when called, will call the function passed as the first argument to partial, passing in undefined as the first argument to that function call, followed by the arguments passed to the function isUndefined i.e.
partial(function(a, b){return a === b;}, undefined /* this will become 'a' when isUndefined is invoked */)(argumentForisUndefined /* this will become 'b' when isUndefined is invoked */);
isDefined composes isUndefined with another function that negates the result of isUndefined.
var isDefined = compose(op["!"], isUndefined);
is equivalent to
var isDefined = compose(function(a){return !a;}, isUndefined);
which is equivalent to (renamed variables for clarity)
var isDefined = compose(
function(a){return !a;},
partial( /* partial function becomes 'a' passed to first function */
function(b, c) {
return b === c;
},
undefined /* undefined becomes 'b' passed to partial */
)
)(argumentForisDefined /* argumentForisDefined becomes 'c' passed to partial */);
If we look at what we have so far and substituting for readability, boils down to a function that takes an argument and compares it to undefined, negates the result and returns a boolean
var isDefined = function (b) { return !undefined === b; }
So lets simply dissect it. Assuming we have this compose function:
function compose(func1, func2) {
return func1(func2.apply(null, arguments));
}
What will happen when you use it like this?
a = compose(function(){console.log(1)}, function(){console.log(2)});
The second function would be call immediately outputting 2, and straight afterwards the first function will be called outputting 1. a will be undefined, because the first function does not return anything.
What you want combine to do, is to return a new function, that combines the two other functions and that you can call at will.
Doing the above all on the original compose, will return a new function, that, when you call it with a() will output 2 and then 1.