I have been looking underscore.js library functions and I noticed a function which returns whether the element is a DOM element or not. The function is below.
_.isElement = function(obj) {
return !!(obj && obj.nodeType == 1);
};
Can you please tell me why !! is being used instead of just returning (obj && obj.nodeType == 1). I am wondering whether !! adds any performance improvements. Any idea...
!! forces the result to be a boolean.
If you pass null, for example, then the && will return null. The !! converts that to false.
If obj is "truthy", you'll get the result of obj.nodeType == 1 which is a boolean.
Related
I want to add some defensive coding to the following check. I have 3 strings and I want to know if any of them have anything in them (for my purposes, null or undefined means they do not have anything in them).
if (twitterUrl.length + facebookUrl.length + linkedInUrl.length > 0) {
This works, but feels like very bulky. I use TypeScript and not sure if there is anything there that can help me with this.
if ((twitterUrl ? twitterUrl.length : 0) +
(facebookUrl ? facebookUrl.length : 0) +
(linkedInUrl ? linkedInUrl.length : 0) > 0) {
You can use the fact that empty strings are falsy¹. If you know they'll be strings or null or undefined and you don't need to worry about strings with just whitespace in them (" " is truthy¹), then:
if (twitterUrl || facebookUrl || linkedInUrl) {
If you need to worry about trimming, then a helper function is probably in order:
function present(s) {
return s && (typeof s !== "string" || s.trim());
}
and
if (present(twitterUrl) || present(facebookUrl) || present(linkedInUrl)) {
or
if ([twitterUrl, facebookUrl, linkedInUrl].some(present)) {
¹ falsy and truthy: When you use a value in a condition (like an if), JavaScript will implicitly coerce the value to a boolean. A value that coerces to false is falsy; one that coerces to true is truthy. The falsy values are "", null, undefined, 0, NaN, and of course, false. All other values (including " ") are truthy.
You could define a function as the following one:
function getLength(s){
if(typeof s !== "string") return 0;
return s.length;
}
and then use it like below:
if (getLength(twitterUrl) > 0 || getLenght(facebookUrr) > 0 || getLength(linkedInUrl){
// code
}
Essentially, getLength check if the value you pass when you call the function is a string and if so it returns its length. Otherwise, it returns 0. So in order to achieve that you want, (I want to know if any of them have anything in them), you have to check one by one the strings you have, if the first string has a length greater than zero, there isn't any need to continue the check for the other two strings. Otherwise you call the function on the second string and so on and so forth.
Try like this, normal if statement also works
const socialLinks = [twitterUrl, facebookUrl, linkedInUrl];
const hasSomething = socialLinks.some(social => social);
Here is falsy value like null, undefined, '' and etc., https://developer.mozilla.org/en-US/docs/Glossary/Falsy
if social are empty string('') or null or undefined then it's return false. We omitted return keyword because arrow function has implicit return behaviour.
This is a solution using some(), which checks whether at least one element in the array passes the test implemented by the provided function.
var twitterUrl, facebookUrl, linkedInUrl;
linkedInUrl = 'nonEmpty';
result = [twitterUrl, facebookUrl, linkedInUrl].some(arrVal => arrVal);
console.log(result);
I need to determine whether a given object is either an Array, or typed array such as Float32Array.
Currently I'm checking whether the .length property is defined, but this isn't always indicative of an array. Similar issues arise with existence checking of .forEach() or other methods.
Several instanceof checks would suffice, as done here - but I'm wondering if there is a simple built-in feature, e.g., a generic Array.isArray() function that does what I need.
function isArrayOrTypedArray(x) {
return Boolean(x && (typeof x === 'object') && (Array.isArray(x) || (ArrayBuffer.isView(x) && !(x instanceof DataView)));
}
Unfortunately, I don't believe there is.
You can do the instanceof checks you mentioned, or you could check the result of Object.prototype.toString.call(variable) to see if it's one of the predefind strings ("[object Array]", "[object Uint8Array]", etc.). (Edit: Ah, I see by following the link in your question that that's also demonstrated by that code.)
While I think, as T.J. Crowder already said, there's no built-in function, you should be able to combine Array.isArray and ArrayBuffer.isView to get the functionality you want:
function isArrayOrTypedArray(x) {
return Array.isArray(x) || (ArrayBuffer.isView(x) &&
Object.prototype.toString.call(x) !== "[object DataView]");
}
Array.isArray(x) returns true if x is an array. ArrayBuffer.isView(x)returns true if x is a typed array or DataView, so we just need to ignore the case where x is a DataView to get the function we want.
Demonstration:
function isArrayOrTypedArray(x) {
return Array.isArray(x) || (ArrayBuffer.isView(x) && Object.prototype.toString.call(x) !== "[object DataView]");
}
console.log(isArrayOrTypedArray()); // false
console.log(isArrayOrTypedArray({})); // false
console.log(isArrayOrTypedArray(null)); // false
console.log(isArrayOrTypedArray(undefined)); // false
console.log(isArrayOrTypedArray(new ArrayBuffer(10))); // false
console.log(isArrayOrTypedArray([])); // true
console.log(isArrayOrTypedArray([1,2,3,4,5])); // true
console.log(isArrayOrTypedArray(new Uint8Array())); // true
console.log(isArrayOrTypedArray(new Float32Array())); // true
console.log(isArrayOrTypedArray(new Int8Array(10).subarray(0, 3))); // true
var buffer = new ArrayBuffer(2);
var dv = new DataView(buffer);
console.log(isArrayOrTypedArray(dv)); // false
You could do something like this:
function isArray(array) {
if((array.length || array.length === 0) && (array.constructor !== String)) {
return true;
}
return false;
}
Note that a String also has a length property and we need to exclude that, hence the constructor check.
To determine if x is an ArrayBuffer,
You can take advantage of the fact that new DataView(x) throws "TypeError: First argument to DataView constructor must be an ArrayBuffer" if x isn't an ArrayBuffer.
In other words, simply do:
function isArrayBuffer(x) {
try {
new DataView(x);
return true;
}
catch (TypeError) {
return false;
}
}
And to test if a thing is a TypedArray,
I believe ArrayBuffer.isView does the job.
You can use obj.constructor.name as a way of getting the object's name rather than an instanceof matching ladder.
What all these arrays have in common is they have Array in their classname and a array.length property which is a number.
function isArray(x) {
if (typeof x.length === 'number'
&& x.constructor.name.includes('Array')) {
return true;
}
return false;
}
This works in later versions of Javascript/Node anyway.
You could use name.includes if your JS version supports it.
Array.constructor.name is Array for [] and others like Uint8Array for typed arrays.
In other versions of JavaScript you may need obj.prototype.constructor.name.
I'm trying to teach myself some JavaScript via Eloquent Javascript.
I'm on chapter 4 practice 4.4 Deep comparison.
I've written my own code, passed all the tests given, even some tests I've made myself, but when I checked the solution, it was something totally different than what I had.
Could anyone tell me whether my code produces the same result as the solution, or some ideas of how to figure out whether if my code is right even when mine is something totally different than what the solution is, not just for this practice problem but also in future problems?
I'm just afraid of having a wrong idea and not realizing since my code works.
The question is:
Write a function, deepEqual, that takes two values and returns true only if they are the same value or are objects with the same properties whose values are also equal when compared with a recursive call to deepEqual.
To find out whether to compare two things by identity (use the === operator for that) or by looking at their properties, you can use the typeof operator. If it produces "object" for both values, you should do a deep comparison. But you have to take one silly exception into account: by a historical accident, typeof null also produces "object".
My code is:
function deepEqual(val1, val2) {
if(typeof val1 !== typeof val2) return false;
else if(typeof val1 !== "object") return val1 === val2;
for(var event in val1){
return deepEqual(val1[event], val2[event]);
}
}
and the solution is:
function deepEqual2(a, b) {
if (a === b) return true;
if (a == null || typeof a != "object" ||
b == null || typeof b != "object")
return false;
var propsInA = 0, propsInB = 0;
for (var prop in a)
propsInA += 1;
for (var prop in b) {
propsInB += 1;
if (!(prop in a) || !deepEqual(a[prop], b[prop]))
return false;
}
return propsInA == propsInB;
}
Thanks in advance!
There are a couple of problems with your code:
You only test the first property in an object, because you have a return in your for-in loop. So when comparing objects, all your code does is check that first property.
If you kept a flag and returned the result after the loop, it would still have the issue that it only checks the properties in a; what if b has a property a doesn't have?
I have some inherited code which is causing problems in Safari.
The problem comes from a few lines in the code that do things like this:
if ( ... && $("#element1").val().match(/regex/) && ...)
The javascript itself is programmatically generated.
The problem is that sometimes that $("#element1").val() returns null and I can't easily put a typeof check before it, because it needs to treat null as empty string.
The easiest (and manageable) solution would be either to create a nullmatch function and call that instead or to override the .match function itself. The new function would then check for null first and (if it is null) pass empty string to match instead of null.
I am not sure how to do either, or which would be best.
It would be better to either replace, or add to it (e.g.
$("element1").val().nullmatch(/regex/) or
$("element1").val().nullToEmpty().match(/regex/)
That isn't really possible, because .nullmatch or .nullToEmpty would need to be a method on a possibly null value.
If you really want to write in this fashion, or it's easier for your backend to generate, then you could write a mini-plugin:
$.fn.valNullToEmpty = function() { return this.val() || ''; }
$("element1").valNullToEmpty().match(/regex/)
You can use the || operator:
if ( ... && ($("#element1").val() || "").match(/regex/) && ...)
Basically, foo || "" will return foo if it's truthy, or the empty string if foo is falsy (false, undefined, null, empty string, +0, -0 or NaN).
How about...
function nullString(str) {
if (str === null) {
return "";
else {
return str;
}
So your if statement could become
if ( ... && nullString($("#element1").val()).match(/regex/) && ...)
The jQuery docs for val() state that it returns null when the element is select and no options are selected.
So using valHooks may help
var originalSelectHook;
if ($.valHooks.select) {
originalSelectHook = $.valHooks.select.get;
}
$.valHooks.select = {
get: function(elem) {
var index = elem.selectedIndex;
if (index == -1 || elem.options[index].disabled) {
return "";
}
else {
return originalSelectHook(elem)
}
};
Code assumes that there is a existing hook for select
I don't recollect exactly what its called but php checks and exists as soon as it finds one false value in a function, like so :
// php
if(isset(a["hi"]) && isset(a["hi"]["hello"])) {
}
here if a["hi"] is not set, it will not bother to check the next a["hi"]["hello"].
to check something like this in javascript you'd need to nest
// js
if(typeof(a["hi"]) != "undefined") {
if(typeof(a["hi"]["hello"]) != "undefined") {
}
}
Can we do php style lazy checking in javascript?
(I may not be using the best method to check if an element exists in a multi-dimentional array, if there is a succinct way of doing this, would love to know.)
thanks!
You could use in to check property existence.
if(a && ('hi' in a) && ('hello' in a['hi'])) {
}
if(a.hi === undefined && a.hi.hello === undefined) {
if you know that a.hi can never be a falsey value (null / false / 0) you can do
if(!a.hi && !a.hi.hello) {
Checking the typeof a variable for the string "undefined" is equivalent to using === to check whether the variable is the same data type as the undefined keyword. You can therefore reduce the nested if statements to a single statement:
if(a.hi !== undefined && a.hi.hello !== undefined) {
// do something with a.hi.hello
}
It's worth noting that the statement above assumes that a is not null when the if statement takes place which could cause errors. It also holds true that if you require a.hi.hello to be present for the if statement to evaluate, then you can use falsy checking for a and a.hi as they would need to be object types for (which are non-falsy):
if(!!a && a.hi && a.hi.hello !== undefined) {
// do something with a.hi.hello
}