How to indicate that new RegExp() constructed by undifined value? - javascript

I have this JavaScript row:
var matcherName = new RegExp(filterValueName);
The filterValueName variable has some string but, might be situation when filterValueName is undifined .
My question is how can I know if matcherName was constructed by filterValueName = undifined?

Why not testing filterValueName first?
Something like
var matcherName = null;
if( filterValueName != undefined ) {
var matcherName = new RegExp(filterValueName);
}
...
if( matcherName === null ) {
// filterValueName was undefined
} else {
// filterValueName was ok
}

In Firefox and Chrome at least the regex defaults to /(?:)/. But just compare the strings to be sure:
function is_regex_undefined(regex) {
var undefined;
return String(regex) === String(new RegExp(undefined));
}
According to MDN the pattern should not be absent. I would not doubt that there might be a JS engine where new RegExp(undefined) equals /undefined/. Then this solution would fail if you really have an expression that should match the string "undefined". #RiccardoC's answer is the safer choice.

I would recommend having an if statement before, since you can't easily extract what you constructed it with. Is there anything preventing you from testing the values before you work with them?
var matcherName = new RegExp("foo");
var matcherName2 = new RegExp(undefined);
console.log(matcherName)
VM522:2 /foo/
console.log(matcherName2)
VM527:2 /(?:)/

Related

Getting all occurences in a string with Javascript Regex

First of all I am not an expert on JavaScript, in fact I am newbie.
I know PHP and there are functions to get all occurences of a regex pattern preg_match() and preg_match_all().
In the internet I found many resources that shows how to get all occurences in a string. But when I do several regex matches, it looks ugly to me.
This is what I found in the internet:
var fileList = []
var matches
while ((matches = /<item id="(.*?)" href="(.*?)" media-type="(?:.*?)"\/>/g.exec(data)) !== null) {
fileList.push({id: matches[1], file: matches[2]})
}
fileOrder = []
while ((matches = /<itemref idref="(.*?)"\/>/g.exec(data)) !== null) {
fileOrder.push({id: matches[1]})
}
Is there a more elegant way other than this code?
Using regexes on html is generally held to be a bad idea, because regexes lack sufficient power to reliably match a^n b^n arbitrarily nested occurrences such as balanced parens or HTML/XML open/close tags. Its also trivially easy to get data out of the DOM in JavaScript without treating it like a string, that's what the DOM is for. For example:
let mapOfIDsToFiles = Array.from(document.querySelectorAll('item'))
.reduce((obj, item) => {
obj[item.id] = item.href;
return obj;
}, {});
This has the added advantage of being much faster, simpler, and more robust. DOM access is slow, but you'll be accessing the DOM anyway to get the HTML you run your regexes over.
Modifying built-in prototypes like String.prototype is generally held to be a bad idea, because it can cause random breakages with third-party code that defines the same function but differently, or if the JavaScript standard gets updated to include that function but it works differently.
UPDATE
If the data is already a string, you can easily turn it into a DOM element without affecting the page:
let elem = document.createElement('div')
div.innerHTML = data;
div.querySelectorAll('item'); // gives you all the item elements
As long as you don't append it to the document, its just a JavaScript object in memory.
UPDATE 2
Yes, this also works for XML but converting it to DOM is slightly more complicated:
// define the function differently if IE, both do the same thing
let parseXML = (typeof window.DOMParser != null && typeof window.XMLDocument != null) ?
xml => ( new window.DOMParser() ).parseFromString(xml, 'text/xml') :
xml => {
let xmlDoc = new window.ActiveXObject('Microsoft.XMLDOM');
xmlDoc.async = "false";
xmlDoc.loadXML(xml);
return xmlDoc;
};
let xmlDoc = parseXML(data).documentElement;
let items = Array.from(xmlDoc.querySelectorAll('item'));
Note that if the parse fails (i.e. your document was malformed) then you will need to check for the error document like so:
// check for error document
(() => {
let firstTag = xmlDoc.firstChild.firstChild;
if (firstTag && firstTag.tagName === 'parsererror') {
let message = firstTag.children[1].textContent;
throw new Error(message);
}
})();
I came up with the idea of creating a method in String.
I wrote a String.prototype that simplyfy things for me:
String.prototype.getMatches = function(regex, callback) {
var matches = []
var match
while ((match = regex.exec(this)) !== null) {
if (callback)
matches.push(callback(match))
else
matches.push(match)
}
return matches
}
Now I can get all matches with more elegant way. Also it's resembles preg_match_all() function of PHP.
var fileList = data.getMatches(/<item id="(.*?)" href="(.*?)" media-type="(?:.*?)"\/>/g, function(matches) {
return {id: matches[1], file: matches[2]}
})
var fileOrder = data.getMatches(/<itemref idref="(.*?)"\/>/g, function(matches) {
return matches[1]
})
I hope this helps you too.

