passing single argument into a function that requires multiple arguments in javascript - javascript

I'm trying to read through some source code on the internet, and I'm getting confused because the author defined a function as:
var _0x80a1 = function (x, a) {...}
But then only calls it using statements like this:
_0x80a1("0x0")
How does that work?

JavaScript parameters are optional you don't need to pass them. So you can do something like this:
function multiply(a, b) {
if(typeof b === 'undefined') {
b = 10;
}
return a * b;
}
console.log(multiply(5));
// expected output: 50
In newer versions of JS you can also do default parameters like this:
function multiply(a, b = 10) {
return a * b;
}
console.log(multiply(5));
// expected output: 50

No function "requires" an argument in JavaScript. It's not a strongly typed language.
I might be typing out of my own butt, but I think function's arguments are syntactic sugar in JS. You can always pass any amount of arguments, regardless of the function's "signature", because the only thing that identifies a function in JS, is its name (and the object on which it is called). That is why, the arguments object exists.
So, as others pointed it out, the second, third, or any other argument that wasn't given will simply be undefined.
An answer on this subject with examples

In ,JavaScript function parameters are optional.If your'e not making use of 'a' inside your function then JS compiler don't care about that.If your'e making use of 'a' inside your function then you will encounter some error like "a is undefined".
function (x,a=10){
}
You can set default parameters like this.Now even if your'r passing one parameter to your function it will run without any errors

I was curious so tried to understand this a bit so I could try to answer.
The variable _8x80a1 is a literal bit definition (https://www.hexadecimaldictionary.com/hexadecimal/0x80A1/) representing e.g. 32929 in decimal.
I'm guessing JS internally numbers all functions when its run. This leaves an entire integer (32766) 'vanilla' functions that can be compiled before using a literal as a function name might cause a conflict.
So the 'x' in the function def. looks like it's passing a string, but it might be just calling 'Function #0' in the _8x80a1 var/function. This would make sense if the function contains multiplpe 'sub functions', as then the 'a' variable can be an object collection (e.g. parameters), that can be passed to the sub-function.
Roughtly, I think .. Not used JS for a whilst and just thought I'd try to help answer! ;-) Essentially a compact way to make a toolkit you can copy between projects, and know your references will all work as expected to your tools, without disrupting e.g. jQuery or other scripts. (Wouldn't be surprised if this is how JS is minified actually ;)).
Chris

Related

Can I make a variable of a class into a function with JavaScript? [duplicate]

Is it possible to make an object callable by implementing either call or apply on it, or in some other way? E.g.:
var obj = {};
obj.call = function (context, arg1, arg2, ...) {
...
};
...
obj (a, b);
No, but you can add properties onto a function, e.g.
function foo(){}
foo.myProperty = "whatever";
EDIT: to "make" an object callable, you'll still have to do the above, but it might look something like:
// Augments func with object's properties
function makeCallable(object, func){
for(var prop in object){
if(object.hasOwnProperty(prop)){
func[prop] = object[prop];
}
}
}
And then you'd just use the "func" function instead of the object. Really all this method does is copy properties between two objects, but...it might help you.
ES6 has better solution for this now. If you create your objects in a different way (using class, extending 'Function' type), you can have a callable instance of it.
See also: How to extend Function with ES6 classes?
Following the same line of #Max, but using ES6 extensions to Object to pass all properties and prototype of an object obj to the callable func.
Object.assign(func, obj);
Object.setPrototypeOf(func, Object.getPrototypeOf(obj));
Others have provided the current answer ("no") and some workarounds. As far as first-class support in the future, I suggested this very thing to the es-discuss mailing list. The idea did not get very far that time around, but perhaps some additional interest would help get the idea moving again.
https://esdiscuss.org/topic/proposal-default-object-method
"CALLABLE OBJECTS"
I haven't seen mention of this type of answer yet.. but this is how I do "callable" objects:
<< PSEUDO CODE >>
{...objectWithFunctionsInside}[keyString](optionalParams)
short example defining first, simplest and preferred method if I just want a "callable object," in my definition:
let obj = {
o:()=>{return("oranges")},
b:()=>{return("bananas")},
s:"something random here, doesn't have to be functions"
}
obj["o"]()
short example of nameless object being run within a function's return, with parameters (note parameters works in the first example too):
function autoRunMyObject(choice,param){
return{
o:(p)=>{return(p+"oranges")},
b:(p)=>{return(p+"bananas")},
}[choice](param)
}
autoRunMyObject("b","orange you glad I didn't say ")
and that's pretty much it
You could even get weirder with it and do nameless functions that auto-run themselves and produce an output right away... for no reason, lol.
... hit F12 and copy this code into your browser console and press enter, you'll get an output right away with the full string:
((autoparam="o")=>{return{
o:(p)=>p+"oranges",
b:(p)=>p+"bananas",
}[autoparam]("I guess this time it's ")})()
You could even pass in the string of "b" in the final parenthesis for a different output from the default "o".
Also, each of my examples (minus the pseudo code first example) are easily copy/paste-able into the browser console for quick testing -- it's a nice place to experiment with JS.
In summary -- this is how I like to do "callable objects"
It's much better than
SWITCH(){CASE:BREAK;};
statements and
IF{}ELSE IF(){}ELSE IF(){};
chains.

