Is the order in which function arguments are resolved guaranteed? [duplicate] - javascript

This question already has answers here:
What is the order of evaluation for function arguments in Javascript?
(3 answers)
Closed 5 years ago.
say I have this:
function write3(a, b, c) {
document.write(a + " " + b + " " + c);
}
var arr = [1, 2, 3];
var i = 0;
write3(arr[i++], arr[i++], arr[i++]);
It results in 1 2 3 as expected, however, I'm not sure that this is guaranteed behavior. Could the arguments passed to write3 hypothetically be resolved in any other order than left to right?

Yes, the order of argument evaluation is guaranteed to be left-to-right.
According to sections 11.2.3 and 11.2.4 of the ES5 spec, function arguments are Argument Lists, and Argument Lists should always be evaluated left to right.
Specifically, the function to call gets evaluated, and then the function's arguments are evaluated from left to right.

Could the arguments passed to write3 hypothetically be resolved in any other order than left to right?
No, they will always be resolved left-to-right. This is guaranteed behavior.
I also feel like I should point out that you can call a function with an array of arguments using apply:
write3.apply(null, arr)
. . . or the spread operator in ES6+ (may not be supported in all browsers):
write3(...arr)
Demo Snippet:
function write3(a, b, c) {
document.write(a + " " + b + " " + c)
}
var arr = [1, 2, 3]
write3.apply(null, arr)
write3(...arr)

Afterwords. If you use ES6 you can write:
write3(...arr)

Related

Change Behavior of Operators [duplicate]

This question already has answers here:
Javascript: operator overloading
(9 answers)
Closed 5 years ago.
This is more of a "for fun" sort of thing, as it would be impractical to actually use this. I just want to satisfy my curiosity as to whether or not it's even possible.
I have a function...
function longAdd(a,b){
//computation here
return sum;
}
...which "adds" the values of a and b together as a string; meaning, it iterates through each character and adds them up. Thus, it can compute numbers which are greater than what could otherwise be achieved.
(for the purposes of this question, the actual code should not be relevant, so it is not included)
My question is: would it be possible to directly change the "+" operator to use this function? For instance,
c+d
anywhere in the code would essentially compute longAdd(c,d).
Any possible hacky ways to achieve this? For that matter, can the behavior of any operators be directly changed?
Note: Yes, I am aware this would screw up concatenation and big, numerical values would have to stay strings. This is just a concept I'm curious about.
My question is: would it be possible to directly change the "+" operator to use this function?
No, JavaScript has no user-defined operator overloading at all.
The nearest I can see getting is defining an object with its own valueOf method which returns the result of converting itself to a string and doing your longAdd just on itself, and returning that result. Then the existing + would trigger that behavior on the objects referenced by a and b.
That's not overloading +, just taking advantage of the behavior it already has:
function Thing(val) {
this.val = val;
}
Thing.prototype.valueOf = function() {
// Here I'm just doubling it; you'd actually do your longAdd thing
return this.val * 2;
};
var a = new Thing(1);
var b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
Or with ES2015's class:
class Thing {
constructor(val) {
this.val = val;
}
valueOf() {
return this.val * 2;
}
}
const a = new Thing(1);
const b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
Or just with objects, no constructors:
var thingPrototype = {
valueOf: function() {
return this.val * 2;
}
};
var a = Object.create(thingPrototype);
a.val = 1;
var b = Object.create(thingPrototype);
b.val = 2;
console.log(a + b); // 6 (1 * 2 + 2 * 2)

Converting ECMAScript 6's arrow function to a regular function [duplicate]