Setting a Javascript if statement with 2 requirements to one line

var status = result.locations[index].status;
var operator = result.locations[index].operator;
var original = result.locations[index].original;
var produced = result.locations[index].produced;
var href = result.locations[index].more;
I have the above which each need to be an if statement to check if there is content and my output is the below code.
if (result.locations[index] && result.locations[index].status){
var status = result.locations[index].status;
} else {
var status = '';
}
I would need to reproduce this per line from the code at the top of the post. What would be the best method to simplify each down to keep the code neater and not produce 5 lines of if statement when 1 or 2 would do.
var status = (result.locations[index] && result.locations[index].status ? result.locations[index].status : '');
Not sure why you want to, but:
var status = (result.locations[index] && result.locations[index].status) ? result.locations[index].status : ""
Your problem is trying to access a property of a "deep" javascript object using its path.
This is a common question :
Javascript: Get deep value from object by passing path to it as string
Accessing nested JavaScript objects with string key
There is no built-in way to do this in javascript.
There are plenty of libraries to do that, for example, with selectn, this would become something like (I have not tested it, so I don't know if the index part will work, but you get the idea) :
var status = selectn("locations." + index + ".status", result) || ''
If the structure of your objects is always the one above (that is, the property is just at one level of depth), and you're not expecting 'falsy', you could simply write the 'test' function yourself :
function safeGet(instance, propertyName, defaultValue) {
// As pointed by AlexK, this will not work
// if instance[propertyName] can be anything Falsy ("", 0, etc...)
// If it's possible, get a library that will do
// the full series of insane checks for you ;)
if (instance && instance[propertyName)) {
return instance[propertyName];
} else {
return defaultValue;
}
}
var location = result.locations[index]; // Potentially undefined, but safeGet will deal with it
var status = safeGet(location, "status", "");
var operator = safeGet(location, "operator", "DEFAULT_OPERATOR");
...
var status = result.locations[index] && result.locations[index].status || '';
However, better maje sure before, if result.locations[index] exists... else do whatever is to be done in your code..

how to handle JSON.stringify when string is empty

I'm trying to handle an object which doesn't exist in the array.
var departureGate = JSON.stringify(data.flightStatuses[i].airportResources.departureGate);
So, when the javascript code gets here, it fall over because there happens to be nothing in the actual string it is trying to parse. I've tried catching it with "typeof", but that doesn't work either. I'm stumped.
So, the data.flightStatuses[i] array exists, just not the .airportResources.departureGate.
I tried to see if it exists using "typeof data.flightStatuses[i].airportResources.departureGate". It still falls over.
alert (typeof data.flightStatuses[i]) // this comes back "object"
alert (typeof data.flightStatuses[i].airportResources.departureGate) // it dies...
Should be fairly straight forward like this:
if (data.flightStatuses[i].airportResources.departureGate) {
var departureGate = JSON.stringify(data.flightStatuses[i].airportResources.departureGate);
}
It looks like your problem is with airportResources, and not with departureGate.
Try this:
var departureGate = null,
ar = data.flightStatuses[i].airportResources;
if(ar && 'departureGate' in ar){
departureGate = JSON.stringify(ar.departureGate);
}
Cheers
You can check if the departuregate is defined as a property at all like this, and then do the action you wanted, for example:
if(data.flightStatuses[i].airportResources.hasOwnProperty('departureGate') {
var departureGate = JSON.stringify(data.flightStatuses[i].airportResources.departureGate);
} else {
var departuregate = null; // for example
}
More info here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

simplify javascript if statement where conditions are identical except for variable

I apologize if this is a duplicate question. It's such a use-case question that it seems everyone has their own version.
I'm wondering if this can be simplified:
if ($('.taxclass').text().indexOf(tax1)>-1 || $('.taxclass').text().indexOf(tax2)>-1) {}
It's pretty simple as it stands, but you could make it a bit less redundant mainly by getting the elements text only once and reusing the variable:
var text = $('.taxclass').text();
if (text.indexOf(tax1)>-1 || text.indexOf(tax2)>-1) {
}
A further note could be to reduce the traversal of the DOM by using an identifier and looking only for a distinct element (if that suits your needs) instead of every possible thing that has the class taxclass.
var txt = $('.taxclass').text();
if (txt.indexOf(tax1)>-1 || txt.indexOf(tax2)>-1) {}
One super quick way would be not to duplicate $('.taxclass').text()
Try something like
var tax = $('.taxclass').text();
if (tax.indexOf(tax1)>-1 || tax.indexOf(tax2)>-1) {}
You can store $('.taxclass').text() in a variable, or use regex.
var str = $('.taxclass').text();
if (str.indexOf(tax1) > -1 || str.indexOf(tax2) > -1)
// Or with regex
if(/(text1)|(text2)/.test($('.taxclass').text())
{}
Quick and dirty:
text.indexOf(tax1+"~"+tax2)>-1
Functional, works on n strings, but verbose:
[tax1, tax2].some(function(s) { return s.indexOf(text)>-1 })
As a prototype:
String.prototype.foundIn = function() {
var s=this; return Array.prototype.slice.call(arguments).some(function(m)
{return m.indexOf(s)>-1});
};
Usage:
$('.taxclass').text().foundIn(tax1, tax2)
What about:
f = function (x) { return $('.taxclass').text().indexOf(x) > -1; }
if (f(tax1) || f(tax2)) {}

jquery/javascript missing ) after formal parameters

Hi there I have this code:
function getFullnameDetails(mainHeight,upperstyle,type=''){
setTimeout(function(){fullnameCenter(mainHeight,upperstyle,type='')},2000);
}
function fullnameCenter(mainHeight,upperstyle,type=''){
var distOfMainAndUpper = mainHeight - upperstyle;
var mainHalfHeight = mainHeight/2;
var imageHeight = jQuery("img[rel='fullname']").height(); //there is a delay
var imageHalfHeight = imageHeight/2;
var fromImageTopToMainHalf = mainHalfHeight - imageHeight;
var position = imageHalfHeight+fromImageTopToMainHalf-distOfMainAndUpper;
if(type == 'big'){ jQuery("#temp .test1").css("bottom",position+"px"); }
else { jQuery(".test1").css("bottom",position+"px"); }
}
It says that I'm missing ) after formal parameters.
This happens on this line:
function getFullnameDetails(mainHeight,upperstyle,type=''){ //IT HAPPENS HERE! :)
setTimeout(function(){fullnameCenter(mainHeight,upperstyle,type='')},2000);
}
What am I doing wrong here.
Thanks in advance for the help :)
Javascript does not support default function parameter values.
You can do things like this (but be wary of unintended 'falsey' values):
function getFullnameDetails(mainHeight,upperstyle,type){
type = type || ''; // if type is 'falsey' (null, undefined, empty string) assign ''
//...
}
As other answers have pointed out, JavaScript doesn't support default values in the function parameters. However, as also pointed out in the other solutions, using an inline || won't work when falsey values are passed (eg null, 0, '', NaN, false). A better solution is to check to see if the argument is undefined:
type = typeof(type) !== 'undefined' ? type : '';
or, more generally:
argument_name = typeof(argument_name) !== 'undefined' ? argument_name : default_value;
Of course, this means that passing undefined to a function will mean that the default value is used instead - but that should be pretty uncommon.
Are you trying to use like a default parameter or something?
type=''
That is not valid -- you can't have an equal sign in the parameter list of a function like that.

Categories