listToArray Eloquent JavaScript - javascript

The book says:
To run over a list (in listToArray and nth), a for loop specification like this can be used:
for (var node = list; node; node = node.rest) {}
Every iteration of the loop, node points to the current sublist, and the body can read its value property to get the current element. At the end of an iteration, node moves to the next sublist. When that is null, we have reached the end of the list and the loop is finished.
Question 1: Could you explain how the condition of the for loop works? I understand that it is checking whether the node(the current list) is null.. but how does the "node" argument by itself work?
Question 2: why doesnt the following code work?
function listToArray(list){
var result = [];
while(list.value != null){
result.push(list.value);
list = list.rest;
}
return result;
};
console.log(listToArray(list));

To understand how this works, you need to know two things:
How java script For loop works.
What are truthy values.
The syntax for the for loop statement:
for ([initialization]; [condition]; [final-expression]) statement
[condition] An expression to be evaluated before each loop iteration.
If this expression evaluates to true, statement is executed. If the
expression evaluates to false, execution skips to the first expression
following the for construct.
In Java script, a truthy value evaluates to true when evaluated in a Boolean context.
All values are truthy unless they are defined as falsy (i.e., except
for false, 0, "", null, undefined, and NaN).
So till node is null at one point, we may say that node is truthy and evaluates to true.
When the statement, node = node.rest assigns a null value to node, there the for loop exits.
The below code does not work because, list.value may be undefined, or as a fact any other falsy value other than null.
function listToArray(list){
var result = [];
while(list.value != null){
result.push(list.value);
list = list.rest;
}
return result;
};
console.log(listToArray(list));
instead try, while(list.value).

...but how does the "node" argument by itself work?
node is a variable. A variable is resolved to its value. E.g. if I have
var foo = 3;
alert(foo + 1);
it will resolve foo to the value 3 and then add 1 to it. Similarly in this case, node is resolved to whatever value it has, that value is converted to a Boolean value (i.e. Boolean(node)) and then tested whether it is true or false.
If the value of node is null, then Boolean(node) will return false.
why doesnt the following code work?
Can't really tell without knowing what list is and what exactly "does not work".
But presumably, list.rest is null at some point, in which case you would try to access null.value which throws an error. The equivalent version to the for loop would be to compare list itself:
while (list != null)

A simpler way is to use:
var result = Array.prototype.slice.call(list);
this will turn the list into an array

function listToArray(listValue){
var arrayResult = [];
while(listValue.list){
arrayResult.push(listValue.value);
listValue = listValue.list;
}
arrayResult.push(listValue.value);
return arrayResult;
}

Related

for loop syntax

Someone can explain me this part of code please.
function parent (elem, selector ) {
for ( ; elem && elem !== document; elem = elem.parentNode ) {
if ( elem.matches( selector ) ) return elem;
}
}
I understand what he does, but I don't understand the start of loop exactly this part : for ( ; elem && elem !== document; ...
Usually we have to specify a starting number for the iteration, it's very strange for me this loop.
Thanks for your help.
While the first part of the loop configuration is for setting up an index, the second part is where the looping condition goes. If the condition is not based on the index, then the index can be omitted. In this case, the loop cares about the passed argument elem, not an index.
In fact, all 3 configuration sections of a for are optional (making the for more like a while). From MDN:
Syntax
for ([initialization]; [condition]; [final-expression])
statement
(As you may be aware, the use of [] in an argument list being show for syntax purposes means optional.)
Here's an example:
var obj = {}; // Not null
// Keep looping as long as obj is not null (which it isn't to start)
for ( ; obj != null; obj=null) {
console.log("Loop!"); // First time through the loop, obj != null so loop will go
} // After first iteration, obj will become null (because of 3rd part of loop config)
// so loop will terminate
Having said that, this is certainly not an elegant way to use JS for syntax. The logic could be handled in a more readable way with a while loop:
function parent (elem, selector ) {
while (elem && elem !== document){
if (elem.matches( selector )) {
return elem;
}
elem = elem.parentNode;
}
}
There's nothing that specifies a for loop must use an iterator. The for loop syntax was invented because it is very common to iterate over a range of numbers, and doing that with a while loop always looks something like this:
var counter = 0;
while (counter < 10) {
// do something...
counter++;
}
Because it was so common to see a variable used as an iterator, then an expression to be checked in a while loop, and an increment operation at the end of the while loop body, some clever programmers created the for loop syntax so that these parts could all be stated upfront in a concise manner: for ([initialization]; [condition]; [final-expression]). Note well that any of these parts can actually be omitted - only the semi-colons are actually required inside the parenthesis.
The author of this code doesn't need an iterator, however, perhaps he or she just likes that all of the necessary pieces are on a single line. You could just as easily write this function with a while loop that would look like this:
function parent(elem, selector) {
while (elem && elem !== document) {
if (elem.matches(selector)) {
return elem;
}
elem = elem.parentNode;
}
}
You may refer to this. The structure of a for-loop consists of three statements, all of which are optional. The first statement executes before the loop starts, so typically, it is used for variable declaration. The second statement is used to define conditions. The third statement Is called upon each loop, hence it is typically used to increment or decrement values, or assign new values.
When all of these statements are not there as below, it means that it is an infinite loop.
for (;;)
When the first statement is not there, which is the case in your example, then there was need to declare variables or have a code block to execute before the for loop starts. However, there is still condition that must be satisfied in order to keep the loops going (statement 2), and block that is called upon each loop (statement 3).
Statement 1: None // If there was any, it would have been called at the beginning
Statement 2: elem && elem !== document // Decides whether to continue looping
Statement 3: elem = elem.parentNode // Called each loop

