I'm looking to see how the typeof operator in JavaScript knows that an object is a function.
To be precise, I'm wondering how I can take the function 'body' and reverse engineer it to determine what arguments it expects. The arguments property seemed close, but is only available within the evaluated function.
Neither uneval() or toSource() appear to do quite what I want, in addition to being obsolete.
The specification shows that:
Objects that do not implement [[Call]] are objects
Objects that do implement [[Call]] are functions
([[Call]] is an "internal property" of objects - it's not exposed directly to interactable running JavaScript)
So anything that can be ()d is a function. This will even include Proxies, since proxies can be called as if they were functions.
For the other question:
I'm wondering how I can take the function 'body' and reverse engineer it to determine what arguments it expects
The simplest method would be to turn the function into a string and use a regex to parse the parameter list:
function sum(a, b) {
return a + b;
}
const argList = String(sum).match(/\((.*)\)/)[1];
console.log(argList.split(/,\s*/)); // depending on how complicated the list is
// you may need to make the above pattern more elaborate
in javascript we can perform operations on an object in a few different ways. My question is primarily about the 2 ways described below:
function op() {
this.x;
this.y;
etc..
}
op.apply(someObject);
or
function op(ob) {
ob.x;
ob.y;
etc..
}
op(someObject);
both of these seem to get the same end result. are there scenarios where using one has advantages over using the other?
advantages can be things that make the code:
more flexible
more declarative
easier to maintain
simpler
or other advantages I haven't thought of
The first (using apply to set this) is a bit more obscure. If one looks just at the function definition, one will spend some time wondering what this is supposed to be. If by any chance, the function is defined as a method, then naturally one would assume that this is supposed to refer to the object it is defined on.
The second variant (without apply) is clearer: the parameter has a name that can (should) reveal its role, while this can remain available for when the function is assigned to an object property, and it is called as a method on that object.
As a side note: apply allows (and expects) the (other) arguments to be passed as an array. This used to be a "plus" in some scenarios, but has become less significant now that the spread syntax is available.
This question already has answers here:
What happens if I call a function with more arguments than it is defined to accept?
(5 answers)
Closed 3 years ago.
I know its silly to ask this question but still, I want to know why don't javascript throw an error if we declare a function with only 1 parameter and pass multiple arguments.
function checkIt(a){
return a;
}
checkIt(6,5);
and the answer we got is 6.
It's just how JS is implemented-- you can have less or more arguments without any errors.
If you have less, you get undefined for where you didn't enter any arguments.
If you have more, it's simply put into the arguments array. Usually, if you want to accept a misc. number of arguments, you'll use the (...) operator in parameters to let people know that it's a function that accepts an unknown number of arguments. Also, the good thing about the (...) operator is that it only grabs arguments that aren't known, as opposed to the arguments variable which just grabs everything.
Interesting question.
JavaScript is a "Loosely Typed" Language.
In programming, we call a language "loosely typed" when you don't have to explicitly specify types of variables and objects.
JavaScript is loosely typed. You don't have to tell that a string is a string, nor you can require a function to accept an integer as its parameter.
This gives JavaScript a lot of flexibility. Flexibility lets you move faster, change things quickly, iterate at a faster velocity.
One of the features of loosely typed language is that they auto initialize and typecast variables as required. Hence, when the JS interpreter reads the arguments and sees that one of the argument is missing, it automatically initializes it as undefined and continues with the further programming flow.
This is a concept which almost applicable to all loosely typed languages.
Thanks.
One reason is that it's not necessarily possible to determine how many arguments a function should accept, just from reading it. For example, what if your checkIt checked arguments[1] somewhere? (But that's not something for the interpreter to scan for on function invocation)
function checkIt(a) {
console.log(arguments[1]);
return a;
}
checkIt(6, 5);
Or, the same thing with argument rest syntax:
function checkIt(...args) {
console.log(args[1]);
return args[0];
}
checkIt(6, 5);
The argument index to find could even be dynamic:
function checkIt(argIndex, ...args) {
console.log(args[argIndex]);
}
checkIt(1, 5, 6, 7);
Passing more arguments than stated in the parameter list may well be a code smell, but just like missing semicolons and unnecessary semicolons, there's no explicit reason for it to throw an error, so it doesn't.
I am new to JavaScript and I am learning React using the following tutorial.
It also teaches to use Alt as a state management library and my question is related to the connect method syntax. I am not explaining the problem in detail as I believe my question is only related to understanding the syntax.
I understand that here connect passes comma separated parameters as props to the component App. I however do not understand the first parameter.
The arrow functions I have come across all use {} after => such as () => {}, where parameters will be in () and body of the function will be in {}
My understanding of ({lanes}) => ({lanes}) is that this is a function that takes an array of objects named lanes and returns the same array .The code snippet is as below:
export default connect(({lanes}) => ({lanes}), {
LaneActions
})(App)
My questions are:
Am I right that the first parameter is indeed a function?
is lanes enclosed in {} to specify it's an array? If no, what does it represent?
If 1. is right, why pass a function that passes the parameter as is. Why not write connect as connect(lanes,LaneActions)(App) or connect({lanes},LaneActions)(App)
Would enclosing lanes in {} make a difference and what is it?
If 1. is wrong please explain what the first parameter means.
Yes, that is indeed an arrow function.
No, that is not an "array" in JS (although if you've used PHP, you might mistakenly call it that, since the PHP community often uses "(associative) array" for this concept). That's an "object" in JS jargon, i.e., a key-value data structure (whereas in JS, arrays are numerically indexed). Specifically, the left-hand side is a new feature called "destructuring arguments", which takes an object and pulls out specific keys into local variables. On the right-hand side, there's an object literal, creating a new object based on local data (note that the value is omitted, a trick possible in recent JS).
Presumably because connect expects a callback as the first argument, and would break if you passed a non-function. Also, note that this isn't plain passthrough; it strips every key except lanes from the first argument, before returning it.
Since (1) is right, no answer needed here.
5 & 6: These are a bit broad. I'd recommend asking a new question or checking MDN's page on arrow functions if you want to find out all there is to know. To answer for this specific case: the () on the argument is needed because the arguments are more complex than a single identifier, the {} in the arguments are for destructuring, the () on the body is to distinguish between an object literal and a block consisting only of the single statement lanes, and the {} in the body creates an object literal.
If you're wondering exactly what the (somewhat densely-coded) arrow function does, by the way, it does roughly the same thing as the following (give or take a few currently-irrelevant quirks of arrow functions):
function(obj) {
return { lanes: obj.lanes };
}
When creating a JavaScript function with multiple arguments, I am always confronted with this choice: pass a list of arguments vs. pass an options object.
For example I am writing a function to map a nodeList to an array:
function map(nodeList, callback, thisObject, fromIndex, toIndex){
...
}
I could instead use this:
function map(options){
...
}
where options is an object:
options={
nodeList:...,
callback:...,
thisObject:...,
fromIndex:...,
toIndex:...
}
Which one is the recommended way? Are there guidelines for when to use one vs. the other?
[Update] There seems to be a consensus in favor of the options object, so I'd like to add a comment: one reason why I was tempted to use the list of arguments in my case was to have a behavior consistent with the JavaScript built in array.map method.
Like many of the others, I often prefer passing an options object to a function instead of passing a long list of parameters, but it really depends on the exact context.
I use code readability as the litmus test.
For instance, if I have this function call:
checkStringLength(inputStr, 10);
I think that code is quite readable the way it is and passing individual parameters is just fine.
On the other hand, there are functions with calls like this:
initiateTransferProtocol("http", false, 150, 90, null, true, 18);
Completely unreadable unless you do some research. On the other hand, this code reads well:
initiateTransferProtocol({
"protocol": "http",
"sync": false,
"delayBetweenRetries": 150,
"randomVarianceBetweenRetries": 90,
"retryCallback": null,
"log": true,
"maxRetries": 18
});
It is more of an art than a science, but if I had to name rules of thumb:
Use an options parameter if:
You have more than four parameters
Any of the parameters are optional
You've ever had to look up the function to figure out what parameters it takes
If someone ever tries to strangle you while screaming "ARRRRRG!"
Multiple arguments are mostly for obligatory parameters. There's nothing wrong with them.
If you have optional parameters, it gets complicated. If one of them relies on the others, so that they have a certain order (e.g. the fourth one needs the third one), you still should use multiple arguments. Nearly all native EcmaScript and DOM-methods work like this. A good example is the open method of XMLHTTPrequests, where the last 3 arguments are optional - the rule is like "no password without a user" (see also MDN docs).
Option objects come in handy in two cases:
You've got so many parameters that it gets confusing: The "naming" will help you, you don't have to worry about the order of them (especially if they may change)
You've got optional parameters. The objects are very flexible, and without any ordering you just pass the things you need and nothing else (or undefineds).
In your case, I'd recommend map(nodeList, callback, options). nodelist and callback are required, the other three arguments come in only occasionally and have reasonable defaults.
Another example is JSON.stringify. You might want to use the space parameter without passing a replacer function - then you have to call …, null, 4). An arguments object might have been better, although its not really reasonable for only 2 parameters.
Using the 'options as an object' approach is going to be best. You don't have to worry about the order of the properties and there's more flexibility in what data gets passed (optional parameters for example)
Creating an object also means the options could be easily used on multiple functions:
options={
nodeList:...,
callback:...,
thisObject:...,
fromIndex:...,
toIndex:...
}
function1(options){
alert(options.nodeList);
}
function2(options){
alert(options.fromIndex);
}
It can be good to use both. If your function has one or two required parameters and a bunch of optional ones, make the first two parameters required and the third an optional options hash.
In your example, I'd do map(nodeList, callback, options). Nodelist and callback are required, it's fairly easy to tell what's happening just by reading a call to it, and it's like existing map functions. Any other options can be passed as an optional third parameter.
I may be a little late to the party with this response, but I was searching for other developers' opinions on this very topic and came across this thread.
I very much disagree with most of the responders, and side with the 'multiple arguments' approach. My main argument being that it discourages other anti-patterns like "mutating and returning the param object", or "passing the same param object on to other functions". I've worked in codebases which have extensively abused this anti-pattern, and debugging code which does this quickly becomes impossible. I think this is a very Javascript-specific rule of thumb, since Javascript is not strongly typed and allows for such arbitrarily structured objects.
My personal opinion is that developers should be explicit when calling functions, avoid passing around redundant data and avoid modify-by-reference. It's not that this patterns precludes writing concise, correct code. I just feel it makes it much easier for your project to fall into bad development practices.
Consider the following terrible code:
function main() {
const x = foo({
param1: "something",
param2: "something else",
param3: "more variables"
});
return x;
}
function foo(params) {
params.param1 = "Something new";
bar(params);
return params;
}
function bar(params) {
params.param2 = "Something else entirely";
const y = baz(params);
return params.param2;
}
function baz(params) {
params.params3 = "Changed my mind";
return params;
}
Not only does this kind of require more explicit documentation to specify intent, but it also leaves room for vague errors.
What if a developer modifies param1 in bar()? How long do you think it would take looking through a codebase of sufficident size to catch this?
Admittedly, this is example is slightly disingenuous because it assumes developers have already committed several anti-patterns by this point. But it shows how passing objects containing parameters allows greater room for error and ambiguity, requiring a greater degree of conscientiousness and observance of const correctness.
Just my two-cents on the issue!
Your comment on the question:
in my example the last three are optional.
So why not do this? (Note: This is fairly raw Javascript. Normally I'd use a default hash and update it with the options passed in by using Object.extend or JQuery.extend or similar..)
function map(nodeList, callback, options) {
options = options || {};
var thisObject = options.thisObject || {};
var fromIndex = options.fromIndex || 0;
var toIndex = options.toIndex || 0;
}
So, now since it's now much more obvious what's optional and what's not, all of these are valid uses of the function:
map(nodeList, callback);
map(nodeList, callback, {});
map(nodeList, callback, null);
map(nodeList, callback, {
thisObject: {some: 'object'},
});
map(nodeList, callback, {
toIndex: 100,
});
map(nodeList, callback, {
thisObject: {some: 'object'},
fromIndex: 0,
toIndex: 100,
});
It depends.
Based on my observation on those popular libraries design, here are the scenarios we should use option object:
The parameter list is long (>4).
Some or all parameters are optional and they don’t rely on a certain
order.
The parameter list might grow in future API update.
The API will be called from other code and the API name is not clear
enough to tell the parameters’ meaning. So it might need strong
parameter name for readability.
And scenarios to use parameter list:
Parameter list is short (<= 4).
Most of or all of the parameters are required.
Optional parameters are in a certain order. (i.e.: $.get )
Easy to tell the parameters meaning by API name.
Object is more preferable, because if you pass an object its easy to extend number of properties in that objects and you don't have to watch for order in which your arguments has been passed.
For a function that usually uses some predefined arguments you would better use option object. The opposite example will be something like a function that is getting infinite number of arguments like: setCSS({height:100},{width:200},{background:"#000"}).
I would look at large javascript projects.
Things like google map you will frequently see that instantiated objects require an object but functions require parameters. I would think this has to do with OPTION argumemnts.
If you need default arguments or optional arguments an object would probably be better because it is more flexible. But if you don't normal functional arguments are more explicit.
Javascript has an arguments object too.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments