How to pass Arguments to this signature? - javascript

I see a JavaScript Signature like:
attachMetadataFailed(oData?, fnFunction, oListener?)
now I know, that the first and the last parameter are optional. But the mandatory parameter is in the middle.
How can I call the function, if I dont want to set the optional parameters?
I think when I will use attachMetadataFailed(function() {...}) that I will access just the first parameter which is optional or not?

JavaScript doesn't provide a way to call a function while providing argument 2 but not argument 1.
You can either:
Explicitly pass an undefined value
foo(undefined, 123);
Have the function detect the object type
function foo (obj, func) {
if (typeof func === "undefined" && typeof obj === "function") {
func = obj;
obj = undefined;
}
// etc
}

I guess this is a thrid-party function and you are reading the documentation for it. If the documentation is true, then:
If you pass one parameter, it will be bound to fnFunction.
If you pass two, the first one will be bound to oData and the second one to fnFunction.
If you pass three, the first one will be bound to oData, the second one to fnFunction, and the third one to oListener.
So attachMetadataFailed(myfn) will behave the same as attachMetadataFailed(undefined, myfn).
Yes, JavaScript can manage that. See Quentin answer for how you can do it with your own functions.

Related

Passing `null` as context object vs directly calling the function

From this question, given that I don't want to specify any context, hence, passing null to thisArg in call().
What would be the difference between line 2 and line 3 in the following code? Is there any benefit from doing one over the other?
function sum(a,b) { return a + b; }
var result1 = sum.call(null,3,4); // 7
var result2 = sum(3,4); // 7
Similarly for apply():
var arr = [1,2,4];
var result3 = Math.max.apply(null, arr); // 4
var result4 = Math.max(...arr); // 4
It depends on whether the function you're calling was defined in loose mode or strict mode.
When calling a loose-mode function, the following three things all call the function such that this within the call is the global object for the environment (globalThis, aka window on browsers):
Calling the function without setting this: fn()
Calling the function providing a this value of undefined: fn.call(undefined) and similar
Calling the function providing a this value of null: fn.call(null) and similar
With a strict mode function, the first two both cause this during the call to be undefined, and the third (explicitly setting it to null) sets it to (you guessed it) null.
Examples:
function loose() {
console.log(`loose: ${this === null ? "null" : typeof this}`);
}
loose();
loose.call(undefined);
loose.call(null);
function strict() {
"use strict";
console.log(`strict: ${this === null ? "null" : typeof this}`);
}
strict();
strict.call(undefined);
strict.call(null);
In the normal case, if you don't need to set this to anything in particular, just call the function so the default behavior takes place.
One wrinkle: If you have an array of arguments you need to spread out as discrete arguments to the function, in any even vaguely up-to-date environment, you can use spread notation to do that: fn(...theArray). If you're stuck in an obsolete environment, the rough equivalent is fn.apply(undefined, theArray).
If you have a specific need to set a specific this value, you can do that via call or apply (as you've found), including (for strict mode functions) undefined or null.
TJ Crowder has the detailed response here, but as a general rule:
fn.call(null): In almost all cases, just call the function.
fn.apply(null, args): This is useful in some cases where you have an array of arguments and your environment doesn't support ...args, but otherwise spreading the arguments is probably more conventional: fn(...args)

Javascript function with default not required values

I can't find the similiar problem, I guess it's because i can't find a correct question/answer.
I want to create a function that will use default values if there is not arguments passed when calling a function, if so, replace default values with the values passed in function's parameters.
For example:
function openBlock(false){
// if parameter was passed with 'false' value, it will do this
// else it will put automatically a 'true' value to an function's argument
}
So if call a function openBlock() without any params, it will consider that it's param true by default. If i call a function with argument false like openBlock(false) it will override the default behavior.
Thanks
There are various ways to do this in Javascript, though none are built in. The easiest pattern is:
function(option) {
option = option || "default";
// do stuff
}
But as #FelixKling notes, this won't work in your case, as it will replace any false-y value (including explicitly setting the argument to false) with the default. For boolean arguments that you want to default to true, you need:
function(option) {
// default to "true"
option = option !== undefined ? option : true;
// do stuff
}
When you're dealing with more than one or two arguments, the best option is often to use a single options or config argument and check for the existence of properties:
function(options) {
var arg1 = option.arg1 !== undefined ? false : true;
var arg2 = option.arg2 || "default";
// do stuff
}
If you're using a library like jQuery or underscore, the extend method makes it quite easy to set up an object with default values and then overwrite them with supplied values if they exist:
function(options) {
var defaults = {
arg1: true,
arg2: "default"
};
options _.extend(defaults, options);
// do stuff
}
JavaScript doesn't really have default parameters implemented like other languages do.
You'll have to implement them yourself:
function openBlock(argument) {
argument = typeof argument !== 'undefined';
}
Take a look at Is there a better way to do optional function parameters in Javascript? for a more generic approach.

How do I call a method that takes multiple parameters when I have a single list of values?

I am writing a way to store method calls into an object:
var action = {'method':'foo', 'params': [1,'bob',45]}
I have my methods:
function foo(order, name, size);
function bar(input);
function baz(name, length, time, debug);
etc
When given an action I wish to automatically call the function associated with it:
var fn = window[action.method]
if(typeof fn === 'function')
{
fn(//blah)
}
The problem is, the action object has a list of parameters, but my functions take multiple parameters. How do I accomplish this?
Use .apply:
fn.apply( this, action.params );
This calls fn, but uses the first argument to set the this value of fn, and uses the individual members of the second argument (the action.params array) to populate the arguments of the call as individual arguments.
I'd note that since you're doing:
window[action.method]
that you actually have the method name as a string:
{'method':'foo',...}

Is it risky to ask for a nonexistent javascript argument?

If I have a function
foo()
that I call with no arguments most of the time, but one argument in special cases, is
var arg1 = arguments[0];
if (arg1) {
<special case code>
}
inside the function a completely safe thing to do?
Yes it is safe. Unless you pass in false, "", 0, null or undefined as an argument. It's better to check againts the value of undefined. (If you pass in undefined then tough! that's not a valid argument).
There are 3 popular checks
foo === undefined : Standard check but someone (evil) might do window.undefined = true
typeof foo !== "undefined" : Checks for type and is safe.
foo === void 0 : void 0 returns the real undefined
But this is prefered
function myFunction(foo) {
if (foo !== undefined) {
...
} else {
...
}
}
Yes, that's fine. A reasonable alternative is to name the argument, and not use the arguments object:
function foo(specialArg)
{
if (specialArg)
{
// special case code
}
}
Note that if(bar) tests the truthiness of bar. If you call foo with any falsy value, such asfoo(0), foo(false), foo(null), etc., the special case code will not execute in the above function (or your original function, for that matter). You can change the test to
if (typeof specialArg !=== 'undefined')
{
// ...
}
to make sure that the special case code is executed when the argument is supplied but falsy.
You can do this:
function foo(arg1){
if (arg1){
// Special case
}
else{
// No argument
}
// Rest of function
}
As long as you document the behaviour sufficiently I don't see anything wrong with it.
However you'd be better off checking the argument length, as opposed to how you're doing it now. Say for example you called:
myFunction(0);
It will never process the argument.
If it's a single optional argument you may be better off having it as a named argument in the function and checking if a defined value was passed in, depends on your use case.
The basic fact you are interested in is "was foo called with 0 or 1 argument(s)?". So I would test arguments.length to avoid future problems with a special argument that evaluates to false.

Javascript/JQuery arguments by type

I'm not quite sure if the title is correct because I'm not sure how to describe my question, but basically I'm wondering how jQuery can handle functions that take things like ("Some String", true, function(){}) and ("Some String", function() {}). IE, it seems like it's an overloaded function, I'd expect the function to be something like
function DoSomething(theStr, theBool, theFunc) {
//...
}
but that doesn't explain how it can handle the 2 argument call, at least to me. Anyone able to explain, or is it just a lot of if/else.
jQuery does type checking or arguments internally, shifting parameters (like a callback, typically at the end) forward if there are no arguments in-between. Let's take for example $.get() where the data argument is optional, the signature looks like this:
jQuery.get(url, [data], [callback(data, textStatus, XMLHttpRequest)], [dataType])
And the check looks like:
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = null;
}
jQuery.isFuncton() is just a repeatedly used shortcut for jQuery.type(obj) === "function" which is really using Object.toString(), but this used to be done with typeof() directly.
You can see the full source from jQuery 1.4.4 here.
How about just opening the file containing the culprit code?
My guess is that it's either doing type-checking on the variables (using typeof or such), or it's using arguments.length to determine how many arguments were passed, and using that to choose from a list of predefined allowed parameters.
JavaScript does not support method overloading through the use of different method signatures.
You can, in fact, pass 0 arguments to methods that list one or more, or pass more arguments than are listed.
All arguments passed to a method can be accessible through the keyword 'arguments' which behaves like an array.
That being said, you can then check for the presence of arguments directly or via the 'arguments' array.
function ABC(arg1, arg2, arg3){
if(typeof(arg2) === 'undefined') { }
if(typeof(arg3) === 'function'){ }
// arguments[0] == arg1, etc
}
ABC(1) ; // arg2 and arg3 are undefined
ABC(1,2,3,4); // arg1, arg2, and arg3 are defined, plus arguments[3] === 4
Knowing the above, you can therefore figure out how many arguments were provided, and use typeof() calls to determine what type.
In JavaScript, the argument list in a function definition doesn't force you to call the function with exactly those arguments:
// Given this definition....
function foo(one, two){
}
// ... all these calls are valid:
foo();
foo(1);
foo(1, 2);
foo(1, 2, 3);
And, of course, JavaScript is loosely typed as well:
foo(1, 2);
foo("Hello", "World");
foo(new Date, {foo: "bar"});
Using these two concepts, the language allows you to overload methods to your will:
function foo(){
var info = "Argument list:\n";
for(var i=0, len=arguments.length; i<len; i++){
info += "- Argument #" + (i+1) + " is a " + typeof(arguments[i]) + "\n";
}
alert(info);
}
foo(1, "1", {}, [], function(){});
Gives:
Argument list:
- Argument #1 is a number
- Argument #2 is a string
- Argument #3 is a object
- Argument #4 is a object
- Argument #5 is a function
+1 for Jani's answer. Just check the type of each parameter, and adjust your logic accordingly.

Categories

Resources