This is a hacky question of JavaScript.
For instance, we have a function as below:
var f1 = function(a,b)
{
return a + b;
};
and now, I want this (or another) function generated by a factory function with a template described in an array, like this:
var fCode = [a, b, a+b];
var functionFactory = function(fCode)
{
//........
return f;
};
var f1 = functionFactory(fCode);
I understand that functionFactory is consequently a closure form, and my question is not that point.
I've tried object wrapper etc., but so far have not been able to find a clean implementation.
Any thoughts? Thanks.
The only way I can see to achieve what I think you are asking for is use the built in Function constructor.
You can create a new function by passing in parameter names and a function body like so:
var f1 = new Function("a", "b", "return a+b;");
f1(2,2); // 4
If you combine that with the built in apply method you can use an array as a sort of "template"
var template = ["a", "b", "return a+b;"];
var f1 = Function.apply(undefined, template);
f1(2,2); // 4
The first argument to apply is what is bound to the this pointer when invoking that function. If you leave it undefined it will be the global object.
Related
I am working on dynamically creating some JavaScript that will be inserted into a web page as it's being constructed.
The JavaScript will be used to populate a listbox based on the selection in another listbox. When the selection of one listbox is changed it will call a method name based on the selected value of the listbox.
For example:
Listbox1 contains:
Colours
Shapes
If Colours is selected then it will call a populate_Colours method that populates another listbox.
To clarify my question: How do I make that populate_Colours call in JavaScript?
Assuming the populate_Colours method is in the global namespace, you may use the following code, which exploits both that all object properties may be accessed as though the object were an associative array, and that all global objects are actually properties of the window host object.
var method_name = "Colours";
var method_prefix = "populate_";
// Call function:
window[method_prefix + method_name](arg1, arg2);
As Triptych points out, you can call any global scope function by finding it in the host object's contents.
A cleaner method, which pollutes the global namespace much less, is to explicitly put the functions into an array directly like so:
var dyn_functions = [];
dyn_functions['populate_Colours'] = function (arg1, arg2) {
// function body
};
dyn_functions['populate_Shapes'] = function (arg1, arg2) {
// function body
};
// calling one of the functions
var result = dyn_functions['populate_Shapes'](1, 2);
// this works as well due to the similarity between arrays and objects
var result2 = dyn_functions.populate_Shapes(1, 2);
This array could also be a property of some object other than the global host object too meaning that you can effectively create your own namespace as many JS libraries such as jQuery do. This is useful for reducing conflicts if/when you include multiple separate utility libraries in the same page, and (other parts of your design permitting) can make it easier to reuse the code in other pages.
You could also use an object like so, which you might find cleaner:
var dyn_functions = {};
dyn_functions.populate_Colours = function (arg1, arg2) {
// function body
};
dyn_functions['populate_Shapes'] = function (arg1, arg2) {
// function body
};
// calling one of the functions
var result = dyn_functions.populate_Shapes(1, 2);
// this works as well due to the similarity between arrays and objects
var result2 = dyn_functions['populate_Shapes'](1, 2);
Note that with either an array or an object, you can use either method of setting or accessing the functions, and can of course store other objects in there too. You can further reduce the syntax of either method for content that isn't that dynamic by using JS literal notation like so:
var dyn_functions = {
populate_Colours:function (arg1, arg2) {
// function body
};
, populate_Shapes:function (arg1, arg2) {
// function body
};
};
Edit: of course for larger blocks of functionality you can expand the above to the very common "module pattern" which is a popular way to encapsulate code features in an organised manner.
I would recommend NOT to use global / window / eval for this purpose.
Instead, do it this way:
define all methods as properties of Handler:
var Handler={};
Handler.application_run = function (name) {
console.log(name)
}
Now call it like this
var somefunc = "application_run";
Handler[somefunc]('jerry');
Output: jerry
Case when importing functions from different files
import { func1, func2 } from "../utility";
const Handler= {
func1,
func2
};
Handler["func1"]("sic mundus");
Handler["func2"]("creatus est");
you can do it like this:
function MyClass() {
this.abc = function() {
alert("abc");
}
}
var myObject = new MyClass();
myObject["abc"]();
Within a ServiceWorker or Worker, replace window with self:
self[method_prefix + method_name](arg1, arg2);
Workers have no access to the DOM, therefore window is an invalid reference. The equivalent global scope identifier for this purpose is self.
I wouldn't recommend using the window as some of the other answers suggest. Use this and scope accordingly.
this['yourDynamicFcnName'](arguments);
Another neat trick is calling within different scopes and using it for inheritance. Let's say you had nested the function and want access to the global window object. You could do this:
this['yourDynamicFcnName'].call(window, arguments);
Just do it
class User
getName()
{
return "dilo";
}
}
let user =new User();
let dynamicMethod='getName';
console.log(user[dynamicMethod]()); //dilo
Hi try this,
var callback_function = new Function(functionName);
callback_function();
it will handle the parameters itself.
A simple function to call a function dynamically with parameters:
this.callFunction = this.call_function = function(name) {
var args = Array.prototype.slice.call(arguments, 1);
return window[name].call(this, ...args);
};
function sayHello(name, age) {
console.log('hello ' + name + ', your\'e age is ' + age);
return some;
}
console.log(call_function('sayHello', 'john', 30)); // hello john, your'e age is 30
Try These
Call Functions With Dynamic Names, like this:
let dynamic_func_name = 'alert';
(new Function(dynamic_func_name+'()'))()
with parameters:
let dynamic_func_name = 'alert';
let para_1 = 'HAHAHA';
let para_2 = 'ABCD';
(new Function(`${dynamic_func_name}('${para_1}','${para_2}')`))()
Run Dynamic Code:
let some_code = "alert('hahaha');";
(new Function(some_code))()
Here is a working and simple solution for checking existence of a function and triaging that function dynamically by another function;
Trigger function
function runDynmicFunction(functionname){
if (typeof window[functionname] == "function" ) { //check availability
window[functionname]("this is from the function it "); //run function and pass a parameter to it
}
}
and you can now generate the function dynamically maybe using php like this
function runThis_func(my_Parameter){
alert(my_Parameter +" triggerd");
}
now you can call the function using dynamically generated event
<?php
$name_frm_somware ="runThis_func";
echo "<input type='button' value='Button' onclick='runDynmicFunction(\"".$name_frm_somware."\");'>";
?>
the exact HTML code you need is
<input type="button" value="Button" onclick="runDynmicFunction('runThis_func');">
Try with this:
var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Is it possible to deep copy a function object in NodeJS? I am trying to use a function that I have set fields on, but I need a way to copy that function so that when I do duplicate it, I can modify these extra fields separately.
For example:
let a = function(){console.log('hello world')}
a.__var = 1
let b = clone(a)
a.__var // 1
b.__val // 1
b.__var = 2
a.__var // 1
I've tried things like using underscore/lodash, but they seem to convert the function to an object in the clone. b would wind up being { __var: 1 } in the previous example. I need to be able to perform a deep copy on the function..
Another approach to this that I've used is to .bind() the function (which produces a copy of the function) but not bind any actual arguments. If the function has static methods/properties on it, you can use Object.assign to copy those on. My use case for doing this was shimming the global Notification constructor. Example:
// copy the constructor
var NotifConstructor = Notification.bind(Notification);
//assign on static methods and props
var ShimmedNotif = Object.assign(function (title, _opts) { /* impl here that returns NotifConstructor */ }, Notification);
//now you can call it just like you would Notification (and Notification isn't clobbered)
new ShimmedNotif('test');
For simpler use cases, bind will probably work, e.g.:
function hi(name) { console.log('hey ' + name); }
var newHi = hi.bind();
newHi('you'); //=> 'hey you'
I was able to achieve the desired functionality by doing the following:
let a = function (){console.log('hello world')}
a.field = 'value'
// Wrap the "cloned" function in a outer function so that fields on the
// outer function don't mutate those of the inner function
let b = function() { return a.call(this, ...arguments) }
b.field = 'different value'
console.log(a.field === b.field) // false
Use lodash's _.assign(dest, src)
let a = function(){console.log('hello world')}
a.__var = 1
Then..
let b = () => 42;
_.assign(b,a);
b.__var // returns 1
b() // returns 42
You will have to forgive me, as I am sure this is addressed elsewhere, but I have no idea what to call this bit of syntax or the concept that this example illustrates. How does this get() function know that the parameter I am passing into it refers to an index of the adjacent array? I am not giving get() any indication of what object I am referring to, unless putting an object in parenthesis directly next to it has this effect. Is this correct? Is there a broader concept here that I am unaware of involving proximity and function calls?
function get(prop) {
return function(obj) {
return obj[prop]
}
}
get(1)([1,2,3]);
// output = 2
It might make more sense if you split get(1)([1,2,3]) out into 2 lines like this:
var get1Function = get(1);
get1Function([1,2,3])
// output = 2
Note: after execution of this line
var get1Function = get(1);
get1Function is now set to function(obj) { return obj[1] }
There's no magic here. You have a function that returns a function. When you call get(2), the returned function has 2 for the value of prop. Your code is essentially equivalent to this:
var fn = get(2);
// fn = function(obj) {
// return obj[2]
// }
fn([1,2,3]);
// => 3
You've just encountered one of the most confusing concepts for early JS programmers. It's called a "closure". MDN has a good article on this topic.
In general though, you can think of get returning a new method where the value of prop has been "saved" to the same value it was when get was first invoked.
The code example you provided would probably be best understood if we renamed some things and broke it down:
function createFunctionToReturnValueForProp(prop) {
return function(obj) {
return obj[prop]
}
}
var getPropertyFor1 = createFunctionToReturnValueForProp(1);
var array1 = [1,2,3];
var array2 = [4,5,6];
var obj = { "0": "foo", "1": "bar" };
getPropertyFor1(array1); // 2
getPropertyFor1(array2); // 5
getPropertyFor1(obj); // "bar"
Since I can determine the number of arguments a function expects to have by calling its Function.length property, is there any way for me to programmatically create the right number of parameters to insert into that function at runtime? Example:
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) { }; // vararg example
var doc = document, func_length = xyz.length;
doc.xyz = (function() {
return function(a,b,c,d,e) { /* works for one but not the other */ } }).call(doc);
/* would prefer to `return function(a,b)` with only 2 parameters, if it is
used for function `xyz` (though returning 5 works fine in this case), and to
`return function(a,b,c,d,e,f)` with 6 if used for function `bcd` (which does
not work with only five params). */
// thinking about xyz.apply(null,arguments)...but which arguments..? :(
// Returning function(a,b,c,d,e) does not support functions with more than five
// parameters...which would mostly be varargs - hence my question
// I am also well aware that I can use an object or an array instead of
// using many params.
/* This is for incorporating a user-defined function for use in my code, while
* allowing for my function to do 'other stuff' afterward. (And allowing for
* varargs, of course).
* Because coding something like: doc.xyz = xyz is inflexible */
As you can see, I don't know how to do this, or if it is even possible. The search bar hasn't given me any other questions like this one, otherwise I would not have asked...
NOTE: This answer is a product of misunderstanding but
may help the future visitors of this site.
Another way:
Do you really need to add parameters? Writing the function this way would be enough:
function foo(){ //No arguments predefined
a = arguments[0] || ""; //first argument or (if not defined) empty string
b = arguments[1] || ""; //second argument etc.
c = arguments[2] || ""; //third argument etc.
alert(a+b+c);
}
foo("Hello ", "world!");
This alerts "Hello world".
The solution you want:
The simplest way:
This is what you've asked for but it's not as simple as the previous solution.
You can define a meta function with all the parameters and a handler function that changes over the time.
(function(){ //Wrapper
var foo_meta = function(a,b,c,d){ //Local meta of foo
alert(a+b+c+d); //Do the code
};
window.foo = function(a,b){ //Global foo
return foo_meta(a,b,"","");
};
window.redefine_foo = function(){ //Global foo-changer
//Rewrites foo
window.foo = function(a,b,c){
return foo_meta(a,b,c,"");
};
};
})(); //Wrapper
//Do some code
foo("a","b");
redefine_foo(); //Rewrite foo
foo("a","b","c");
//Note that foo_meta is not defined here
foo_meta == undefined; //It's safe in the wrapper :)
This will alert "ab" and then "abc". For the meaning of wrapper function, see the references.
Reference:
Arguments array: http://goo.gl/FaLM1H
Wrapping code: http://goo.gl/uQ5sd0
If you send two parameters 6 and 7 to a function doWork(a,b,c,d,e),a=7 and b=6 will be automatically set and rest of the parameters will be ignored.
Why not just pass one object into the function and use JQuery extend.
e.g.
var parm =
{ x: 1, y : 2};
f(p) {
p = $_.extend({...defaults here}, p);
...
}
This is an example for joining the arguments, regardless of the number of arguments, to show how function arguments can be turned into an array and then processed like any other array.
function foo(){ //No arguments predefined
// convert to real array
var args = Array.prototype.slice.call(arguments);
// or if Array generics are available
var args = Array.slice(arguments);
console.log(args.join(' '));
}
foo('Hello', 'world!');
foo('Hello', 'wonderful', 'world!');
Here is the fiddle
Ref: arguments MDN
Well, I think I've figured it out at last. I've realized that there may be no way to 'truly' add a parameter to a function the way that I was asking, but there is a way to emulate the same result:
var doc = document;
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) {};
var obj = {};
// Now, here it is (mostly (sort of)):
obj.userFunc = function(args) {
var args_Array = [];
for (var i=0;i < arguments.length; i++ ) {
args_Array.push(arguments[i])
}
xyz.apply(null,args_Array); // or 'this'. or 'undefined'. Whatever you want.
// do other stuff
return this; // we know what to do to make 'this' scope explicit
} // end
var thisFunc = 'xyz'
doc[thisFunc] = obj.userFunc;
doc.xyz('h','i');
doc.xyz('h','i','j');
doc.xyz('h','i','j','k');
doc.xyz('h','i').xyz('j','l').xyz('j','q'); // etc.
The trick was to use the arguments object, which conveniently assimilated all the parameters into a readily available object, push each value into an array then apply the function.
In case you're wondering what the fuss was all about, I wanted to completely incorporate a user-defined function into another function, while still being able to do 'other stuff' afterward. My previous example worked to an extent, but did not have support for varargs. This does.
This approach is greatly more flexible than: doc[thisFunc] = userDefinedFunction
:) 4/26/2014
I want to create a single object. Does the below code make sense?
singleObj = new function () {
// act as a constructor.
};
Am I hurting any good practice?
I need a constructor. A simple object literal would not be useful here.
If you want just a single object, in that you are never going to make one again, an object literal works perfectly here.
var x = { };
Will give you an object.
In order for
var F = function() {
};
to give you an object you will need to invoke F
var x = new F();
you could try someting like:
var objCreate = function() {
var obj = {};
// do constructor logic
return obj;
};
Just create a new object and then populate it. You don't need a contrustor to do this.
var singleObject = {};
singleObject.value1 = "whatever";
If you really want to use a function, then you need to actually call it.
var singleObj = new (function () {
// act as a constructor.
})();
We can use a self executing function by creating a anonymous function function(){}, and immediately calling it with an empty argument set.
http://www.w3schools.com/js/js_objects.asp
//Used to create an object
personObj=new Object();
personObj.firstname="John";
personObj.lastname="Doe";
personObj.age=50;
personObj.eyecolor="blue";
//Used as a constructor for the object
function person(firstname,lastname,age,eyecolor)
{
this.firstname=firstname;
this.lastname=lastname;
this.age=age;
this.eyecolor=eyecolor;
}
//how to declare objects via constructor template
var myFather=new person("John","Doe",50,"blue");
var myMother=new person("Sally","Rally",48,"green");