JavaScript Function arguments - javascript

I am trying to create a function that deserialises a JSON object and creates some functions, but I want to be able to specify a variable set of arguments.
For example, in JSON I want to specify something like:
{
"handler" :
{
"args" : ["evt","value"],
"content" : "console.log(value);"
}
}
And when I parse the object, I will do something like:
var myFunction = new Function(handler.args,handler.content);
But the challenge is that each argument is supposed to be a n strings followed by the content of the function as the last argument. Is there any easy way of specifying n number of arguments in a new Function()?

To solve the technically issue: You can use apply [docs].
handler.args.push(handler.content);
var myFunction = Function.apply(null, handler.args);
However the question is why you are doing something like this? What is the context? Spontaneously I would say you should consider another solution for whatever problem you are trying to solve ;)

According to MDN
Parameters
arg1, arg2, ... argN
Names to be used by the function as formal argument names. Each must be
a string that corresponds to a valid
JavaScript identifier or a list of
such strings separated with a comma;
for example "x", "theValue", or "a,b".
So the arguments list can either be one or more strings seperated by commas, or just one string with each identifier in it seperated by commas.
Also since
['evt', 'value'].toString() == 'evt,value'
Simply passing your handler.args array as the first argument to the new Function constructor should work exactly as you want it to
new Function(handler.args, handler.content);
Internally, new Function casts every argument to a string if it is not already one. So conceivably something like this would also work
new Function({ toString: function() { return 'a,b,c' } }, 'return a+b+c');
Not that I'm suggesting you do anything silly like that.
This works in every browser I've tried including IE

I think the simplest route would be to combine the 2 properties. Then use apply to construct the function.
var x = {
"handler" :
{
"constructorArgs" : [
"evt",
"value",
"alert(value);"
]
}
};
var f = Function.apply(undefined, x.handler.constructorArgs);
f(1, 2);
To keep it similar you can use Array.prototype.concat.
var x = {
"handler" :
{
args: [ "evt", "value" ],
content : "alert(value);"
}
};
var f = Function.apply(undefined, x.handler.args.concat(x.handler.content));
f(1, 2);

Can;t you just make the body of your functions work with the arguments property?
http://jsfiddle.net/9XcEb/
var add = new Function(
"var total=0;"+
"for (var i=0; i < arguments.length; i++) {"+
"total+=arguments[i]"+
"};"+
" return total"
);
alert(add(3,4,5,6));

Related

can I override in Javascript?

How can I create an object like that
var sum = {
a : 5,
b : 7,
sumar : function()
{
return (this.a+this.b);
},
sumar : function(a, b)
{
return (a+b);
}
}
and then use any of the methods declared like this?
sumar0 = sum.sumar(); //use the method without parameters
sumar1 = sum.sumar(6,7); //use the method with parameters.
Just like "overriding" the methods? is this possible?
Thanks in advance and sorry for my bad english
In Javascript, you do NOT declare two methods of the same name with differnt args like you do in some other languages. Instead, you declare only a single method with the name and then you examine the arguments when the function is called to decide which behavior you should follow.
When you do declare two properties with the exact same name, then one of them is ignored by the interpreter since there can only be one value for any given property in Javascript.
There is a long description of overloading in Javascript with a number of examples here:
How to overload functions in javascript?
In your specific case, you could test how many arguments were passed to the method and branch accordingly:
var sum = {
a : 5,
b : 7,
sumar : function(a, b)
{
if (arguments.length < 2) {
// no arguments passed, use instance variables
return (this.a+this.b);
} else {
// arguments were passed, use them
return (a+b);
}
}
}
document.write(sum.sumar() + "<br>");
document.write(sum.sumar(6, 7) + "<br>");
Though, I must say, this is a particularly odd method that sometimes operates on the instance properties and sometimes doesn't.

mongdb/nodejs: using variables in $inc doesn't work

