Javascript, help understand how parentheses works in code - javascript

my question is about parentheses () in Javascript code, for example in the snippet of code below, are the parentheses 'grouping operators'? or something else? if there are 2 or more sets of parentheses (), which set of () is evaluated first in the same line? have googled but can't find much about this. Although I understand most of this little program, I am struggling to understand lines 5 + 6 as I don't understand this aforementioned parentheses issue, thanks very much for any help!
<script>
function playAudio(audioNumber) {
var audio = document.getElementById('sound' + audioNumber);
audio.play();
var nonPlaying = [1, 2, 3, 4, 5, 6, 7];
nonPlaying.splice(notPlaying.indexOf(audioNumber), 1); // line 5
nonPlaying.forEach(function (id) { // line 6
document.getElementById('sound' + id).pause();
document.getElementById('sound' + id).currentTime = 0;
});
};
</script>

On line 5, the parenthesis follow standard order of operation, just like in math. For
nonPlaying.splice(notPlaying.indexOf(audioNumber), 1);
The call to indexOf is inside of the argument list (parentheses) of splice, so it's evaluated first. This makes sense though since indexOf must be evaluated before its return can be passed to splice.
To answer "which set of () is evaluated first in the same line", that depends on how they're used. In
document.getElementById('sound' + id).pause();
The line is evaluated left to right, although that has little to do with the parentheses. In
a().b()
a must be evaluated first since b is a method of a. The operator associativity of . defines the order.
The only other use is as the parameter list to the anonymous function:
function (id) {...}
Which is a bit of a special case. I don't think there's a situation where you would have nested parentheses in a parameter list; even with destructuring since JS doesn't use () to define any structures.

Related

JavaScript comma seperated values in function body

I recently read some source code that contained a function similar to the one below:
function foo(someArray) {
const arrayPrime = someArray.map(x => x * 2,);
return arrayPrime;
}
To my surprise, the code above is valid - no syntax errors.
Playing with this code more, we can add any number of values separated by commas without generating a syntax error:
function foo(someArray) {
const arrayPrime = someArray.map(x => x * 2, 3, 4, 5, 6);
return arrayPrime;
}
Invoking both versions of foo with foo([11,2,3]) yields 22,4,6.
Can someone explain why this is legal?
Those are additional arguments to the map() method.
map() takes 1 optional argument, the value to be passed as the this context to the callback function. Since arrow functions can't have their this value altered, so it's ignored in this case.
The remaining arguments are ignored completely. JavaScript doesn't report errors when a function is called with more arguments than it needs. (It also doesn't report errors for missing arguments, they're just set to undefined).

Arrow function with multiple statements in one line

Recently I found out that a simple arrow function, for example callback in this map
[1, 2, 3, 4, 5, 6].map(item => {
console.log(item) // or anything else
return item - 1;
})
I can re-write to one line command like this
[1, 2, 3, 4, 5, 6].map(item => (console.log(item), item - 1))
I can use as much statements I want to devided by , and last argument will always be a return value. It looks kind of cool to me, but cant find anything about this syntax in arrow function documentation. Can anyone explain this syntax or just point to place where I found a docs?
Essentially it allows you to do multiple operations in a single statement. It's used commonly in for loops and to assign multiple variables in a single statment, eg.: var a = 1, b = 2;.
Just because it works though, doesn't mean it's a good idea. It makes your code less readable and harder to debug.
See the MDN docs on the Comma Operator.
The comma operator (,) evaluates each of its operands (from left to right) and returns the value of the last operand. This lets you create a compound expression in which multiple expressions are evaluated, with the compound expression's final value being the value of the rightmost of its member expressions. This is commonly used to provide multiple parameters to a for loop.
You are using the comma operator to evaluate multiple expressions:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

Regex to define the number of appearances substituted [duplicate]

