JavaScript typeof - javascript

I have a question about a codeschool.com function exercise which concluded as this...
function countE() {
var phrase = prompt("Which phrase would you like to examine?");
if (typeof(phrase) != "string") {
alert("This is not a valid entry!");
return false;
} else {
var eCount = 0;
for (var i = 0; i < phrase.length; i++) {
if (phrase.charAt(i) === 'e' || phrase.charAt(i) === 'E') {
eCount++;
}
}
alert(eCount);
return true;
}
}
countE()
So.. I wanted to test what is not a string, I wanted to get the alert "This is not a valid entry!".
But, if a prompt only returns a string then why is this
<< if (typeof(phrase) != "string") >> included in the function?
Sorry to ask this basic question here, codeschool discussion page did not give me an answer and I am very curious to know.
Thank you. J

Pressing Cancel or Esc will return null. This is the check you should be interested in.
Reference: MDN prompt.
Note: You don't need to use () with typeof. So change it to:
if (typeof phrase != "string") {
Other Scenarios
When you are expecting a number, like age or something, you can use:
if (isNaN(phrase)) {
The above might help you to decide if it is a number or not.

Related

Comparison Operator Vs. Assignment Operator In JavaScript

This is a piece of code from a simple Bookmarker App I made. I am kind of confused about something here.
Look at the 3rd line of the code. Isn't there supposed to be == instead of = after classname?
Because = is an assignment operator. What I need is true which == or === should give and it indeed does from the console.log.
However when I use === inside the if statement the function no longer works. But it works with the = which is not making any sense to me. It would be great if someone could clarify what's the problem here.
If anyone would like to check the full code including the HTML and CSS, here it is: https://github.com/magnetickode/Bookmarking-App
document.querySelector('.bookmarks').addEventListener('click', deleteBookmark);
function deleteBookmark(e) {
if (e.target.className = 'delete') {
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
console.log(e.target.className === 'delete');
//console.log(e.target.parentNode.getElementsByTagName('p')[0].textContent);
for (let i = 0; i < bookmarks.length; i++) {
if (bookmarks[i].name === e.target.parentNode.getElementsByTagName('p')[0].textContent) {
bookmarks.splice(i, 1);
break;
}
}
}
}
change this:
if (e.target.className = 'delete') {
to
if (e.target.classList.contains('delete')) {
Inside if statement we should use anything, which converts to boolean, so, as you mentioned, simple assignment doesn't make sense, because it always returns true. e.target.className contains all classes of the element, so you can't just do e.target.className == 'delete' or e.target.className === 'delete' if there is more than one class, because strings will not be equal ("q w e" includes "q", but "q" isn't equal to "q w e"). I see, you're using ES6, so you can do e.target.className.includes('delete'), it checks, does the element contain class delete, (for more info about includes method for strings: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes). It is also possible to use String.indexOf like element.className.indexOf('class') !== -1 to test for the existence of a class (or === -1 to test for it's absence).
And here is the example:
const bookmarks = document.querySelectorAll('.bookmarks');
for (let i = 0; i < bookmarks.length; i++) {
bookmarks[i].addEventListener('click', deleteBookmark);
}
function deleteBookmark(e) {
alert("Target contains 'delete' class? " + e.target.className.includes('delete').toString().toUpperCase());
/*if (e.target.className.includes('delete')) {
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
for (let i = 0; i < bookmarks.length; i++) {
if (bookmarks[i].name ===e.target.parentNode.getElementsByTagName('p')[0].textContent) {
bookmarks.splice(i, 1);
break;
}
}
}*/
}
<div class="bookmarks delete">CLICK (contains "delete" class)</div>
<div class="bookmarks">CLICK (doesn't contain "delete" class)</div>

what is the order of boolean logic in Javascript?

I wanted to use two Not and one and in booleans to test if the variable is neither upper case nor lower case.
I used this code so far but it didn't work as required:
else if ((x[i]) !== (x[i].toUpperCase()) && (x[i]!== x[i].toLowerCase()) ){
x.splice(x[i], 1);
}
This code was for a function that sorts entered strings yet uppercase are sorted first.
Here is the full code, I am also open to understanding better ways to create this function apart from boolean logic and the array methods I used.
function alpha(str){ // United States
var x = str.split(""); // [U,n,i,t,e,d,S,t,a,t,e,s]
var cap = [];
var small = [];
for (var i = 0; i<x.length; i++){
if (x[i] == x[i].toUpperCase()){
cap.push(x[i]);
}
else if ((x[i]) !== (x[i].toUpperCase()) && (x[i]!== x[i].toUpperCase()) ) {
x.splice(x[i], 1);
}
else {small.push(x[i]);}
}
var z = cap.sort();
var y = small.sort();
return z.concat(y).join("");
}
Please note the second else if statement is only useful because the code adds an empty space string at the beginning of the output, I'm not sure where it comes from, so please let me know if you have any idea how to sort this even without using the second else if.
In the ASCII table, upper case letters come first. That's why they come first when you sort alphabetically. Here's a link to a page on Wikipedia that shows the table with the upper case letters appearing first and their numerical equivalents. It's even printable.
Also, I took the liberty of simplifying your code a little. Seems like .splice() was not necessary.
function alpha( str ) {
var x = str.split(""); // [U,n,i,t,e,d,S,t,a,t,e,s]
var cap = [];
var small = [];
var length = x.length;
for (var i = 0; i < length; i++) {
if (x[i] === x[i].toUpperCase()) {
cap.push(x[i]);
} else if (x[i] === x[i].toLowerCase()) {
small.push(x[i]);
}
}
return cap.sort().concat(small.sort()).join("");
}
Maybe explain what you're trying to do? It most likely has been done before in some form and you definitely came to the right place to find an answer.
Is this what you want to do?
var str = "United States";
function alpha(str) {
return str.split('').sort().join('');
}
alert(alpha(str));
In all programming languages (as far as i know), boolean expressions are always evaluated from the left to the right with brackets of course.
So in the following example my_func() is called first, and then if there is the chance that the complete expression becomes true my_other_func() is called
if (my_func() && my_other_func()) {
// I only get here if my_func() AND my_other_func() return true
// If my_func() returns false, my_other_func() is never called
}
The same is true for the "or" operator in the following example
if (my_func() || my_other_func()) {
// I only get here if my_func() OR my_other_func() return true
// If my_func() returns true, my_other_func() is not called
}
So back to your code, in details this part (I reformated it a bit for better readability):
if (x[i] == x[i].toUpperCase()){
// only uppercase here
cap.push(x[i]);
} else if (x[i] !== x[i].toUpperCase() && x[i] !== x[i].toUpperCase()) {
// tested twice the same thing, so Im really sure that its not uppercase :D
// only lowercase here
x.splice(x[i], 1);
} else {
// I will never reach this
small.push(x[i]);
}
Im not sure what you want to do, but I hope the comments help to understand your code.

How to check if condition if property has a string?

How to check with if condition if response has a string , if response has a string then execute the if condition.basically if there is error from server i want to make $scope.ActiveFile true.
main.js
$scope.onError = function(e) {
console.log('Error while uploading attachment', e.XMLHttpRequest.response);
$scope.errorMessage = JSON.parse(e.XMLHttpRequest.response).techErrorMsg;
if ($scope.errorMessage >= 1){
$scope.applyActiveFile = true;
}
};
response.json
Server response: {"errorCode":500,"errorMsg":"Service failed. Please contact administrator.","techErrorMsg":"Sheet : PROCESS_INVENTORY not found in the File"}
To solve your specific query this should work
if ($scope.errorMessage != null/blank) //whatever suits you
{
$scope.applyActiveFile = true;
}
Now answering what your question heading says - to check if property is string
if (typeof response === string)
/*typeof tells the type of operator, it will return number in case of number and string in case of string*/
{
$scope.applyActiveFile = true;
}
As mic4ael said, you could use some condition such as:
if ($scope.errorMessage)
$scope.applyActiveFile = true;
You could use some regular expression such as:
if ((/^\s*$/).test($scope.errorMessage))
$scope.applyActiveFile = false;
...which would check if the string is empty or has only white spaces and turn your trigger to false. You'd only want to check one or two values with this, though cause it'll be performance-heavy otherwise.
Many other solutions...
Something like this
for (var i in $scope.errorMessages){
if (typeof $scope.errorMessages[i] === "string"){
alert($scope.errorMessages[i]);
}
}
To test in browser console input:
var a = {"errorCode":500,"errorMsg":"Service failed. Please contact administrator.","techErrorMsg":"Sheet : PROCESS_INVENTORY not found in the File","thirdFieldNotString":1};
for (var i in a){
if (typeof a[i] === "string"){
alert('Value is string');
}
};

Proper way to return value from recursion contained within for loop

I have a function I'm using to recurse through a series of nested, tree node-like objects. Based on the console output, I can tell that all nodes are currently being visited. Here's the function:
function directoryRecurse(dir, searchedPath) {
for (var ii = 0; ii < dir.children.length; ii++) {
if (dir.children[ii].path && dir.children[ii].path === searchedPath) {
return dir.children[ii];
} else {
directoryRecurse(dir.children[ii], searchedPath);
}
}
}
However, the return value is always undefined. I've tried modifying the function so that directoryRecurse(dir.children[ii], searchedPath) is replaced with return directoryRecurse(dir.children[ii], searchedPath), but in this case the function terminates after the first leaf node is found. How do I ensure all nodes are visited and that the final return value is the node being searched for?
So directoryRecurse returns a dir if a match is found, and 'undefined' if no match is found... so you need to check which in your recursive call:
function directoryRecurse(dir, searchedPath) {
for (var ii = 0; ii < dir.children.length; ii++) {
if (dir.children[ii].path && dir.children[ii].path === searchedPath) {
return dir.children[ii];
} else {
var result = directoryRecurse(dir.children[ii], searchedPath);
if (typeof result != 'undefined') {
return result;
}
}
}
}
Not sure of the Javascript syntax for result !== undefined, so anyone who knows feel free to correct.
Update: I think this answer (How to check for "undefined" in JavaScript?) suggests typeof for this case of undefined, so updated accordingly.

Javascript behaving weirdly

the following function does not work as I thought it should have. For some reason, the loop breaks whenever one the the validate function returns false. Why is that?
Here is my code :
function validateGroup(input) {
if (!input.value.match(/^[0-9]{0,2}$/)) {
$(input).addClass("invalidField");
return false;
}
$(input).removeClass("invalidField");
return true;
}
function validateClass(input) {
if (!input.value.match(/^[a-zA-Z0-9-]{0,9}$/)) {
$(input).addClass("invalidField");
return false;
}
$(input).removeClass("invalidField");
return true;
}
function validateData() {
var rows = document.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
var valid = true;
for (var i = 0, arrayLength = rows.length; i < arrayLength; ++i) {
valid = valid && validateClass(rows[i].getElementsByTagName("input")[0]);
valid = valid && validateGroup(rows[i].getElementsByTagName("input")[1]);
valid = valid && validateGroup(rows[i].getElementsByTagName("input")[2]);
}
return valid;
}
Thanks a lot!
the statement valid && validateClass(...) will not call the validateClass method if valid is false. I think what you want to do is change the order of those to
valid = validateClass(rows[i].getElementsByTagName("input")[0]) && valid;
valid = validateGroup(rows[i].getElementsByTagName("input")[1]) && valid;
valid = validateGroup(rows[i].getElementsByTagName("input")[2]) && valid;
Javascript doesn't bother evaluating the rest of an && expression if it already knows that the result is false.
It looks like you want to run the validate functions on each iteration even if ‘valid’ was already set to false. However the && operation you are using will short-circuit, so although the loop will continue the validate functions will not be called on subsequent iterations.
A really simple alternative which would work the way you want would be:
for (var i = 0, arrayLength = rows.length; i < arrayLength; ++i) {
if(!validateClass(rows[i].getElementsByTagName("input")[0])) valid = false;
if(!validateGroup(rows[i].getElementsByTagName("input")[1])) valid = false;
if(!vvalidateGroup(rows[i].getElementsByTagName("input")[2])) valid = false;
}
It sounds like that is the intent of the function. The three lines of
valid = valid && validate...
mean that if any of the validate functions ever hits false valid will remain false for the rest of the loop.
I think it's because of the lazy evaluation scheme Javascript uses with &&. Try a single & instead.
Short-circuit evaluation: Support in common programming languages
It's called short-circuiting. Quick fix: replace each line with
valid = validateClass(rows[i].getElementsByTagName("input")[0]) && valid;

Categories