I have the following that i entered into the mongo terminal and it works great
db.cars.update({'_id':'FordXdfg'},{$inc :{'attribs.0.totl':1}})
which basically updates an array using dot notation, the 0 is the index of the array.
this does work. but transferring it to node my 0 comes from a variable.
so i tried
var carIndex = 3;
cars.update({'_id':'FordXdfg'},{$inc :{'attribs.' + carIndex + '.totl':1}}, function (err, callback) ................)
seems to be invalid javascript, if i replace my carIndex with 3 then it works i.e.
cars.update({'_id':'FordXdfg'},{$inc :{'attribs.3.totl':1}}, function (err, callback) ................)
Any ideas?
thanks
When using that style of object initialization in JavaScript, property names must be string literals. When using the object initialization syntax, property names can not be constructed at run time in code. For example, you can only use literals like:
{
"name": "Martin"
"location": "Earth"
"value": 1234
}
You cannot do this:
var propName = "name";
var obj = {
propName: "Martin";
};
While it syntactically appears to work, you'll end up with an object that looks like:
{
propName: "Martin"
}
Again, that's because only literal values are accepted when constructing an object using the shortened syntax. It will not interpret variable values.
There are two other options for setting properties of a JavaScript object, either through simple dot-notation:
obj.name = "Martin";
Or, you can use bracket notation:
obj["name"] = "Martin";
As objects in JavaScript act like associative arrays in that you can define new properties/keys at runtime each with a value, either syntax above works, and both result in the same underlying storage (and can be used interchangeably).
So, you'll need to construct the $inc syntax separately using the other technique for setting object property values in JavaScript:
var inc = {};
inc["attribs." + carIndx + ".totl"] = 1;
Then use that inside of your update:
{ $inc: inc }

how can I get the name of each argument in the arguments object in javascript

In javascript we have the arguments object that is a not quite array that we can query.
How can I get the name of each argument?
For example if I want to know that the 3rd argument is called embedded for example, how would I discover this?
arguments[2].name == "embedded'
Obviously the above does not work.
I'm afraid that's not possible. Only the values themselves are passed:
function logArguments(){
for(key in arguments)
console.log(key, arguments[key]);
}
var someObject = {someProperty:false};
logArguments("1", 3, "Look at me I'm a string!", someObject);
// Returns:
// 0 1
// 1 3
// 2 "Look at me I'm a string!"
// 3 Object {someProperty: false}
So you can only get their array indexes.
You can however, use this for(key in arguments){} to supply as many arguments to a function as you'd want.
something like this
function a() {
var arr = Array.prototype.slice.call(arguments, 0, arguments.length);
for (var aux in arr) {
alert(aux + ":" + arguments[aux]);
}
}
src:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments
The arguments object is a list of parameters, it does not store the name of the arguments.
Some browsers let you use the toString method to get the code of a function:
function a(arg1){}
// undefined
a.toString()
// "function a(arg1){}"
If you need named parameters it's common to pass an object:
$.ajax({
url: "test.html",
cache: false
})
I'm not sure what you are trying to achieve... if you use positional arguments and the third argument is called "embedded" then the name of arguments[2] will always be "embedded". But while you know that when writing the code the name of the arguments aren't stored anywhere where you can conveniently access them.

Passing object in javascript function

Say I already have many objects, like obj1, obj2, .....obj30.....
Now I am trying to write a function like this:
function blar(N){
do something to objN
}
blar('4');
So far it seems that the only way to do it is
function blar(thisObj){
do something to thisObj
}
blar(obj4);
I wonder what is the right way to pass the N such that the function can use that N value to process objN.
Hope I make myself clear.
PS: I even try something like blar(obj+N) but apparently it's wrong too, as the system tries to find obj, which doesn't exist.
Use square bracket notation.
window['obj' + N];
This depends on them dangling off the window object and not being nicely scoped though.
… but if you have a bunch of objects, which are identified by being the same except for a number, then you should probably be storing them in an array in the first place. Then you would just:
myArray[N];
Use eval:
function blar(N) {
var obj = eval("obj"+N);
}
Or, if you can put those objects into an object, you can use []
function blar(N) {
var obj = tracker["obj" + N];
}
It's pretty simple:
function blar(objectNo) {
var obj = eval('obj' + objectNo);
alert(obj);
}
To give you some keywords for talking with others about this: what you want to do is to access an object by its name, in the current scope.
But note that the following doesn't work:
function main() {
var a = 1, b = 2, c = 3;
blar('a'); // doesn't work
doSomething(eval('a')); // works
}
This is because the variable a is only visible in the main function, but not in blar. That is, the eval must be called in a scope where the variable is visible.

