This question already has answers here:
Set a default parameter value for a JavaScript function
(29 answers)
Closed 6 years ago.
I have several functions with optional callback:
let myFunc = (callback) => {
callback = callback || (() => {});
// do something...
callback();
}
What is the best way to write the callback default parameter?
None of the following solutions satisfy me much:
1 If callback defined:
if (typeof callback === 'function') {
callback();
}
Not compact at all!
2 Utility function:
let safeFunc = (callback) => {
return callback || (() => {});
};
let myFunc = (callback) => {
// do something...
safeFunc(callback)();
}
but the problem is that in between this has changed, and it matters in my case.
3 Using call
let myFunc = (callback) => {
// do something...
safeFunc(callback).call(this);
}
Not very user friendly.
4 Creating ID function
const ID = () => {};
let myFunc = (callback=ID) => {
// do something...
callback();
}
Has external dependency, not very functionnal, though probably the best choice.
Calling directly Function() constructor looks meaningful:
let myFunc = (callback = Function()) => {
// do something...
callback();
}
Calling Function() returns a noop function:
let noopFunc = Function()
noopFunc() // => undefined
Here is another option.
5 Just an if check..
if (callback) callback();
If you want to prevent calling the callback twice, another utility function here I've called callIt, it also handles passing arguments, and if this is important also to prevent using bind, just pass this..
function callIt(that, fn) {
if (fn) fn.apply(that, Array.prototype.slice.call(arguments,2));
}
//Test Object
function Test() {
this.test = 'Test';
}
Test.prototype.calltest = function (callback) {
callIt(this, callback, 1, 2, 3);
}
var t = new Test();
t.calltest(
function (a,b,c) {
console.log('this.test = ', this.test);
console.log('args = ', a, b, c);
}
);
// ES6 way:(default parameters)
function(callback=()=>{}) {
if(typeof callback === 'function') {
callback();
}
}
Related
I wanted to create a function that I can add actions to later. I tried this:
Function.prototype.appendAction = function(action) {
let _ogFn = this
return function(...args) {
_ogFn(...args)
action()
}
}
function a() {
console.log("foo")
}
a()
a = a.appendAction(() => console.log("bar"))
a()
This does work, but how can I make it change the function automatically? I want to make it work like this:
a()
a.appendAction(() => console.log("bar")) //note it doesn't have the "a = "
a() //changed function
Depending on your scenario you could create a function decorator. This would mean defining a function (for example fnMod) that accepts a function fn and returns a decorated version that executes some before and after hooks.
const a = fnMod(() => {
console.log("foo");
});
a();
a.appendAction(() => console.log("bar"));
a();
const john = {
name: "John Doe",
age: 42,
greet: fnMod(function () {
console.log(`I'm ${this.name}.`); // <- uses `this` so use a normal function
})
}
john.greet.prependAction((name) => {
console.log(`Hi ${name}!`); // <- does not use `this` so both a normal function
}); // or arrow function will work fine
john.greet.appendAction(function () {
console.log(`I'm ${this.age} years old.`);
});
john.greet("Jane");
function fnMod(fn) {
const before = [];
const after = [];
function hookable(...args) {
before.forEach(fn => fn.apply(this, args));
const result = fn.apply(this, args);
after.forEach(fn => fn.apply(this, args));
return result;
};
hookable.prependAction = (fn) => {
before.unshift(fn);
}
hookable.appendAction = (fn) => {
after.push(fn);
}
return hookable;
}
You might want to tweak it to your liking. Currently both this and all arguments passed to the decorated function are forwarded to all hooks, which might or might not be desirable.
If you just want to call it immediately:
Function.prototype.appendAction = function(action) {
let _ogFn = this
return (function(...args) {
_ogFn(...args)
action()
})()
}
function a() {
console.log("foo")
}
a.appendAction(() => console.log("bar"))
That is the immediately invoked function expression (IIFE) pattern
For your purposes you could use eval:
First, grab the user input however you are handling it and parse it as a string.
Then use eval like so:
let userInput = 'console.log("hello world")';
const callUserFunction = (action) => {
eval(`function fn(){${action}}`);
fn();
}
callUserFunction(userInput);
Be aware that allowing a user to write or JS is a security risk, which can open doors to all kinds of attacks, so in most scenarios, I would discourage doing so
See this:
var funkyFunction = function() {
return function() {
return "FUNKY!"
}
}
var theFunk = funkyFunction(funkyFunction())
I need theFunk variable to be assigned value "FUNKY!" from the inner function but I have no idea how to go about it?
Since funkyFunction is returning a function, the result of invoking funkyFunction can then be invoked:
var func = funkyFunction(); // 'func' is the inner function
var theFunk = func(); // 'theFunc' = 'FUNKY!'
With ES6/ES7 You can return a function from within a function without naming the inner function.
const myOuterFunction = () => {
// the ...args just places all arguments into an array called args (can be named whatever)
console.log("OuterGuy");
return (...args) => {
//Whatever Else you want the inner function to do
console.log(args[0]);
};
};
//The way you call this
const innerGuy = myOuterFunction();
const randomVariableThatINeed = 'Yay!';
//Call inner guy
innerGuy(randomVariableThatINeed);
A beforeFilter is that block of code which is executed before calling any function. I am new to javascript.
Lets say I have a module:
SomeModule.js
module.exports = {
someFunction: function (arg) {
//some logic here
},
}
Now whenever I want to call the above function, I will do:
SomeModule.someFunction("helloWorld");
Like this you can assume I got many functions in the module but I want to execute some code before calling any function of the module, lets say I want to execute this line:
console.log("BeforeFilter Called");
So question is:
How can I ensure that the line gets executed before calling any function of the module ?
You have to iterate over properties of SomeModule and overwrite all properties which are functions:
const SomeModule = {
someFunction(a, b) {
console.log('some function', a + b);
}
};
for (const i in SomeModule) {
if (typeof SomeModule[i] === 'function') {
const originalFunction = SomeModule[i];
SomeModule[i] = function (...args) {
console.log('BeforeFilter Called');
originalFunction(...args);
};
}
}
SomeModule.someFunction(3, 4);
I try to realize a function e.g. MyFn() with some features as follows:
1. MyFn('Id') > It must be result the value of document.getElementById('Id');
2. MyFn('Id').MyMethode(); > It must be result the performing of a function.
Below this is realized by means of "Object.prototype" as follows:
Object.prototype.MyFn =function(param1){ return document.getElementById(param1); };
alert( MyFn('mydiv1') );
MyFn('mydiv1').posi = function() { alert("Hello, I'm the function posi!"); };
MyFn('mydiv1').posi();
alert( MyFn('mydiv1') );
Just the above example is what I'm trying to realize. But I don't want to use Object.prototype or jQuery.
Below is my wrong approach (it is maybe helpfully what I'm trying to say or to do):
var MyObj = {
method: function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
}
MyFn = function(sId) {
return MyObj;
};
alert( MyFn("mydiv1").method() ); // This is ok, because it calls the method: MyObj.method() as it was expected.
alert( MyFn("mydiv1") ); // <-- But here I like to get document.getElementById("mydiv1").
Note: The syntax of code (how the functions are to call) is important! The functions are to call as follows: MyFn('Element-Id') or MyFn('Element-Id').posi(), but not something as follows: MyObj.MyMethode()
Do you have any idea how can I it realize? Thanks in advance.
You could try something like:
var MyObj = {
method: function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
}
var MyFn = function(sId) {
this.elem = document.getElementById(sId);
this.MyObj = MyObj;
return this;
};
alert( MyFn("mydiv1").MyObj.method() );
alert( MyFn("mydiv1").elem );
This returns a reference to the function, after the function executes, so offers syntax much like C# extension methods for example.
Should be rather straight forward, seeing as functions are objects as well.
The way it's usually done, and the way jQuery does it, is to return a new instance of the function, which is done with a simple check
function MyFn(selector, context) {
if ( !(this instanceof MyFn) ) { // not an instance
return new MyFn(arguments); // calls itself with the "new" keyword
} else { // now it is an instance
context = context || document;
this[0] = context.getElementById(id);
}
return this;
}
Now building on that, we can add methods, but that requires prototyping them, which is the correct way to do this anyway
MyFn.prototype.width = function() {
return this[0].style.width;
}
and even make those methods chainable
MyFn.prototype.width = function(width) {
if ( width ) {
this[0].style.width = width + 'px';
return this;
} else {
return this[0].style.width;
}
}
FIDDLE
Ugly, not recomended by almost all design patern, but should work :
MyFn = function(sId) {
var obj = document.getElementById(param1);
obj.method = function(args, callback) {
if(typeof callback == "function") {
callback();
}
return 123;
}
return MyObj;
};
Basicly you add the function manualy to the object.
It's not a good desing patern as someone external won't know in advance that the object has an extra method.
This is a bit hacky solution:
var MyObj = function (id) {
var obj = document.getElementById(id);
// attach functions here
obj.myFun = function () {
// ...
}
// ...
return obj;
}
You get the object, attach your own functions to the object (hopefully without redefining existing ones), then return it.
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;
}
}