often time I missed one or two checking thus it break the entire app. I really feel this is a pain in writing in js because one simple mistake can ruin entire app.
Take this code
{this.state.floor && this.state.floor[this.state.selectedTab].units.length === 0 && <div>render something</div>}
it will have error if units is undefined. How to I check? the first check this.state.floor doesn't seem to work. Should I check if this.state.floor.length > 1?
If the return of data has nested or multiple nested properties, my jsx will be so complicated sometime.
you can do it with lodash get function like this :
const r = {a:{b:{name:'foo'}}};
const existence = !!_.get(r, 'a.b.name');// !! Convert to the returned value to boolean
console.log(existence); // true
has you can see the _.get secound parameter can be property path like 'a.b.name'
in your case i would do:
!!_.get(this.state, `floor[${this.state.selectedTab}].units.length`);
If the logic to determine whether I should render something or not gets complicated, I will usually extract it to a function rather than leaving it all in the main render's jsx.
renderSomething() {
const { floor, selectedTab } = this.state
if (floor && floor[selectedTab] && floor[selectedTab].units && floor[selectedTab].units.length === 0) {
return <div>render something</div>
}
return null
}
render() {
return (
<div>
{renderSomething()}
{renderSomethingElse()}
</div>
)
}
If you can't assume anything about your state, the above check ought to be safe. Usually, you may be able to assume some things about your state if you are the one controlling the data that would make some of the checks unnecessary. For instance, you may know that it is the case that every value in the floor object always has a units property. Thus, the floor[selectedTab].units would not be required. The extra check obviously doesn't hurt anything, but it can clutter code to always add what would often be redundant checks.
If you're feeling pain keeping track of what values may be undefined and do need extra safety checks, I'd definitely recommend using flow or typescript. Let the computer do a lot of that bookkeeping.
use this function for arrays or nested array (but not for strings)
arr={nested:{nested2:{val:'isset'}}}
if(t=isset(arr,'nested=>nested2=>val')){
alert(t)
}
function isset(obj,nested) {
var dub=obj
var isset=false
if(typeof(obj)!="undefined" && typeof(nested)!="undefined"){
var arr=nested.split('=>');
for(var k in arr){
var key=arr[k];
if(typeof(dub[key])=="undefined"){
isset=false;
break;
}
dub=dub[key];
isset=dub
}
}
return isset;
}
Related
What would be the best approach to check if all the elements of a given array are contained by another array? For example:
match(['countryaarea', 'countrybarea'], ['countrya', 'countryb']) // true
I have tried indexOf() and includes(), but it does not work.
You can use every and some methods.
const arr = ['countryaarea', 'countrybarea'];
function match(array, searchArray) {
if (array.length !== searchArray.length) {
return false;
}
return array.every(el => searchArray.some(sEl => el.includes(sEl)));
}
console.log(match(arr, ['countrya', 'countryb'])); // returns true
console.log(match(arr, ['countrya'])) // returns false
console.log(match(arr, ['abcd'])) // returns false
console.log(match(arr, [])) // returns false
You would also want to check for null values.
... best approach...
The 'best approach' is robust code that handles edge cases. But the OP is insufficient to know what the edge cases are. That's addressed below but first, the code.
function isSubset ( subset, reference ) {
if ( !Array.isArray( subset ) || !Array.isArray( reference )) return false;
return subset.every( element => reference.includes( element ));
}
The 'best approach' for coding:
generally almost never involves for loops. Less readable and more error prone than Iterator functions. And as seen in the other answers, for loops put artificial constraints on the problem.
Code composition using functions is in keeping with Javascript language design, functional programming paradigm, OO principles, and clean code in general.
The 'best approach' depends on desired functionality:
Must the arrays be the same length? All answers (as of this writing) assumes that.
Must the test-array be shorter and/or equal length of the reference array?
Can either or both arrays have duplicate items?
Is this throw-away code ?
Is this destined for a library or at least production code?
What if there are mixed types in either or both arrays?
If this is simply "git er done", isolated use then verbose-but-understood code is OK and non-robust parameter checking is OK.
My assumptions
Return false for failed parameter checks, don't just blow up.
Both things must be arrays.
No constraints on array length.
Duplicate elements in either array do not need item-for-item duplication in the other.
An empty array is a subset of any other array including another empty array.
String compare is case sensitive.
I did not want to get wrapped around the axle with using "truthiness" for parameter validation so I left that sleeping demon alone.
var arraysMatch = function (arr1, arr2) {
// Check if the arrays are the same length
if (arr1.length !== arr2.length) return false;
// Check if all items exist and are in the same order
for (var i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
// Otherwise, return true
return true;
};
Say I want to have an if statement to test if an array is empty or not,
Looking it up I have found no way to check besides array[0], which in frameworks like React and Angular give errors on the array's item not existing.
let arr = [];
if (!arr[0]) {
arr.map(val=>{
return <div>{val.name}</div>
});
}
In this example I want it to Display the JSX and if not, do not display any JSX. But doing this throws an error. Is there anyway to do this? preferably without any outside libraries.
edit: "added 'this' after 'to do'"
This checks whether the variable is defined and whether it contains anything (although in this case you'd probably not need the first check):
if ( arr && arr.length )
Also, don't forget to return arr.map(...
If you're not even certain your variable even is an array, this is what I would do:
if (Array.isArray(arr) && arr.length) { /*...*/ }
For your special case you probably don't even need the 2nd check, though, because all of the Array iterators don't run even once if the Array they are called on is empty.
Example:
const arr = [];
console.log(arr.map(Number));
console.log(arr.some(parseInt));
console.log(arr.every(parseInt));
console.log(arr.filter(Number));
None of the methods will throw an error provide arr is an array.
this.breakintoletters=()=>
this.lengthi!==0?(this.title2=this.title,this.title2.split(),this.title2.
map((x)=>this.arol.push(new letter(x))))
:!!false
So basically this is the code. It's supposed to break the string into letters and then push pertinent objects into an array..
Checks for the length of the string, if not 0 proceeds, returns an errors where MAP function is at...) TypeError telling me it's not a function. Editor is not showing errors. Would appreciate help
I suggest to use a different approach by checking this.lengthi in advance and return either false, or later the mapped length of the pushed values.
this.breakintoletters = () => {
if (!this.lengthi) return false;
this.title2 = this.title;
// this.title2.split(); the result is not taken, not even splitted
return this.title2.map(x => this.arol.push(new letter(x)));
};
You're not assigning splited value back to this.title2 and than using map on this.split2 which is a string
this.breakintoletters=()=>
this.lengthi ? (this.title2=this.title,
this.title2=this.title2.split(),
this.title2.map((x)=>this.arol.push(new letter(x))))
:false
IMO you should try to make your code consice only upto a point where it stays readabale you can simply it in following manner
this.breakintoletters = ( ) => {
if(this.lengthi === 0 ) return false;
this.title2=this.title;
this.title2=this.title2.split();
return this.title2.map((x) => this.arol.push(new letter(x))))
}
(this.title2=this.title, this.title2.split(), this.title2.
map((x)=>this.arol.push(new letter(x))))
Is this.arol the name of an array?
Try restructuring it to be:
(this.title.split().map((x) => this.arol.push(new letter(x)))
Methods like split() join() map() etc can be chained together.
I would rethink using the map function here though and the ternary which other commenters covered above. I mean it works technically, but if the goal is to iterate through the string in order to push certain values, it'd be better to use a for loop. Map functions are more when you want to iterate in order to apply the same specified method to each individual character
Also this is just a formatting thing but it makes it a lot easier to read and understand your code when you have some spaces between variables and operators, and choosing variable names that make sense for what you are doing (this.bookLength, this.reverseAr), or at least using the generic this.array or this.arr It makes it easier to ask questions like this because you'll get less clarifying questions about typos, and also if you are ever planning to work on a larger code base it's important to write clean code that is understandable to someone who doesn't know you
I have feeling this must be a duplicate, but I've been unable to find anything, probably due to different wording, or just because there really is nothing better.
I am generating kind of huge chunk of JS code, which "ORs" object properties with variables, while identifiers don't necessarily match. It looks like this (values are boolean):
a.borderline = a.borderline || borderline;
a.st1 = a.st1 || st;
a.ref64 = a.ref64 || ref;
a.unfortunatelySometimesQuiteLongIndentifier123 = a.unfortunatelySometimesQuiteLongIndentifier123 || unfortunatelySometimesQuiteLongIndentifier;
...
To make it leaner I tried something like
a.st1 |= st;
but it makes a.st1 integer instead of boolean and I don't want to add another line with double negation to retype it back to boolean.
Using intuition I also tried ||=, which did not help :)
Is there any better (shorter) way of writing these commands?
Note: I cannot process the commands using a loop, because the commands are not executed all at once, instead they are spread in small chunks in the rest of the code (which was omitted for simplicity).
No, there is no shorthand OR operator in javascript. Coffeescript however does provide ||= and ?= to support this idiom.
Is there any better (shorter) way of writing these commands?
In your case, you're amending the a object instead of assigning to variables. You might do this in a loop fashion:
function amendWith(target, source)
for (var p in source)
if (!target[p])
target[p] = source[p];
return target;
}
amendWith(a, {
borderline: borderline,
st1: st,
ref64: ref,
unfortunatelySometimesQuiteLongIndentifier123: unfortunatelySometimesQuiteLongIndentifier
…
});
I'm not sure this is any shorter, but just as an alternative idea you could put the OR logic in a function and then loop through your values.
function myFunctionName(value1, value2) {
return value1 || value2;
}
//names are property names of object 'a' that you want to set, values are the alternate (default) values
var myMapping = {borderline:borderline, st1:st, reallyLongName123:reallyLongName};
for (temp in myMapping) {
a.temp = myFunctionName(a[temp], myMapping[temp]);
}
Since your unable to use a loop and you don't know all the values ahead of time, you could try adding the function to your object 'a'
a.test = function(propName, otherValue) {
this[propName] = this[propName] || otherValue;
};
a.test("borderline", borderline);
Scenario: I'm searching for a specific object in a deep object. I'm using a recursive function that goes through the children and asks them if I'm searching for them or if I'm searching for their children or grandchildren and so on. When found, the found obj will be returned, else false. Basically this:
obj.find = function (match_id) {
if (this.id == match_id) return this;
for (var i = 0; i < this.length; i++) {
var result = this[i].find(match_id);
if (result !== false) return result;
};
return false;
}
i'm wondering, is there something simpler than this?:
var result = this[i].find(match_id);
if (result) return result;
It annoys me to store the result in a variable (on each level!), i just want to check if it's not false and return the result. I also considered the following, but dislike it even more for obvious reasons.
if (this[i].find(match_id)) return this[i].find(match_id);
Btw I'm also wondering, is this approach even "recursive"? it isn't really calling itself that much...
Thank you very much.
[edit]
There is another possibility by using another function check_find (which just returns only true if found) in the if statement. In some really complicated cases (e.g. where you don't just find the object, but also alter it) this might be the best approach. Or am I wrong? D:
Although the solution you have is probably "best" as far as search algorithms go, and I wouldn't necessarily suggest changing it (or I would change it to use a map instead of an algorithm), the question is interesting to me, especially relating to the functional properties of the JavaScript language, and I would like to provide some thoughts.
Method 1
The following should work without having to explicitly declare variables within a function, although they are used as function arguments instead. It's also quite succinct, although a little terse.
var map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return this.id == match_id ? this : map(this, function(u) {
return find.call(u, match_id);
}).filter(function(u) { return u; })[0];
};
How it works:
We test to see if this.id == match_id, if so, return this.
We use map (via Array.prototype.map) to convert this to an array of "found items", which are found using the recursive call to the find method. (Supposedly, one of these recursive calls will return our answer. The ones which don't result in an answer will return undefined.)
We filter the "found items" array so that any undefined results in the array are removed.
We return the first item in the array, and call it quits.
If there is no first item in the array, undefined will be returned.
Method 2
Another attempt to solve this problem could look like this:
var concat = Function.prototype.call.bind(Array.prototype.concat),
map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return (function buildObjArray(o) {
return concat([ o ], map(o, buildObjArray));
})(this).filter(function(u) { return u.id == match_id })[0];
};
How it works:
buildObjArray builds a single, big, 1-dimensional array containing obj and all of obj's children.
Then we filter based on the criteria that an object in the array must have an id of match_id.
We return the first match.
Both Method 1 and Method 2, while interesting, have the performance disadvantage that they will continue to search even after they've found a matching id. They don't realize they have what they need until the end of the search, and this is not very efficient.
Method 3
It is certainly possible to improve the efficiency, and now I think this one really gets close to what you were interested in.
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
obj.find = function(match_id) {
try {
(function find(obj) {
if(obj.id == match_id) throw this;
forEach(obj, find);
})(obj);
} catch(found) {
return found;
}
};
How it works:
We wrap the whole find function in a try/catch block so that once an item is found, we can throw and stop execution.
We create an internal find function (IIFE) inside the try which we reference to make recursive calls.
If this.id == match_id, we throw this, stopping our search algorithm.
If it doesn't match, we recursively call find on each child.
If it did match, the throw is caught by our catch block, and the found object is returned.
Since this algorithm is able to stop execution once the object is found, it would be close in performance to yours, although it still has the overhead of the try/catch block (which on old browsers can be expensive) and forEach is slower than a typical for loop. Still these are very small performance losses.
Method 4
Finally, although this method does not fit the confines of your request, it is much, much better performance if possible in your application, and something to think about. We rely on a map of ids which maps to objects. It would look something like this:
// Declare a map object.
var map = { };
// ...
// Whenever you add a child to an object...
obj[0] = new MyObject();
// .. also store it in the map.
map[obj[0].id] = obj[0];
// ...
// Whenever you want to find the object with a specific id, refer to the map:
console.log(map[match_id]); // <- This is the "found" object.
This way, no find method is needed at all!
The performance gains in your application by using this method will be HUGE. Please seriously consider it, if at all possible.
However, be careful to remove the object from the map whenever you will no longer be referencing that object.
delete map[obj.id];
This is necessary to prevent memory leaks.
No there is no other clear way, storing the result in a variable isn't that much trouble, actually this is what variables are used for.
Yes, that approach is recursive:
you have the base case if (this.id==match_id) return this
you have the recursive step which call itself obj.find(match_id) { ... var result = this[i].find(match_id); }
I don't see any reason, why storing the variable would be bad. It's not a copy, but a reference, so it's efficient. Plus the temporary variable is the only way, that I can see right now (I may be wrong, though).
With that in mind, I don't think, that a method check_find would make very much sense (it's most probably basically the same implementation), so if you really need this check_find method, I'd implement it as
return this.find(match_id) !== false;
Whether the method is recursive is hard to say.
Basically, I'd say yes, as the implementations of 'find' are all the same for every object, so it's pretty much the same as
function find(obj, match_id) {
if (obj.id == match_id) return obj;
for (var i = 0; i < obj.length; ++i) {
var result = find(obj[i], match_id);
if (result !== false) return result;
}
}
which is definitely recursive (the function calls itself).
However, if you'd do
onesingleobjectinmydeepobject.find = function(x) { return this; }
I'm not quite sure, if you still would call this recursive.