How does this unique() function work

As I was looking at a unique() function I found
which takes an array as argument and returns a new array which contains the unique elements of this array (which means no duplicated items). However I cannot understand the logic of this function. Can somebody explain it to me?
Here is the function:
function unique ( array ) {
return array.filter(function(a){
return !this[a] ? this[a] = true : false;
}, {});
}
I can't really understand the whole code especially the !this[a] ? this[a] = true : false; and the new object ({}) that is passed as the second argument to filter.
Let's start with the filter:
The filter() method creates a new array with all elements that pass
the test implemented by the provided function.
The a is the random number of the array to which you apply the filter. The whole essence is in the following statement:
return !this[a] ? this[a] = true : false;
If the this[a] is true, a has been already processed once and it has been added to this as one of its properties. Otherwise, this[a] is false. So taking its negation result in true and the current a should be returned. Furthermore this[a] would be set to true and then we proceed to the next a.
The following snippet will help you grasp what filter does:
var numbers = [1,2,3,4,5];
var filteredNumbers = numbers.filter(function(number){
console.log(number);
return number > 2;
});
console.log(filteredNumbers);
And the following snippet will show you in action what happens in unique function:
function unique ( array ) {
return array.filter(function(a){
console.log(this);
return !this[a] ? this[a] = true : false;
}, {});
}
var array = [1,2,3,1,2,3,4,5,5,6];
console.log(unique(array));
I understand the basic logic of filter but what i dont is the {}
passed as a 2nd argument and how each value is added to a new array
with !this[a]
The second argument is an optional value that you can pass to the filter method and it can be used as the this, when your callback would be executed (check the link I mentioned at the beginning about filter). You pass there an empty object. When you use the keyword this inside your callback, your refer this object. This is why the first time that code gets in this method returns {}. Check the first line of the output of the second snippet.
I will explain the second part of your question based on the second snippet. The first time you get in you have an empty object (I refer to this) and the first number processed is 1. So this1 would be undefined. So !this[1] would be true. Hence the first part after the ? is executed which is an assignment
this[1] = true.
Now this acquired its first key, 1, with value true. Furthermore, 1 would be returned from filter. The same happens with 2 and 3. When we arrive at 1 the
!this[1]
is false, since this[1] is true. So false is returned and the 1 now would not be added to the array that would be returned after all elements of array have been processed.
Basically, .filter would call the callBack function by supplying the individual values of the iterating array. If the callBack returns a value that resolves to true then that value will be collected, else that particular value will be ignored.
Here the second argument of filter has been used. That second argument will be used as a context(this) while calling the callBack internally. So here in your code, the passed object will be added with the array's value as property for each iteration. And in the consecutive iterations, the code will check the current value is available as a property in the initially passed object. If available then that ternary operator would return false, otherwise true.
Hence the unique values will be returned from the filter function.
Array.filter will only grab elements of the array when the function passed return truthy.
For each element of the array it is doing
return !this[a] // if value is not yet on this
? this[a] = true // add value to this and return true (grab element)
: false; // value was already cached, so return false (don't grab)
So it will only return 1 of each
Other answers have explained basically how this works. But a couple of points:
First, instead of return !this[a] ? this[a] = true : false;, it would be more concise to write
!this[a] && (this[a] = true)
Second, this code has the flaw that it only works on elements which can serve as keys into an object--basically strings or numbers. That is why using Set is better:
Array.from(new Set(array))
The above will work on any primitive or object.
Third, this approach does not work properly with strings and numbers. If the number 1 is present, it will filter out the string "1".
const uniq = a => a.filter(x => !this[x] && (this[x] = true), {});
console.log(uniq([1, '1']));
The reason is that object keys are string-valued.
Finally, IMHO this code is a bit too tricky for its own good. Most developers, even experienced ones, would stop and scratch their heads for a minute before figuring it out. Less experienced developers would have to consult the documentation for the thisArg parameter to Array#filter before being able to understand it. The ternary operator with the assignment inside is also a bit cryptic. I'd go ahead and write it out as
if (this[x]) return false;
this[x] = true;
return true;

