I am fairly new to JavaScript
and coming from a different programming background I have a tough time to understand how JavaScript
knows how to resolve parameters passed to a function.
Let's look at and easy example. from the documentation of jQuery .on
, I see 2 different signatures:
.on( events [, selector ] [, data ], handler )
.on( events [, selector ] [, data ] )
However, the following snippet produces perfectly valid code and does what is intended:
$(function() {
let dat = {a: 1, b: 2}
$('#do').on('click', dat, function(evt) {
alert(evt.data.b);
});
$('#do2').on('click', function(evt) {
alert("click");
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="do">
Click!
</button>
<button id="do2">
Click!
</button>
How does JavaScript
"know" that dat
in the first case is the data (and not the selector
)? Apparently there is no positional matching of neither of the two signatures? So how does that work internally and how could I use this pattern for my own functions?
Looking at the jQuery source code for on
, types are checked by hand and any omitted parameters are accounted for manually (parameters always populate left-to-right):
function on( elem, types, selector, data, fn, one ) {
var origFn, type;
// Types can be a map of types/handlers
if ( typeof types === "object" ) {
// ( types-Object, selector, data )
if ( typeof selector !== "string" ) {
// ( types-Object, data )
data = data || selector;
selector = undefined;
}
for ( type in types ) {
on( elem, type, selector, data, types[ type ], one );
}
return elem;
}
if ( data == null && fn == null ) {
// ( types, fn )
fn = selector;
data = selector = undefined;
} else if ( fn == null ) {
if ( typeof selector === "string" ) {
...etc.
This might be shocking coming from a non-dynamically typed background, but it's pretty commonplace in JS.
How doe JavaScript "know" that datin the first case is the data (and not the selector)?
It doesn't. The language just passes the arguments given by the caller to the function. Figuring out what the caller passed is handled by the function, not the language.
Apparently there is no positional matching of neither of the two signatures?
JavaScript only uses positional matching. As of ES2015+, it will also provide defaults for missing parameters (or parameters whose passed argument is the value undefined
).
So how does that work internally and how could I use this pattern for my own functions?
In JavaScript, you don't have to pass the same number of arguments to a function as the number of parameters it declares; you can pass fewer or more. The function can tell what you've passed it in three ways:
arguments
array-like object which is created for each function and contains the arguments and a length
property saying how many there are.undefined
.Here's an example:
function example(obj, number, str) {
console.log("Arguments received: " + arguments.length);
if (typeof number === "string") {
// Caller provided a string, not anumber, as the second
// argument; move things around
str = number;
number = undefined;
}
console.log("obj", obj);
console.log("number", number);
console.log("str", str);
}
console.log('Calling example({}, 42, "forty-two");');
example({}, 42, "forty-two");
console.log('Calling example({}, "no number given");');
example({}, "no number given");
.as-console-wrapper {
max-height: 100% !important;£
}
Here's an example of using a rest parameter:
function example(obj, ...rest) {
let number, str;
if (rest.length === 2) {
[number, str] = rest; // This is called "destructuring assignment"
} else {
[str] = rest;
}
if (typeof number === "string") {
// Caller provided a string, not anumber, as the second
// argument; move things around
str = number;
number = undefined;
}
console.log("obj", obj);
console.log("number", number);
console.log("str", str);
}
console.log('Calling example({}, 42, "forty-two");');
example({}, 42, "forty-two");
console.log('Calling example({}, "no number given");');
example({}, "no number given");
.as-console-wrapper {
max-height: 100% !important;£
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With