I'd like to know how to replace a capture group with its uppercase in JavaScript. Here's a simplified version of what I've tried so far that's not working:
> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'
Would you explain what's wrong with this code?
You can pass a function to replace.
var r = a.replace(/(f)/, function(v) { return v.toUpperCase(); });
Explanation
a.replace( /(f)/, "$1".toUpperCase())
In this example you pass a string to the replace function. Since you are using the special replace syntax ($N grabs the Nth capture) you are simply giving the same value. The toUpperCase is actually deceiving because you are only making the replace string upper case (Which is somewhat pointless because the $ and one 1 characters have no upper case so the return value will still be "$1").
a.replace( /(f)/, String.prototype.toUpperCase.apply("$1"))
Believe it or not the semantics of this expression are exactly the same.
I know I'm late to the party but here is a shorter method that is more along the lines of your initial attempts.
a.replace('f', String.call.bind(a.toUpperCase));
So where did you go wrong and what is this new voodoo?
Problem 1
As stated before, you were attempting to pass the results of a called method as the second parameter of String.prototype.replace(), when instead you ought to be passing a reference to a function
Solution 1
That's easy enough to solve. Simply removing the parameters and parentheses will give us a reference rather than executing the function.
a.replace('f', String.prototype.toUpperCase.apply)
Problem 2
If you attempt to run the code now you will get an error stating that undefined is not a function and therefore cannot be called. This is because String.prototype.toUpperCase.apply is actually a reference to Function.prototype.apply() via JavaScript's prototypical inheritance. So what we are actually doing looks more like this
a.replace('f', Function.prototype.apply)
Which is obviously not what we have intended. How does it know to run Function.prototype.apply() on String.prototype.toUpperCase()?
Solution 2
Using Function.prototype.bind() we can create a copy of Function.prototype.call with its context specifically set to String.prototype.toUpperCase. We now have the following
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Problem 3
The last issue is that String.prototype.replace() will pass several arguments to its replacement function. However, Function.prototype.apply() expects the second parameter to be an array but instead gets either a string or number (depending on if you use capture groups or not). This would cause an invalid argument list error.
Solution 3
Luckily, we can simply substitute in Function.prototype.call() (which accepts any number of arguments, none of which have type restrictions) for Function.prototype.apply(). We have now arrived at working code!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Shedding bytes!
Nobody wants to type prototype a bunch of times. Instead we'll leverage the fact that we have objects that reference the same methods via inheritance. The String constructor, being a function, inherits from Function's prototype. This means that we can substitute in String.call for Function.prototype.call (actually we can use Date.call to save even more bytes but that's less semantic).
We can also leverage our variable 'a' since it's prototype includes a reference to String.prototype.toUpperCase we can swap that out with a.toUpperCase. It is the combination of the 3 solutions above and these byte saving measures that is how we get the code at the top of this post.
Why don't we just look up the definition?
If we write:
a.replace(/(f)/, x => x.toUpperCase())
we might as well just say:
a.replace('f','F')
Worse, I suspect nobody realises that their examples have been working only because they were capturing the whole regex with parentheses. If you look at the definition, the first parameter passed to the replacer function is actually the whole matched pattern and not the pattern you captured with parentheses:
function replacer(match, p1, p2, p3, offset, string)
If you want to use the arrow function notation:
a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()
Old post but it worth to extend #ChaosPandion answer for other use cases with more restricted RegEx. E.g. ensure the (f) or capturing group surround with a specific format /z(f)oo/:
> a="foobazfoobar"
'foobazfoobar'
> a.replace(/z(f)oo/, function($0,$1) {return $0.replace($1, $1.toUpperCase());})
'foobazFoobar'
// Improve the RegEx so `(f)` will only get replaced when it begins with a dot or new line, etc.
I just want to highlight the two parameters of function makes finding a specific format and replacing a capturing group within the format possible.
SOLUTION
a.replace(/(f)/,(m,g)=>g.toUpperCase())
for replace all grup occurrences use /(f)/g regexp. The problem in your code: String.prototype.toUpperCase.apply("$1") and "$1".toUpperCase() gives "$1" (try in console by yourself) - so it not change anything and in fact you call twice a.replace( /(f)/, "$1") (which also change nothing).
let a= "foobar";
let b= a.replace(/(f)/,(m,g)=>g.toUpperCase());
let c= a.replace(/(o)/g,(m,g)=>g.toUpperCase());
console.log("/(f)/ ", b);
console.log("/(o)/g", c);
Given a dictionary (object, in this case, a Map) of property, values, and using .bind() as described at answers
const regex = /([A-z0-9]+)/;
const dictionary = new Map([["hello", 123]]);
let str = "hello";
str = str.replace(regex, dictionary.get.bind(dictionary));
console.log(str);
Using a JavaScript plain object and with a function defined to get return matched property value of the object, or original string if no match is found
const regex = /([A-z0-9]+)/;
const dictionary = {
"hello": 123,
[Symbol("dictionary")](prop) {
return this[prop] || prop
}
};
let str = "hello";
str = str.replace(regex, dictionary[Object.getOwnPropertySymbols(dictionary)[0]].bind(dictionary));
console.log(str);
In the case of string conversion from CamelCase to bash_case (ie: for filenames), use a callback with ternary operator.
The captured group selected with a regexp () in the first (left) replace arg is sent to the second (right) arg that is a callback function.
x and y give the captured string (don't know why 2 times!) and index (the third one) gives the index of the beginning of the captured group in the reference string.
Therefor a ternary operator can be used not to place _ at first occurence.
let str = 'MyStringName';
str = str.replace(/([^a-z0-9])/g, (x,y,index) => {
return index != 0 ? '_' + x.toLowerCase() : x.toLowerCase();
});
console.log(str);

What does it mean when variable value in round brackets?

What does it mean when variable value in round brackets in js?
For example,
let a = (1,2,3);
What does it mean and why console.log(a) output is 3?
What is usage of comma operator in round brackets in variable initialization?
The parentheses are needed for grouping. In a let statement, commas are normally used to separate multiple variables that are being declared, e.g.
let a = 1, b = 2, c;
which is short for
let a = 1;
let b = 2;
let c;
If you write
let a = 1, 2, 3;
you'll get a syntax error, because after the comma it expects another variable declaration; it's equivalent to:
let a = 1;
let 2;
let 3;
The second and third declarations are clearly wrong, as 2 and 3 are not variable names.
The parentheses indicate that the whole expression 1, 2, 3 is being used to initialize one variable.
The expression 1, 2, 3 uses the Comma operator, which executes each of its subexpressions and returns the last one as its value. It's pretty useless when the subexpressions are all constants, so I assume your code was just a simplified example. Because the way it's written, it's really just equivalent to:
let a = 3;
What you have encountered is the comma operator.
Quoting the docs
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
Therefore in your case 1, 2 and 3 is evaluated and 3 is returned and thus assigned to the variable a.
This is not variable declaration-specific thing. You can write (1,2,3) anywhere in your JS code and it will always evaluate to 3. The thing is, JavaScript (like many other programming languages, e.g. C) has comma operator, which simply returns last element. The expression (1,2,3) basically looks just like (1+2+3) to JavaScript, except for comma operator is applied instead of addition.
It's call the comma operator:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
It's a very handy thing to use in JavaScript, because it allows you to run multiple statements as a single value for an arrow function.
Here is an example of a 10x10 identity matrix generated with one line of code. The last comma value is returned as the value.
const m = new Array(9).fill('000000000').map((v,i)=> (v=[...v],v[i]='1',v.join()));
console.log(m);
The same above code as a blocked function would take a lot more lines.
const m = new Array(9).fill('000000000').map((v,i)=> {
v = [...v];
v[i] = '1';
return v.join()
});
console.log(m);

Converting a loop into a recursive function

I wrote a function yesterday to count the number of "a" characters in a string. My teacher told me to refactor the code into a recursive function and I don't really know how to do so.
I would like some feedback on the subject, and by the way I'm an absolute beginner in JavaScript.
function numberOfA(n){
var numberA =0;
for (i=0; i<=n.length; i++){
if(n.charAt(i)== "a" ){
numberA++;}
}
return numberA;
}
to call the function following piece of code :
var n = prompt("type a word");
var output = numberOfA(n);
alert (output);
Thanks in advance !
The goal of recursion is to make a function which calls itself.
You might have mutual-recursion -- function A calls function B, calls function A... but that's certainly not needed here, and is better suited for when you know that you need to do two distinct things (one per function) and know that you need to do them in a leapfrog pattern.
Where recursion comes into play is when you're thinking about loops.
Normally, when you're doing things with loops, you might end up having two or three loops inside of one another.
Instead of worrying about managing loops, recursion is a way of thinking about what happens in a single-iteration of a loop, and writing ONLY the code needed to do that.
A really simple example of singular recursion might be to log all elements of an array to the console.
This is not a practical example -- it's a trivial example which has most of the pieces you need to make practical examples.
var array = [ "one", "two", "three", "four" ];
function listNextItem (array, index) {
var item = array[index];
if (!item) { return; }
console.log(item);
listNextItem(array, index + 1);
}
listNextItem(array, 0);
I've created a very simple function which looks like the inside of your innermost loop.
It sets an item variable, based on array[index].
If it doesn't exist, we're done, and we can return out of the function, so we don't try to go on forever (this is very important in recursion).
If it does exist, we log the item's value.
Then we call the exact same function, and pass it the exact-same array, but we pass it the value of index + 1.
Did this change anybody's life, or make loops obsolete?
Not really.
But it's the first step to getting recursion.
The next step is getting a return from recursion.
function recursiveAddOne (current, max) {
if (current === max) { return current; }
return 1 + recursiveAddOne(current + 1, max);
}
var total = recursiveAddOne(0, 3); // === 3 + 1 + 1 + 1
total; // 6
Normally in my return statement, I'd be sending the answer back to the variable in the outside world.
I'm still doing that, but here I'm adding a call to the same function, as part of my return.
What does that do?
Well, the outside function can't return a value until the inside function returns.
The inside function can't return a value until ITS inside function returns...
...and it goes all the way down until my termination-condition is met.
That condition returns a value to its outer function. That outer function returns that added value to ITS outer function... ...all the way up to where the outermost function gets handed the value of all of the other functions put together, and then returns THAT to the outside world.
It's like giving each Russian Matryoshka ("babushka") doll a piece of work.
You start with the biggest one, and go all the way inside to the tiniest one.
The tiniest one does its work first, and hands it back to the next one, which does its work and hands that back... ...all the way back until you're outside again.
Well, the basic concept of recursion is solving a problem with a smaller version of itself.
You have a function, numberOfA which gives you the length of a string(or maybe substring).
So let's say you have the string "javascript' the first string is at index 2.
It's logical to say that the number of as in your string is equal to 1 plus the number of as in the entire substring after the first a.
So what you do, is you add 1 to the number of as in the substring vascript
So here's some psudocode
function numA(str)
{
var substring = substr(index_of_first_a, str.length - index_of_first_a
return 1 + numA(substring);
}
function numberOfA(n, count){
if(!n.length) {
return count;
}
if(n.charAt(i)== "a") {
++count;
}
return numberOfA(n.substr(1), count);
}
var numberA = numberOfA('asdfafeaa', 0);
Try this:
function numberOfA(n) {
return n == "" ? 0 : (n.charAt(0) == "a" ? 1 : 0) + numberOfA(n.substring(1))
}
Here's how it works:
If n is the empty string, return 0 and finish the recursion. This is the base case of the recursion.
Else if the character at the first position in the string is an "a" add one, if not add zero and either way advance the recursion by removing the first character from the string. This is the recursive step of the recursion.
As you can see, every recursive solution must have at least a base case and a recursive step.
<!DOCTYPE html><html lang="en"><body><script>
var foo = function foo() {
console.log(arguments.callee); // logs foo()
// callee could be used to invoke recursively the foo function (e.g. arguments.callee())
}();
</script></body></html>
arguments.callee function will call the currently being executed method.

Categories