Can't use String.prototype.match as function for Array.some?

This doesn't work:
var s = '^foo';
console.log(['boot', 'foot'].some(s.match));
Uncaught TypeError: String.prototype.match called on null or undefined
But this does:
var s = '^foo';
console.log(['boot', 'foot'].some(function(i) { return i.match(s) }));
Why is this? I imagine somehow the String.prototype.match function is too "primitive" or something, but why exactly? Since I'm not using ES2015, the second version seems quite verbose. Is there an alternative?
EDIT
When I wrote the above, I actually got it backwards compared to my actual need, which was matching one string against a number of regexes. But thanks to the great answers and comments below, I get it: [/^foo/, /^boo/].some(''.match, 'boot').
Note: The value of this is determined by how the function is called! (exception: bound and arrow functions)
If you pass s.match to .some, then the function will be called with this set to the global object (e.g. window) not the string it "belongs" to.
I.e. it would be equivalent to this:
String.prototype.match.call(window, 'foo')
This cannot work because this has to refer to a string object.
You could solve this by binding the function to a specific this value:
['boot', 'foot'].some(s.match.bind(s));
Learn more about this:
MDN - this
You Don't Know JS: this or That?
How to access the correct `this` context inside a callback?
A function value in Javascript does not bring its object along with it. The value of s.match is a plain function value, with no knowledge that you happened to find it attached to s. In fact, no matter what String you access it through, it's always the same function value:
"foo".match === "bar".match
//= true
When you call a function through an object, Javascript sets this to that object for the duration of the function call. But as soon as anything comes between retrieving the function value and calling it, any object association is lost.
You can create a function that does remember a specific this value using bind, as in #Felix King's answer. someFunction.bind(someObject) has approximately the same meaning as function(arg1, arg2,...) { return someObject.someFunction(arg1, arg2,...); }, but it automatically handles the number of parameters properly.

How come I can call a function with an argument, when the function is defined with no parameters?

Good day!
I stumbled upon something I've never seen in the realm of JavaScript, but I guess it's very easy to explain for someone who knows the language better. Below I have the following function: (Code taken from the Book: "Secrets of the JavaScript Ninja")
function log() {
try {
console.log.apply(console, arguments);
}
catch(e) {
try {
opera.postError.apply(opera, arguments);
}
catch(e) {
alert(Array.prototype.join.call(arguments, " "));
}
}
}
As you can see, the function is defined with an empty parameter list, but I was completely puzzled when I saw, later in the book, that they actually use said function like this...
var x = 213;
log(x); //Hmmm, I thought this function had an empty parameter list.
Could someone please explain to me, why is that function call allowed/possible? What are the concepts involved in JS that support this functionality? Thanks in advance, I'm very confused.
Best Regards,
You can call functions with the wrong number of parameters as much as you like. Excess parameters will be ignored; missing parameters will be given a default value.
As you can see from the code sample, you can access the arguments that were actually passed with the "arguments" object.
One of the design principles of JavaScript is to be forgiving rather than strict. If there's a way to keep going, JavaScript keeps going. Failing to pass a sufficient number of arguments is not considered fatal in JavaScript the way it would be in a language like C#, where one of the design principles is "bring possible errors to the developer's attention by failing at compile time".
Javascript functions have an implicit arguments parameter which is an array-like object with a length property.
for your log method you could do.
function log(){
alert(arguments[0]);
alert(arguments[1]);
}
And you can call log.
log("first","second");
JavaScript functions are variadic, i.e. they can take an arbitrary and infinite amount of arguments. You can access them via the arguments object, and pass in a variable number of values via apply. The formal parameter list just declares some variable names that are pointers to the arguments, and if there are less arguments given than parameter names defined they will default to undefined.
JavaScript allows you to call functions with any number of parameters, but if you'd like something more rigorous, there is TypeScript.
It prevents incorrect method calls and a lot of other JavaScript silliness.

