I've just wrote this function for answer on SO:
function ngWrap($scope, fn) {
return function() {
var args = [].slice.call(arguments);
return $scope.$apply(function() {
fn.apply(null, args);
});
};
}
With a better version:
function ngWrap($scope, fn) {
return function() {
var args = [].slice.call(arguments);
if ($scope.$$phase) {
fn.apply(null, args);
} else {
return $scope.$apply(function() {
fn.apply(null, args);
});
}
};
}
that can be use to shorten this:
socket.on('myevent', function(arg){$scope.$apply(function(){trigger_fn(arg)})})
into:
socket.on('myevent', ngWrap($scope, trigger_fn));
Does this function have a name (the first one) or maybe you can write simple version of it using underscore (that can use just $scope.$apply.bind($scope) as argument) or maybe lisp have a function that word that way?
Does this function have a name
Not that I know, but I could think of "lifting fn to the Angular $scope" or so.
you can write simple version of it using underscore
Yes, what you're doing there is basic function composition, so you can use Underscore's compose function:
function ngWrap($scope, fn) {
return _.compose($scope.$apply.bind($scope), fn);
}
Related
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))
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 was reading the source code for async.js library and with in that i found a function called 'only_once' and then i tried some examples to make it clear how it works, but i can't figure out what is wrong with my examples cause they simply do not behave the way they should. here is my code:
function only_once(fn) {
var called = false;
return function () {
if (called) throw new Error('Callback was already called.');
called = true;
fn.apply(this, arguments);
};
}
// my example code
var add = function (a, b) { return a + b; };
var add_once = only_once(add);
var a = add_once(1, 3);
console.log(a); // this prints undefined not 4, what the hell ?????
only_once() isn't currently doing anything with the result of fn -- add, in this case.
It should provide the return value from fn as its own:
return fn.apply(this, arguments);
// vs.
fn.apply(this, arguments);
In context:
// ...
return function () {
if (called) throw new Error('Callback was already called.');
called = true;
return fn.apply(this, arguments);
};
// ...
Within async.js, the return value isn't being used, so it doesn't have to be provided.
The asynchronous functions the library is designed for instead accept callback functions as arguments to be invoked later and passed the results.
only_once is just preventing these from being invoked multiple times:
function asyncFunc(callback) {
setTimeout(callback, 100); // callback invoked
setTimeout(callback, 200); // Uncaught Error: Callback was already called.
}
asyncFunc(only_once(function (value) {
console.log('callback invoked');
}));
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;
}
}
I have the below code:
filtersManager = (function ($) {
var that = this;
function configure() {
// some work
return that;
};
function process() {
// some work
return that;
}
return {
// public functions
configure: configure,
process: process
};
}(jQuery));
but when it's called using the below it fails:
filtersManager.configure().process();
Error: Object doesn't support property or method 'process'
whereas the below works:
filtersManager.configure();
filtersManager.process();
You are returning the wrong thing (this in a plain function invocation is the global object). You want to return the object that you originally created, which I will call the interface.
filtersManager = (function ($) {
var interface = {
// public functions
configure: configure,
process: process
};
function configure() {
// some work
return interface;
};
function process() {
// some work
return interface;
}
return interface;
}(jQuery));
If you're wondering why I can reference the functions defined below, it's due to hoisting.
Immediate function is executed in global object (window) context. Try something similar to this:
filtersManager = (function ($) {
var that = {};
that.configure = function() {
// some work
return that;
};
that.process = function() {
// some work
return that;
}
return that;
}(jQuery));
UPD. Based on comments
Constructor pattern seems to fit your need better:
var FiltersManager = (function($) {
function FiltersManager() {}
FiltersManager.prototype = {
configure: function() {
console.log('configure');
return this;
},
process: function() {
console.log('process');
return this;
}
}
return FiltersManager;
}(jQuery));
new FiltersManager().configure().process();
As to continue what others have said , I think you confused with the function constructor syntax which would work , similar to what you've said ;
var G=function g()
{
this.configure =function (){return this;}
this.process =function (){return this;}
};
var _= new G();
console.log(_.configure().process())
If you wanted to re-use the functions on other objects too, you could do it like this
filtersManager = function ($) {
function configure() {
// some work
return this;
};
function process() {
// some work
return this;
}
return {
// public functions
configure: configure,
process: process
};
}(jQuery);
(OTOH, if you wanted to create aliases to them, you would then have to bind them to the object)
Or if configure and process are quite short, simple functions :
filtersManager = (function ($) {
return {
// public functions
configure: function () {
// some work
return this;
},
process: function () {
// some work
return this;
}
};
}(jQuery));