This question already has answers here:
What's the meaning of "=>" (an arrow formed from equals & greater than) in JavaScript?
(14 answers)
Closed 6 years ago.
I have the following arrow function
if( rowCheckStatuses.reduce((a, b) => a + b, 0) ){}
rowCheckStatuses is an array of 1's and 0's, this arrow function adds them all up to produce a number. This number acts as a boolean to determine whether or not there is at least one "1" in the array.
The issue is, I don't really understand how arrow functions work, and my IDE thinks it's bad syntax and refuses to check the rest of my document for syntax errors.
How would I go about converting this to a regular function to alleviate both issues?
An arrow function can usually be converted by replacing
(<args>) => <body>
with
function(<args>) { return <body>; }
So yours would be
rowCheckStatuses.reduce(function(a, b) { return a + b; }, 0)
There are exceptions to this rule so it's important that you read up on arrow functions if you want to know all of the differences. You should also note that arrow functions have a lexical this.
You can refactor it as:
if( rowCheckStatuses.reduce(function(a, b){return a + b}, 0)
The initial accumulator isn't necessary (unless you expect the array to be empty sometimes), it could be:
if( rowCheckStatuses.reduce(function(a, b){return a + b})
This number acts as a boolean to determine whether or not there is at least one "1" in the array
It might be faster (and clearer) to use:
if( rowCheckStatuses.some(function(a){return a == 1}))
which will return true if there are any 1s in rowCheckStatuses and will return as soon as one is encountered. Another alternative is indexOf:
if( rowCheckStatuses.indexOf(1) != -1)
Lots of alternatives.
Replacing arrow functions with regular functions is usually unproblematic:
var f = x => y;
var g = function(x) { return y; }
Or, in your specific example:
rowCheckStatuses.reduce((a, b) => a + b, 0);
rowCheckStatuses.reduce(function(a, b) { return a + b; }, 0);
However, be aware of the exceptions:
Arrow functions don't bind a this value. Accessing this in an arrow function might thus return the value of the enclosing execution context's this:
function MyClass() {}
MyClass.prototype.f = () => this;
MyClass.prototype.g = function() { return this; }
myClass = new MyClass();
console.log(myClass.f()); // logs `Window`
console.log(myClass.g()); // logs `myClass`
Arrow functions also don't have access to a local arguments object. Accessing arguments in an arrow function might e. g. return the arguments of an enclosing function:
function test() {
var f = () => arguments;
var g = function() { return arguments; }
console.log(f()); // logs test's arguments
console.log(g()); // logs g's arguments
}
test('x');
The same holds for new.target and super. See also What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?

JavaScript: How to pass extra parameters to a callback [duplicate]

This question already has answers here:
Pass an extra argument to a callback function
(5 answers)
Closed 6 years ago.
I have a question which has bugged me for a while now.
Let's say I have the following array:
var array = [1, 2, 3]
Now I have a function similar to this:
function print(num, str) {
console.log(str + ": " + num);
}
Is it possible to call the forEach method and pass a string to it?
// how do I pass "str"?
array.forEach(print);
Thanks!
You have two options here:
Either you swap the arguments, so that str comes first. Then you can use function.bind to bind the first arguments of the function:
function print(str, num) {
console.log(str + ": " + num);
}
array.forEach(print.bind(null, 'someStr'));
Alternatively, you can also create a new (anonymous) function which simply passes some value to the second argument:
array.forEach(function (item) { print(item, 'someStr'); });
With ES6 and the arrow functions, this even gets a bit prettier:
array.forEach(item => print(item, 'someStr'));
Both solutions have a very similar effect in that they create a new function object which is then passed to forEach. What makes more sense to you depends on your use cases.
And just as a note: You just need to remember that the callback passed to forEach actually takes up to three arguments (the item, the item’s index, and the array itself), so be careful when you pass a function that accepts other additional arguments. You can again use a local function to remedy that.
Not in this particular situation. The simple solution here is to use an anonymous function wrapper:
array.forEach(function (i) { print(i, str); });
If you reversed the parameters to print, you could do this a little more elegantly like so:
function print(str, num) { .. };
array.forEach(print.bind(null, str));
str will be bound as the first parameter, any parameters that forEach passes when invoking the callback are passed in second, third etc. place.
Here you go
var array = [1, 2, 3];
function print(str, num) {
console.log(str + ": " + num);
}
var str = 'someString';
array.forEach(print.bind(null, str));

Is there a JavaScript equivalent for C# 'params'?

I need a method that can have an arbitrary number of parameters. In C# we have the params statement. Do we have anything similar in JavaScript?
There is the arguments collection, which contains all arguments passed to the function.
There is a) no need to specify "optional" arguments in the function signature and b) any function accepts any number of parameters.
function foo() {
console.log(arguments);
}
foo(1,2,3,4); // logs [1, 2, 3, 4]
Likewise, there is no need to supply "required" arguments in a function call:
function foo(a, b, c, d) {
console.log(arguments);
}
foo(1,2); // logs [1, 2]
Any argument named in the signature but not supplied in the function call will be undefined.
Note that arguments behaves like an Array, but technically it isn't one. For example, you can call arguments[0], but you can't call arguments.slice(). What you can do to get around this is using the Array prototype:
Array.prototype.slice.call(arguments, 1, 2);
The so-called rest parameter ... is a new (ES6+) addition to the language and makes working with variadic functions more comfortable. #ArunCM's answer explains it.
I know this thread is too old but I believe something is missing here.
There is Rest parameter (introduced in ECMAScript 6) which will allow us to represent an indefinite number of arguments as an array.
It always returns an array. Which means even in defensive JavaScript land, it’s ok to do things like check .length of rest without guards.
Syntax :
function(a, b, ...theArgs) {
// ...
}
There are three main differences between rest parameters and the arguments object:
rest parameters are only the ones that haven't been given a separate name, while the arguments object contains all arguments passed to the function
the arguments object is not a real array, while rest parameters are Array instances, meaning methods like sort, map, forEach or pop can be applied on it directly;
the arguments object has additional functionality specific to itself (like the callee property).
Additional reading : Spread
function f(x, ...y) {
// y is an Array
return x * y.length;
}
console.log("Expected result : 3*2 = 6 & Actual result : " + f(3, "hello", true));
console.log("Expected result : 3*4 = 12 & Actual result : " + f(3, "a", true, "b", 1));
//here we are not passing anything to "y" but its still safe to check .length of "y" because it always return an array.
console.log("Expected result : 3*0 = 0 & Actual result : " + f(3));
Yes. arguments.
function concatStrings () {
var str = '';
for (var i = 0; i < arguments.length; i++) {
str += arguments[i];
}
return str;
}
Be aware that arguments isn't an array, so it doesn't have methods like join or push. It's just an array-like object (with numerical properties and a length property) so it can be iterated through.
JavaScript has arguments object inside functions. It contains of all params passed to the function.
More info
It is some sort of implicit in the special variable "arguments". Use like this:
function something(arg1, arg2) {
for (var i = 0; i < arguments.length; i++) {
var x = arguments[i];
}
}
Then you can call it like something(1, 2, 3, 'a', 'b', 'c')
More examples here: http://www.jtricks.com/javascript_tutorials/varargs.html
Javascript functions can accept any number of parameters by default. You can see them with the arguments variable.
See here.