Build javascript function to accept default values

function myFunct(){
//blah blah blah
}
how to build a function with key/value pair parameters so when i call this, it will be called like this?
myFunt(prm1:'value1',prm2:'value2',prm3:'value3');
so, when i only need to call the 3rd param, i will do this:
myFunct(prm3:'value3');
Specify some defaults in your function and then call using only the params you need:
function myFunct(param) {
var prm1 = param.prm1 || "default1";
var prm2 = param.prm2 || "default2";
var prm3 = param.prm3 || "default3";
}
Call it using a param object, like this:
myFunct({prm3:'value3'});
prm1 and prm2 will get the default values, but prm3 will get what you passed.
You can specify any combination of values in your param object. Any you leave out will be populated with their default values.
If you're using jQuery you can make this a little prettier using $.extend:
function myFunct(param) {
var parameters = $.extend(true, /* deep copy */
{prm1: "default1", prm2: "default2", prm3: "default3"}, param);
};
The first object given to extend will serve as the default and the properties in your param object will be merged in when present.
function myFunt(jsonObj){
var param3 = jsonObj.prm3;
}
Call the function like this:
myFunt({prm3: 'value3'});
As far as I know, that is not supported by Javascript. You can however achieve a similar effect by just passing one argument, that is an object.
Call:
foo({ prm1: 'value1', prm2: 'value2', prm3: 'value3'})
Function definition:
function foo(args)
{
//use values accordingly
var prm1 = args.prm1;
}
Javascript doesn't directly support this syntax (named parameters, specifically), so you'll have to resort to some sort of workaround. There are two approaches that work in certain situations:
If you only need certain contiguous subsets of the parameters supplied, you can just declare them in order and then manually check whether the remaining parameters have been supplied. Javascript lets you call a function with less than the number of declared parameters, with the unpassed ones defaulting to undefined. Hence you could do something like this:
function myFunc(prm3 ,prm1, prm1) {
// Use defaults if not supplied
if (typeOf(prm1) == 'undefined') prm1 = 'value1';
if (typeOf(prm2) == 'undefined') prm2 = 'value2';
// Rest of function as normal
...
};
Alternatively, if you need more flexibility (i.e. either prm3 or prm2 could be supplied on their own, you'll need some way of associating a name with the value. Hence you'd have to pass all parameters in as an associate array, which is javascript is simply an object:
function myFunc(prms) {
// Unpack actual arguments - if not supplied, will be 'undefined'
var prm1 = prms.prm1;
var prm2 = prms.prm2;
var prm3 = prms.prm3;
// Rest of function as normal
...
};
// Call this function something like the following:
myFunc({prm1: 'Hello', prm3: 'World'});
Now both of these approaches have disavantages, but if you need to support optional arguments they're the only ways I'm aware of to do it.
Use arrays.
either:
var param = [null, 'value2', null]
or
var param = ['value1', 'value2', 'value3']
with function:
myFunct(param);
function myFunct(array){
//blah blah blah
}
This is most easily done by passing an object in as an argument:
myFunct({prm1: 'value', prm2: 'value', prm3: 'value'});
However, if you want any omitted key to have a default value, the most common methodology for this is to use $.extend (assuming you are using jQuery). Example:
function myFunct(obj) {
var defaults = {
prm1: 'value',
prm2: 'value',
prm3: 'value'
};
// Set any defaults
obj = $.extend(defaults, obj);
// Output the results to the console
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
console.log("obj[" + i + "] =", obj[i]);
}
}
}
Then you can call some sample code:
myFunct(); // will output all three params as being "value"
myFunct({prm3: 'test'}); // will output first two as being "value", third as being "test"
If you are not using jQuery, you can use the method described by lwburk above. However, lwburk's method gets rather lengthy if you have a lot of options possible.
The reason the extend method works is that it takes the first object (default in this case) and overwrites all values in the first object (default) with the ones specified in the second object (obj in this case). So $.extend({a: 1, b: 2}, {a: 2}) returns {a: 2, b: 2}; note that the a value was taken from the second object, but the b value from the first was untouched because it was not specified in the second.
Other libraries have similar extend methods (not an extensive list):
jQuery's extend (as linked above)
Prototype's extend
MooTools's merge
Or you could write your own, or use the code from any of the above.

Categories