The main issue I'm thinking about is whether assigning a variable in an if statement is safe and reliable across different browsers. If it is safe, I'd like to use it.
Here it reads the querystring and if the querystring variable SN is either Twitter or Facebook then it enters the if and you can use the variable, if the querystring variable doesn't exist or is some other value then it goes into the else.
if(socialNetwork = (window.location.search.indexOf("SN=Twitter") > 0) ? "Twitter" : ((window.location.search.indexOf("SN=Facebook") > 0) ? "Facebook" : null))
{
alert(socialNetwork);
}
else
{
alert("nope");
}
It is part of the language design and should work in every browser, but it's very difficult to read.
That's ugly.
var uselessSocialNetworkingApp = window.location.search.replace(/.*\bSN=(\w+)\b.*/, "$1");
if (uselessSocialNetworkingApp)
alert("yay!");
else
alert("no");
It's kind-of funny that there'd be that hideous construction in the "if" header, but that it'd be an "if" instead of a "? :" expression inside the "alert" argument list :-)
Also, to be at least slightly sympathetic to the intended style, this is an example of what the "let" statement in ultra-modern Javascript is for.
Oh my! This is valid and should always work, assuming that you create the socialNetwork variable elsewhere, don't ever create implied globals. However, this is really a strange way to solve your problem. Why not create a function that returns the social network to abstract this a little?
That said, if you really want a one line solution, how about this?:
alert(function(){ var m = /SN=([A-Za-z]+)/.exec(window.location.search); return (m ? m[1] : null)}());
location.socialNetwork== (function(){
var s= location.search || '';
s= /SN=([a-zA-Z]+)/.exec(s) || [];
return s[1] || null;
})()
alert(location.socialNetwork)
Related
The verbiage was a little awkward here but I know there's a smart way to go about this. I am requesting data from a JSON object. This JSON object will either have a "city", "town", or "locale". It will only ever have one. I have some verbose layered 'if undefined' checks that just stack on top of each other until I find the right one, but I imagine using operators there must be a better way. This code works, I just believe it can it should be done better. Here's an example:
var town = response.data["locale"];
if(town === undefined){
town = response.data["town"];
if(town === undefined){
town = response.data["city"];
if(town === undefined){
town = "N/A";
}
}
}
As you can see I just want to assign my variable to whichever one exists. I find this nested "if statement" mess a complete eyesore. Perhaps my problem can help people in the future write cleaner code. I'm not great with operators but this situation doesn't seem to call for use of any ternary operators.
You’ve tagged the question with node.js, so I’ll assume you’re using Node.js and have modern JavaScript available. The nullish coalescing operator ?? is almost exactly equivalent:
let town = response.data.locale ?? response.data.town ?? response.data.city ?? "N/A";
and you can avoid repeating response too:
let {data} = response;
let town = data.locale ?? data.town ?? data.city ?? "N/A";
(I say “almost exactly equivalent” because it will also fall back on the value null, not just undefined.)
You can use the or (||) operator while defining a variable for example. It checks if the first one is undefined, and if it is, it will try to use the second one, etc.
In your case, you can just replace it to this line.
let town = response.data["locale"] || response.data["town"] || response.data["city"] || "N/A";
I have this code:
for (var i = 0; i < value.length; i++) {
if (typeof value[i].keyword == 'undefined' || value[i].keyword == null || value[i].keyword.startsWith(keyword)) {
out.push(value[i]);
}
}
I am getting an error message saying:
> TypeError: r[e].startsWith is not a function
> at js-cf2cc68….min.js.gz:85
> at fn (eval at compile (js-cf2cc68….min.js.gz:8), <anonymous>:4:1003)
> at js-cf2cc68….min.js.gz:7
> at p.$digest (js-cf2cc68….min.js.gz:7)
> at p.$apply (js-cf2cc68….min.js.gz:7)
> at HTMLBodyElement.<anonymous> (js-cf2cc68….min.js.gz:9)
How is this possible? I think I've accounted for everything.
value[i].keyword.startsWith("keyword") because the parameter of start with must be a string.
So that will work better this way
for (var i = 0; i < value.length; i++) {
if (typeof value[i].keyword == String(undefined) || value[i].keyword.startsWith("keyword"))
out.push(value[i]);
}
Found a useful article on this topic
The three approaches for converting to string are:
value.toString()
"" + value
String(value)
The point to note here is that approach # 1 doesn’t work if the value is null or undefined.
In my case, approach # 2 for some reason did not work either so the best option would be String(value)
var col = "rt_" + rows[i]["results"][r].ResultTypeID.substring(1); //did not work
var col = "rt_" + String(rows[i]["results"][r].ResultTypeID).substring(1);
Is there a way that I can check if it's a string rather than have it error out?
checking the type?
var out = values.filter(v => v.keyword == null || typeof v.keyword === "string" && v.keyword.startsWith( keyword ));
or simply enforcing the type
var out = values.filter(v => v.keyword == null || String(v.keyword).startsWith( keyword ));
or if you use desctructuring, you can use even this:
var out = values.filter({keyword: v}) => v == null || String(v).startsWith( keyword ));
I'd reccomend you to use the Array-methods instead of manually writing loops.
Imo. it is a better description of your intent (good for scanning over code).
If this is a hot path (it's called often) the JS-optimizer can take advantage of knowing, that youre'just filtering, and optimize the code. Maybe by skipping the lots of integrity-checks for the Array it performs during your loop.
And if this is not a hot-path, the performance-impact of calling a function a few times will even be hard to measure, in JS.
I fixed this by calling value.toString().startsWith(...)
I assume value[i].keyword is a string. String.prototype.startWith is not supported in older browsers. See browser support.
To use it in older browsers, you can use one of existing polyfills. See also answers from How to check if a string “StartsWith” another string?
There's a definitely obvious problem.
(This is entirely for people who have a problem like this one, but they don't really understand)
Of course, just like many others are saying, it's in the type. If you don't know what types are (You likely do if you know this advanced type of stuff, but just in case!), its simple. The primitive types are True/False, Undefined/Null, Numbers, and Strings, any string type that is not empty or numbers not equal to 0 resulting in being true if put through an if statement on their own. Now that we've got that out of the way, its time to talk about startsWith(). If you run console.log("Hey VSauce, Michael here.".startsWith("Hey")), it would output true to the console due to how the string starts out with a string. If you run console.log(1234.startsWith(1)), would occur with a TypeError due to startsWith() requiring a string. We can tell this is a TypeError from the error output. So, the problem above (that was already answered) was that the variable keyword wasn't being defined as a string, but rather any other variable, and needed to be defined as a string
Can someone tell me if this is valid javascript to do this:
if (wf.statusId == Status.Dirty) {
wf.createdDate
? promises.push(self.wordFormUpdateSubmit(wf, key))
: promises.push(self.wordFormAddSubmit(wf, key));
}
Would there be cases where this would not work correctly if createdDate was not defined?
Here's what this replaced:
if (wf.statusId == Status.Dirty) {
if (wf.createdDate) {
var updatePromise = self.wordFormUpdateSubmit(wf, key);
promises.push(updatePromise);
} else {
var addPromise = self.wordFormAddSubmit(wf, key);
promises.push(addPromise);
}
}
Also a related question. Would it be possible to use the same syntax with ? : to replace the need for the if () { } construct ?
Using = with ternary operator is not mandatory unless expr1 and expr2 are returning something and you want to save it in some other variable.
In your case, unless promises.push(self.wordFormAddSubmit(wf, key)) and promises.push(self.wordFormUpdateSubmit(wf, key)) are returning something that you want to save it a variable, there is no need for a =.
if (wf.statusId == Status.Dirty) {
promises.push(self[wf.createdDate ? 'wordFormUpdateSubmit' : 'wordFormAddSubmit'](wf, key));
}
wf.createdDate only true if it is not undefined or have value. so this should work fine.
if (wf.statusId == Status.Dirty) {
wf.createdDate
? promises.push(self.wordFormUpdateSubmit(wf, key))
: promises.push(self.wordFormAddSubmit(wf, key));
}
Regards
Mk
This is an example of a ternary statement, using the conditional (ternary) operator, which by definition replaces an if...else construct.
From MDN:
The conditional (ternary) operator is the only JavaScript operator that takes three operands. This operator is frequently used as a shortcut for the if statement.
[source]
Both of your code samples would work the same way, ie if createdDate was undefined the second expression of your ternary statement would run (the line after the :) just like the else block of your if...else construct would run.
The title question seems somewhat unrelated, in that you would only need to use = if you wanted to save a reference to something. In this case, it does not appear that you do.
As for your follow-up question, plenty of people use ternary statements for small checks and tasks that fit on one or a few lines (I personally don't because I prefer the readability of if...else), however anything even moderately complex can quickly make your code hard to read and understand. But yes, technically, ternary statements can replace if...else blocks.
regarding the second question:
assuming you don't need to save the results in a variable, you can do:
promises.push(wf.createdDate?
self.wordFormUpdateSubmit(wf, key) :
self.wordFormAddSubmit(wf, key);
);
and even this works:
promises.push(
(wf.createdDate? self.wordFormUpdateSubmit:self.wordFormAddSubmit)(wf, key)
);
simple code but answer not found (maybe I haven't looked deep enough since my main language isn't english..)
getDeviceInfos(deviceIP) ? displayDevice(**return of getDeviceInfos function**) : dead.push=deviceIP;
If getDeviceInfos returns something else than 0 (ie. it == true), i want the return value to be the argument in displayDevice call.
Is there any way to do it or I need to write a "regular" comparison ?
Thanks
You can do the following, but it would need a var to avoid a global variable. As a result, it's not really a straight expression.
var info;
(info = getDeviceInfos(deviceIP)) ? displayDevice(info) : (dead.push = deviceIP);
While this wasn't your question, you can (and perhaps should) do something similar by caching the result with a standard if-else statement, either when you var info, or in the if itself:
var info;
if (info = getDeviceInfos(deviceIP)) {
displayDevice(info);
} else {
dead.push = deviceIP;
}
Provided you're not using the value produced by the ternary expression, I would recommend the latter approach for readability.
First create a variable, then perform the assignment and compare like so -
var a; // <-- A variable.
(a = getDeviceInfos(deviceIP)) ? displayDevice(a) : dead.push = deviceIP;
Based on your update in the comments sections (and for readability's sake), I'd suggest making it a two step check:
var deviceInfo = getDeviceInfos(deviceIP);
(deviceInfo !== 0) ? displayDevice(deviceInfo) : dead.push=deviceIP;
That is a more accurate check of the condition and is easier to read.
Conditional Operator
Multiple ternary evaluations are also possible (note: the conditional operator is right associative).
var hadRelations = false;
var isSure = false;
var presidentQuote = hadRelations ? "Had relations" : isSure ? "Did not have relations" : "I admit";
console.log( presidentQuote ); // Prints "I admit" in the console
I moved it into the function itself..
function getDeviceInfos(pIp)
{
//code
result ? displayDevice(result) : dead[dead.length]=pIp
}
I know this isn't strictly speaking an answer your question, but I'd strongly recommend considering not using the ternary syntax, ever. When writing code, always balance what is the easiest to read and maintain with what is compact, efficient, and cool.
In practice, ternary syntax isn't significantly faster than an if statement, so there's generally no "efficiency" grounds to use it.
Compare:
var info;
(info = getDeviceInfos(deviceIP)) ? displayDevice(info) : (dead.push = deviceIP);
with ...
var info = getDeviceInfos(deviceIP);
if (info) {
displayDevice(info);
} else {
dead.push = deviceIP;
}
Sure, the if-then style is less compact, but it's much easier to understand, debug and extend.
In short, there's almost never a reason to use ternary syntax: it's generally harmful to code quality. Avoid.
I'm creating a text editor and I've just finished writing the highlighting algorithms to have each of the syntax appear in a different color, and render in the right position using the proper parse trees.
I was wondering if anyone could provide me with, or the location of a test or series of test cases to make sure nothing will break. The test case(s) should cover all of JavaScript syntax as it is used on the web including edge cases (i.e., including syntax like throw although it is rarely used), DOM creation and manipulation etc.
I have added the following static test case. It should cover all the syntax.
There are a few things to note: since the code is being parse recursively on a grammar level, only basic cases are required. For example, to the editor:
a[1]; and a[1][2][3][4][5]; would be the same syntax. Since the second line, is just recursively more subs then the the first line.
The test case I have created has been moved to an answer below.
Interesting question. I think my initial approach, barring any other interesting suggestions here, would be to grab a bunch of JavaScript from fairly major libraries. I'm thinking jQuery, Mootools, Prototype, etc.
Then, once you've done a few major libs, do some smaller ones. I'd checkout Github. Maybe look at Underscore, HeadJS, and maybe some others at https://github.com/languages/JavaScript.
I would also take a couple minified libraries, run them through JSBeautifier. Not sure if beautified JS may have slightly altered syntax from the original.
Lastly, I would consider running some of these libraries through JSLint, and then manually go through and modify the sources to explicitly hit some of the 'rules' that JSLint has laid out.
EDIT: And by "hit", I mean make sure you cover both scenarios offered by each rule, not just the 'clean' version.
One possible approach: there are various applications that will generate random pieces of code starting from a BNF grammar of a language (such as this one) and there are grammar files for javascript available.
That won't get you a static test case that you can script tests against with known expected results, necessarily, but might be a good way to test your parser against unexpected (but legal) strings and make sure it doesn't break.
This is so far the best test case I was able to come up with.
EDIT: Added regexp, and throw. This case is syntactically valid and should cover all cases of JS. Please message me directly if you find anything missing so that I can add it here.
a = 1;
b = { 'a' : a };
c = 'a';
d = this;
var patt1=/w3ghouls/i;
throw "Err3";
function e(a,b,c){
d += a + b + c++;
return d;
}
this.xy.z = function(a, b){
var x = null;
}
var f = function(a,b){
if(a == b || (b === a && a)){
var f = [a,b];
try{
f = f.slice(0);
}catch(e){
console.log(e * e + '');
}
}else if(a){
a = null;
a = undefined;
b = typeof a;
b = true;
b = false;
}else{
switch(c){
case 'c':
break;
default:
null;
break;
}
}
}
for(var i =0; i <= a.length; i++){
do{
continue;
null;
}while(a != b);
}
if(a == b)
(a) ? null : null;
/* This is a finished
test case */
A good way to start would be to run this through JSLint to see if your JavaScript is valid. It is the best checking tool I know of, but I'm not sure how well it will do to check if code broken. :(
Hope that helps.