Javascript: passing multiple arguments as a single variable

is it possible to pass multiple arguments using a single variable? For example, if I wanted to do something like:
function foo(x,y){
document.write("X is " + x);
document.write("Y is " + y);
}
var bar = "0,10";
foo(bar);
The example above is an simplified example of what I was trying to do. It doesn't work (because the "bar" is detected as a single argument). I know that there are easier ways to implement this using arrays.
So, I ask this question mostly out of curiosity - is it possible to get the "bar" variable to be detected as not one, but 2 arguments?
Thanks!
function foo(thing) {
document.write("X is " + thing.x);
document.write("Y is " + thing.y);
}
var bar = {x:0, y:10};
foo(bar);
What you're asking for is impossible. If you want to pass multiple values in a single argument, use an Array or an Object. If you really must use a string, you'll have to call split() to break the argument string into an array.
function Add (a, b, c) {
return a + b + c;
}
var nums = [1, 2, 4];
var sum = Add.apply (null, nums);
variable-length argument list:
function Add () {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
var n = Add (1, 2, 3, 4, 5);
Reference: apply method (Function object)
Sure, this is common to pass an object for options
function foo(options){
//...
}
then you can pass in anything...
var opts = {};//create an object
opts['x'] = 5;//set whatever properties you want
opts['y'] = 23;
opts['border'] = 3;
foo(opts);//pass 1 argument, with as many values as you want
Often these are defined inline, especially if the values are not needed outside of the method call.
foo({'x':5,'y':23,'border':3});
Not really.
You could do:
window.foo.apply(window, bar.split(','));
(Apply lets you pass an array of arguments instead of each argument separately)
… but the phrase "ugly" comes to mind.
You may use this:
var bar = [0,10]; // creates an array
foo(bar);
function foo(arg){
document.write("X is " + arg[0]);
document.write("Y is " + arg[1]);
}
No, but you could pass a an array or object:
function foo(options){
document.write("X is " + options.x);
document.write("Y is " + options.y);
}
var bar = {x: 0, y:10};
No, it's not possible. You could put two arguments in an array, but an array is still one variable. Then you would need to rewrite the function to accept one variable, and treat it as an array, like this:
function foo(x){
document.write("X is " + x[0]);
document.write("Y is " + x[1]);
}
Basically, a function accepts variables as arguments and, no matter what kind of variable you pass it, each variable is still only one variable - there's no way to get a single variable to be recognized as multiple arguments. An array is one variable, a JSON object is one variable, etc. These things have multiple parts to them, but they're encapsulated by a single variable.
How about? (For ES6+)
function foo({x, y}){
document.write("X is " + x);
document.write("Y is " + y);
}
and call it with:
foo({x:10, y:5})
There is a downside to using a single structured argument over multiple arguments, and that is with multiple arguments you can use /** in may IDEs to generate a method header which will display an #param for each argument.
But if you only have one argument then you will lose the niceness of a description for each argument and hence less useful intelli-sense in the IDE as it wont pick up the docuemntation of the structure's properties.
/**
* Do stuff
* #param {*} param0 - A structure containing the blah, blah blah data
*/
function foo({x, y}){
instead of..
/**
*
* #param {*} x - The value for blah
* #param {*} y - the value for blah-blah
*/
foo1(x, y){
To directly answer your question, no. It's worth noting that the way you have bar defined it's only one value, a string containing "0,10".
function myFunction(a,b){
//do stuff with a and b here
}
myFunction(1,'text')
or...
<a onClick="myFunction(1,'text');"
There's an article on the issue here.

Categories

Resources