how does this if statement works and means? (Javascript)

This function counts number of all characters of a string into a string. I am not fully understanding the if statement here and how it works.
function getFrequency(string) {
var freq = {};
for (var i=0; i<string.length;i++) {
var character = string[i];
if (freq[character]) {
freq[character]++;
} else {
freq[character] = 1;
}
}
return freq;
};
I thought freq[character] is the property of the object such as A B how does it work with if(freq[character]) also how does the increment of freq[character]++ works?
I have made test like this to try and understand it.
var v = {};
v.h = 3;
v["h"]++;
v["h"] = v["h"] + 1;
v.h++;
v.h = v.h + 2;
console.log(v);
console.log(v["h"]);
I think I can guess the if statement works that if the property exists but I thought JS has an object property calls .hasOwnProperty shouldn't this be used instead?
As for the increments, to my test, it works but I just don't get the reason.
Can someone give me a hand to elaborate this?
Thanks in advance
In javascript, objects are associative arrays. And vice versa. There is no difference between the two concepts.
So defining this variable as an empty object:
var freq = {};
... is actually creating an associative array (like a dictionary or map) with no keys added yet.
Moving on, let's take an input string like eek. The code here will look at the first letter and treat freq[character] the same as freq['e'], which is the same as freq.e.
In this code, the initial value of any letter in the freq object is undefined. So that initial if() check for the first "e" in our string actually looks like this:
if(undefined)
Javascript has the concept of "truthy" and "falsy" values; anything in javascript can be evaluated as a boolean, and (in most cases) a sensible result is achieved. Looking at undefined, Javascript will simply treat this a falsy value, fall to the else block, and therefore execute this code:
freq[character] = 1;
As already established, this is the same thing as freq.e = 1;
Now when the loop continues to the next letter (also an "e"), javascript will end up evaluating the expression if (1). Javascript treats this and all other non-zero numbers as "truthy", so this time will execute the following line:
freq[character]++;
Again, that's the same as freq.e++, where freq.e had a value of "1" that can now be incremented to "2".
One more time through the loop for the final letter "k". This time we get freq.k, which is still undefined. Undefined is falsy, so control falls to the else block, and freq.k is set to "1".
Now you can see how we can start to increment letters in the array as you find them in the string, even though it appears that you never defined an array in the first place, never set any values to anything other than "undefined", and never had a real boolean value to check against.
if (freq[character]) checks if the value is "truthy". That is, it's not false, null, undefined or 0. The first time we encounter any character the value will be undefined, since the object literal is created empty, so the "truthy" check will fail and control will fall to the else block.
So when we first see a specific letter set the value to 1 (which is now "truthy").
Any subsequent encounters of that letter just increment the value, which would be equivalent to say freq[character] = freq[character] + 1;. The increment syntax is just a shorthand.
if (freq[character]) checks if the object freq has a property on it with the value of character as the name. The result of this expression evaluates to true or false.
It can be more explicitly stated, as the following non-exhaustively illustrates:
if (freq[character] == null)
or
if (typeof freq[character] === 'undefined')
The danger in not being explicit when evaluating if an object is undefined or null, is if it is actually set to a different type that evaluates to true or false (0, 1, '0', true, false).

What's this JavaScript syntax?

