I am relatively new to Javascript and am working through ch. 5 of Eloquent Javascript. I came across some code that I don't quite understand. I know HOW it works (the general method and steps), but I don't understand WHY it works.
The code is here:
function filter(array, test) {
var passed = [];
for (var i = 0; i < array.length; i++) {
if (test(array[i]))
passed.push(array[i]);
}
return passed;
}
Basically the function takes the element the 'for loop is iterating over' from the array, and compares it to the test parameter.
I am wondering how/why this works:
if (test(array[i]))
There is no || && or other 'comparison operators'. How does it compare values with only using parenthesis?
How is test compared to the array[i] value with no operators?
Link to file: http://eloquentjavascript.net/05_higher_order.html
go to 'Filtering an Array' exercise
Thanks!
Whatever is inside the parentheses of an if statement will be evaluated. If the result is falsy (false, 0, "", NaN, null, undefined) it fails and if the result is truthy (everything else) it passes. So if your if statement contains a function call if (test(something)) {}, then the if statement just says if the result of the function call is truthy then pass.
Also, && and || are not comparison operators, they are boolean operators. They just connect the result of two statements, like true || false which evaluates to true.
I am not quite sure, but I think this is a custom function. Most likely there is some comparison there and the result of the function is True/False. If you give us the whole code we could explain it better to you.
This code is accepting a test parameter that is what is called a "predicate function" i.e. a function that given an element will return true or false.
It's going to be used for example with
var big_numbers = filter(numbers, function(x){ return x > 100; });
i.e. the expected parameter test is actually code.
In Javascript passing code is very common and idiomatic. It's something that is more annoying in other languages that don't support the concept of "closure" and of "nested function", forcing all code to live at the top level, being given a name and to have no context (e.g. the C language).
'test' here is a function, not a value. In Javascript, each function is an object and can be passed as parameter. In this case, test is a function that take one parameter and return true or false base on the parameter value.
So in the for loop, test function is called with each array element and if the result is true, it will be store in another array. Eventually, passed elements would be return to the function caller.
Related
I have a json data with specific key as below:
var object = {"85":{"id":"50","nosurat":"2020-PKL-001","user_created":"02211"},"69":{"id":"50","nosurat":"2020-PKL-002","user_created":"02212"},"104":{"id":"50","nosurat":"2020-PKL-003","user_created":"02213"}};
So, in order to iterate it, I use for method.
The problem is how to make filters inside the for method, but only execute it once?
for(var keys in object){
if(object[keys].nosurat == "2020-PKL-001"){
functionx();
}
}
In the above code, the functionx() executed 3 times, because once it's true, it will loop through as many key as my object has. How to make functionx() only executed once in a while, only when the condition is met, assuming that there will be another key that met the condition.
or you could use Array.prototype.some():
var obj = {"85":{"id":"50","nosurat":"2020-PKL-002","user_created":"02211"},"69":{"id":"50","nosurat":"2020-PKL-001","user_created":"02212"},"104":{"id":"50","nosurat":"2020-PKL-001","user_created":"02213"}};
function functionx(o){console.log(o)}
console.log('=== correct behaviour ========================');
Object.values(obj).some(o=>o.nosurat=="2020-PKL-001" && functionx(o) || true);
console.log('=== alternative correct version ==============');
Object.values(obj).some(o=>o.nosurat=="2020-PKL-001" && (functionx(o),true) );
console.log('===== WRONG behaviour (previous version ======');
Object.values(obj).some(o=>o.nosurat=="2020-PKL-001" && functionx(o));
.as-console-wrapper {max-height:100% !important}
Edit:
Oooops, I just corrected a tiny detail: I forgot to mention that in my original solution functionx(o) needed to return some "truthy" value, otherwise multiple calls would still have happened in some()!
I changed the relevant part of the code now to (functionx(o) || true). This will make sure that some() will definitely stop after the first functionx() call (regardless of whatever functionx might return).
One further remark on the && within the function of the .some() loop: the evaluation of boolean expressions follows strict "lazy" rules in JavaScript (as in almost every other language): terms are evaluated from left to right only as far as necessary to get the result of the whole expression. So if the term before the && evaluates as false the overall result of the expression is determined and nothing after the && could change it anymore. Therefore functionx will not be called in these situations and false will be returned to the calling .some() loop.
for(var keys in object){
if(object[keys].nosurat == "2020-PKL-001"){
functionx();
break
}
}
* EDITED *
REF: Calling a JavaScript function that returns a Boolean [on hold]
function booleanFunction()
{
if (something) return true;
else return false;
}
My original question was "When calling a Boolean Function, is it correct to say?":
if (booleanFunction)
or
if (booleanFunction())
I had previously read that the first choice was correct. Your voluminous responses said otherwise.
Based on all that I have learned from all your responses, I conclude:
(1) if (booleanFunction) is truthy in the sense that this if statement will ALWAYS return true. In other words, this if statement is equivalent to asking if this booleanFunction EXISTS, independent of its correctness.
(2) to evaluate the value (true or false) returned by the booleanFunction, I need to say if (booleanFunction()).
Have I concluded correctly?
The text you quote is outright incorrect.
To call a function, use parentheses. If the function takes no arguments, the call looks like booleanFunction() and returns a value.
To evaluate a value, put it into parentheses. In an if-statement, while-loop, a value is converted to a boolean automatically, the same as (new Boolean( SOME_VALUE )).valueOf() or !! (SOME_VALUE). Refer to MDN for the full conversion rules. For instance,
if (booleanFunction()) {
is perfectly fine, but
if (booleanFunction) {
would convert the value of booleanFunction to boolean, and that is true, because any function object will be converted to true.
I have edited my original question. Hopefully, it is now totally clear.
In the book 'Functional javascript' by Michael Fogus, I faced with one expression that I still can't undrestand.
Here is the function:
function defaults(d){
return function(o, k){
var val = fnull(_.identity, d[k]);
return o && val(o[k]);
}
}
where
function fnull(fun /*, defaults*/){
var defaults = _.rest(arguments);
return function(/* args */){
var args = _.map(arguments, function(e, i){
return existy(e)?e : defaults[i];
});
return fun.apply(null, args);
};
};
function existy(x){return x != null}
(underscore is the object of Underscore.js library)
and the example of use:
function doSomething(config){
var lookup = defaults({critical:108});
return lookup(config, 'critical');
}
doSomething({critical: 9});
//=> 9
doSomething({});
//=> 108
I've recreated exapmle in node.js and it works fine, but I wonder why is the logical 'and' in the return line of 'default' function?
return o && val(o[k]);
What is the point of doing that? I checked the exapmle with
return val(o[k]);
and it also worked well.
It's hard to believe that this is just a mistake...
The logical and will make sure the second part is only evaluated if the first part is true. If o does not evaluate to true, the expression returns false. Otherwise, it returns val(o[k]).
This is used as a quick check to see if o is not false / null / undefined.
return o && val(o[k])
mean that if "o" is TRUE it will return "val(o[k])"
given "expr1 && expr2":
Returns expr1 if it can be converted to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false.
That is smart usage of something called short "short-circuiting" in logical expressions.
As logical expressions are evaluated left to right, they are tested
for possible "short-circuit" evaluation using the following rules:
false && (anything) is short-circuit evaluated to false.
true ||(anything) is short-circuit evaluated to true.
The rules of logic guarantee that these evaluations are always correct. Note that the (anything) part of the above expressions is not evaluated (meaning not ran at all), so any side effects of doing so do not take effect. There are also benefits to it.
Usage:
Make your expressions evaluate faster by putting something easily calculable or likely to be true/fail at leftmost position in expression.
For example parOfExpressionLikelyToBeTrue && (rest of expression) will in most cases not even calculate the other part of expression. Same goes for parOfExpressionLikelyToBeTrue || (rest of espression).
Same can be used if something is very time consuming to calculate, you push it as far back to the right in expression. For example (rest of the expression) && ThisCostsALotOfTime or (rest of the expression) || ThisCostsALotOfTime. Here when first parts of expression short-circuit you save time on your time consuming part.
Short circuit existence evaluation. Lets say you need to check if your object's property pr is 3? What would you do? obj.pr === 3? Yes and no. What if property is missing? It's fine you will get undefined and that is not === 3. But what if object is not there. You will get trying to read pr of undefined error. You can use short-circuit logic here to you benefit by being defensive and writing the expression as if (obj || obj.pr === 3). This ensures there are no errors, only true and false.
Short circuit initialization. Let's say you wanna say variable a is b. But b might be undefined. And you wanna your variable to have a default. You could write a=b and then check if a is undefined and set it to default or you can be clever and write it as a = b || 3. This way a is b or if be is undefined it's 3. Ofc, you can use this for late initialization as well a = a || 3.
Making sure object for function exists before trying to run function. Same as before mentioned with properties you might wanna test if object containing the function exists before running the function. Let's say you got object obj and function fn as it's property. You might call that function like obj.fn(). It's fine, but if obj is undefined you will get an error. Being defensive you might wanna write: obj && obj.fn().
Running the function only if there is one. Since functions in JS can be passed to other functions you can not be sure at run time it's there. Being defensive you might wanna run your function as (typeof passedFunction === "function" && passedFunction() instead just passedFunction() which my produce an error.
other smart things like guardian expressions etc which are complicated and too many to for me to remember all and you should avoid them anyway for better code readability.
This question already has answers here:
Javascript: || instead of IF statement - is this legal and cross browser valid?
(10 answers)
Closed 6 years ago.
So I'm reading Airbnb's JS styleguide and I don't understand what the OR operator is doing in the following example. More specifically in the Jedy constructor options || (options = {}); Is basically creating an empty object if no arguments were passed to the constructor? Therefore, the name property of the Jedi constructor would be set to 'no name'?
function Jedi(options) {
options || (options = {});
this.name = options.name || 'no name';
}
Jedi.prototype.getName = function getName() {
return this.name;
};
Jedi.prototype.toString = function toString() {
return 'Jedi - ' + this.getName();
};
PS. It seems like there are a lot shorthand ways of doing things with JS. Are there any good resources or articles explaining what these are and when it's best to use them?
The || operator takes two arguments. If the first argument is a "truthy" value, it returns the first argument; otherwise, it returns the second. It also short-circuits; that is, if the first argument is truthy it does not evaluate the second. If the second argument is an expression with side effects, this can be very significant.
The statement options || (options = {}); relies on this. If options is truthy, then the assignment expression will not be evaluated. If it is falsy, then the second expression will be evaluated.
Now, this is functional equivalent to the statement options = options || {};. In theory, that statement could be slightly slower, because it will assign options to itself rather than simply not assigning anything. However, the effect of this is negligible.
Js logical operators return not true or false, but truly or falsy value itself. For example in expression x && y, if x is falsy, then it will be returned, otherwise y will be returned. So the truth table for operator is correct.
The same for ||. It's a good way for specifying function default values.
You will often find this code in JavaScript plugins it basically means if an object with name options does not exists create a new one
If you try to access a property on options like
options.name and options does not exists then it will give you an error that options is undefined.But with this options || (options = {}) code you can always ensure that the JavaScript Object you are accessing always exists.
I will check if I could provide you some links for this to read about.
This is a good supporting link
How can I create an empty namespace object without overwriting another object with the same name?
seems like this is a more concise way of checking that the object exists and assigning it the value of an empty object if it does not. It isn't all that clear though. A little clearer implementation would be
var options = options || {};
even better, use es2015 default parameters
function Jedi(options = {}) {
this.name = options.name || 'no name';
}
In many (most) programming languages, at runtime unnecessary executions are optimized away. ||binary operator returns true if either of its operands evaluate to true. Since both the operands are serially evaluated, if the first one evaluates to true, the outcome of || operator is going to be true. so the second operand need not be evaluated. If the first one returns false, then second one decides what the result of || operator is going to be. this is the behavior that is being exploited here.
if options is set to non null value, it will evaluate to true. So don't execute the second operand which initializes it to empty object. on the next line if options.name is not null, then initialize it to 'no name'
I wrote a simple function to sort objects not expecting it to work but it does:
function sortObjs(objArr,field) {
objArr.sort(
function(a,b) {
if( isNaN(a[field]) ) {
return a[field].localeCompare(b[field]);
} else {
return parseFloat(a[field]) - parseFloat(b[field])
}
}
);
return objArr;
}
When I call this function I get my sorted objects without issue. But I was not expecting it to work because I thought the first two return statements would exit the function before it got to the last statement: return objArr.
You have a nested function. The first two returns will exit the inner function, while the last one will exit the outer one.
EDIT:
You can think of function returns as "replacing" the function with the returned value. For example:
var i = getSum(1, 3);
function getSum(a, b) {
return a + b;
}
The function getSum returns the sum of a and b. The line var i = getSum(1, 3) will execute the lines of code contained in the function with a = 1 and b = 3. The value that is returned "replaces" the function call. So now the line of code looks like var i = 4;. Although this is not exactly how it works, it's a good way to conceptualize it. This is a special case because you aren't actually running the inner method here, you're passing it as a variable.
Let me know if you have any more questions!
To understand why the inner function's return statements would not have an effect on the return statement in the outer scope, you need to understand how the Array.prototype.sort() function works.
The function arr.sort([compareFunction]), takes a function as a parameter.
compareFunction
Optional. Specifies a function that defines the sort order.
If omitted, the array is sorted according to each character's Unicode code point value,
according to the string conversion of each element.
The logic you write inside the compareFunction gets executed when
the java script engine tries to compare two elements during its
comparison operation.
Hence for each comparison that it makes, the function would return a
value, based on which the elements would be ordered.
This implies that the compareFunction that we pass on as a parameter
would be used to just obtain a value based on which two elements can
be compared and not exit the sort operation, leave alone exiting the
outer function.
Having said this, the code return objArr;, takes no effect, since the array would be sorted in place.