Performance penalty for undefined arguments

I quite often have optional arguments in functions, but some testing is showing a huge performance hit for them in firefox and safari (70-95%). Strangely, if I pass in the literal value undefined then there is no penalty. What could be happening here? I wouldn't have thought that it was a scope chain issue as they are inherently local to the function. Am I to start passing undefined into every optional argument?
jsPerf: http://jsperf.com/function-undefined-args/2
For a function like this:
function threeArgs(x, y, z) {
return x + y + z;
}
that's called like this:
threeArgs(1, 2, 3);
the optimizer is free to make the choice to generate no code at all. It's fairly easy for it to determine that there are no side effects, because the function simply references its parameter values and returns the result of a simple expression. Since the return value is ignored, there's no reason for the runtime to do anything at all.
Beyond that, if the code were:
something += threeArgs(1, 2, 3);
the optimizer might decide to generate code roughly equivalent to:
something += 6;
Why? Because the call was made with numeric constants, and it can safely fold those at code generation time. It might be conservative on that, because numbers are weird, but here they're all integers so it could well do this. Even if it didn't, it could safely inline the function:
something += 1 + 2 + 3;
When there's a parameter missing, however, it may be that the optimizers bail out and generate a real function call. For such a simple function, the overhead of the function call could easily account for a large difference in performance.
By using variables instead of constants in a test, and by actually using the return value of the function, you can "confuse" the optimizer and keep it from skipping the call or pre-computing the result, but you can't keep it from inlining. I still think that your result is interesting for that reason: it exposes the fact that (as of today anyway) those optimizers are sensitive to the way that functions are invoked.
I think what could explain the performance difference is the way arguments are passed to a function object: via the arguments object. When not passing any arguments, JS will start by scanning the arguments object for any of the given arguments, when those are undefined, The arguments prototype chain will be scanned, all the way up to Object.prototype. If those all lack the desired property, JS will return undefined. Whereas, passing undefined explicitly, sets it as a property directly on the arguments object:
function foo(arg)
{
console.log(arguments.hasOwnProperty('0'));
}
foo();//false'
foo('bar');//true
foo(undefined);//true
I gather that's the reason why passing undefined explicitly tends to be faster.

Why does my JavaScript function accept three arrays, but not an array containing three arrays?

function product() {
return Array.prototype.reduce.call(arguments, function(as, bs) {
return [a.concat(b) for each (a in as) for each (b in bs)]
}, [[]]);
}
arr4=[['4','4A','4B'],['16D','15D'],['5d','5e']];
alert(product(['4','4A','4B'],['16D','15D'],['5d','5e']);
The above works but the following don't work:
arr4=[['4','4A','4B'],['16D','15D'],['5d','5e']];
alert(product(arr4);
Thanks for suggestions
You can have either one or the other; otherwise it's poorly defined. (Unless you want to make the very questionable decision to do special-casing like "if my first argument is an array and each element is an array, return something different". Then you'll be remaking PHP in no time. =])
Use the somefunction.apply method instead; that's what it was made for. For example:
product.apply(this, arr4)
Is equivalent to:
product(arr4[0], arr4[1], ...)
If you do this a lot, you can define product2(arrays) {return product.apply(this,arrays)}.
However unless you want to do both product([..], [..], ..) and product([[..],[..],..]), this seems inelegant.
If you want this function to behave by default like product([[..],[..],..]), then the correct way to solve this is to modify the function to suit your needs. It is currently using the default "variadic" (multiple arguments) arguments variable special to javascript, which stands for an array representing all the arguments you passed into the function. This is not what you want, if you want normal-style fixed-number-of-arguments functions. First add in the appropriate parameter:
function product(arrays) {
...
}
and rather than using the default arguments variable, replace that with arrays.

Categories

Resources