I am new to JavaScript. The following code is from some production codebase.
The regDefinition is passed in JSON form. But I am not quite sure about the syntax in the method body.
Especially the || and [] parts.
function getCookieValue(regDefinition) {
return (document.cookie.match(regDefiniation.regEx) || [])[regDefiniation.index] || null;
}
It looks like someone has made a lot of effort to make this very hard to read.
If I interpret it right, it does something like this:
call the match method.
it returns an array of matches, or nothing (null, undefined?). If it doesn't return anything, default to an empty array.
Of the array, get the element with index 'regDefiniation.index'.
If that item doesn't exist (which can be the case for matches, and will always be the case for the empty default array), return null.
There are some good answers here, but nobody seems to really be explaining why you'd do
(foo || [])[bar]; // or similarly (foo || {})[bar]
instead of just
foo[bar]
Consider case the RegExp failed,
var foo = null, bar = 0;
Now without anything special you'd get an error thrown and the code would stop
foo[bar]; // TypeError: Cannot read property '0' of null
However the parenthesised-or version will be different
(foo || [])[bar]; // undefined (note, no error)
This is because the result of (null || []) is [], and you can now try to read a property of it safely
document.cookie is a string that contains the cookies associated with the current page. The document.cookie.match(regDefiniation.regEx) function call is searching this string with a regular expression to get a list of substrings that match.
If nothing in the cookie string matches the regex, the match call will return null, so the || [] is there to replace that null with an empty array. This ensures that the expression (document.cookie.match(regDefiniation.regEx) || []) always returns an array.
The [regDefiniation.index] is just retrieving an element from that array. But if the requested index doesn't exist in the array — for example, if the array is empty because the regex didn't match anything in the cookie string — the result will be undefined, so the || null changes the result to null in that case.
So to understand this let's dig into this example
var myValue = someValue || otherValue
So here if someValue can be converted into true then myValue would contain someValue else it would contain otherValue
// Values that evaluate to false:
false
"" // An empty string.
NaN // JavaScript's "not-a-number" variable.
null
undefined // Be careful -- undefined can be redefined!
0 // The number zero.
Anything else would return true
So to understand your code let's break it
var myCookie = document.cookie.match(regDefiniation.regEx) || []
So here if document.cookie.match(regDefiniation.regEx) returns true then return it else return the empty array.
Same for other part too. For more information of logical operators in JavaScript please follow the following link
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
Here's the step-by-step:
document.cookie returns a string and match method (inbuilt) is applied to that. If the parameter is in regDefiniation.regEx found, then do this else return [] (i.e., array)
After this, whatever is returned by above step, apply indexing to that with [regDefiniation.index].
`If all the above steps fail, then return null.

"var variable" returns undefined?

When I run "var variable = true;" in chrome console I get "undefined" returned:
> var variable = true;
undefined
But when I run without "var" it returns true:
> variable = true;
true
Why is it returning "undefined" with "var"?
It's confusing cause I expected it would return true.
The first is a statement, while the second is an expression. While not quite the same, it is similar to C's rules:
// A statement that has no value.
int x = 5;
// An expression...
x = 10;
// ...that can be passed around.
printf("%d\n", x = 15);
var x = y; is a statement which returns no value. In the WebKit JS console, a statement that returns no value will show undefined as the result, e.g.
> if(1){}
undefined
> ;
undefined
> if(1){4} // this statement returns values!
4
The assignment is an expression which returns the value of the LHS. That means, this expression statement has a return value, and this will be shown.
An assignation returns the assignation's value, but with var this return is "consumed" (?)
Statements always return undefined.
var color = "red";
undefined
Expressions always return a value.
color = "orange";
"orange"
I'd like to point out, that the answer provided by kennytm should be the accepted answer, at least for pedagogical purposes. The accepted answer doesn't answer why this is the case or provide deeper understanding.
Like the null value in JavaScript, undefined indicates absence of value, but in a much deeper way. The following should be taken as complimentary to the above-mentioned answers:
undefined is the value of variables that haven't been initialized and the
value you get when you query the value of an object property or
array element that doesn't exist. This value is also returned by
functions that have no return value, and the value of function
parameters for which no argument is supplied. undefined is a predefined
global variable (not a language keyword like null) that is initialized
to the undefined value.
You might consider undefined to represent a system-level, unexpected,
or error-like absence of value and null to represent program-level,
normal, or expected absence of value.
-- Flanagan, David. JavaScript: The Definitive Guide: Activate Your Web
Pages (Definitive Guides) . O'Reilly Media. Kindle Edition.
Also, makes sure to check out both the accepted and the second most voted answer for further reference:
Chrome/Firefox console.log always appends a line saying undefined

Categories

Resources