How to detect syntactical features of JavaScript? - javascript

I know that feature detection works for sniffing objects and methods (things like JSON, querySelector,...) but what about new syntax? like default function parameters?
The problem is that they cause a syntax error that cannot be caught.
Any insight on this? apart from browser and version sniffing which is mostly unreliable.
And if there is no way, does this mean we can not use new features! what are they for then (maybe for use after 10 years !)

Try to create a function within a try-catch block.
var code = '"forgotten close quote';
var valid = true;
try {
new Function(code);
}catch(exc) {
valid = false;
}
Here, trying to put "forgotten close quote into a function will fail due to a syntax error, which is then caught and will set valid to false.

As icktoofay demonstrates, there are ways to check for syntactical features without causing a syntax error, but even if you do that, what would you do with that information? You would need to have multiple versions of your code depending on the supported syntax features and need to do dynamic loading of your scripts for no real purpose.
To address your last question, you don't necessarily have to wait to use the new features. You can use a JavaScript-next to JavaScript-of-today compiler like traceur-compiler, or Typescript, which includes future JavaScript features and compiles into browser-friendly JavaScript.

There is no reliable way to check general support for syntax errors.
However there is plenty that can be used in NodeJS, today.
Also, there's nothing preventing you from using a transpiler, like Traceur, to write fancy JS and have it come out ES5-compatible on the other side.

Related

qx.log.appender Syntax

When declaring qx.log.appender.Native or qx.log.appender.Console, my IDE (PyCharm) complains about the syntax:
// Enable logging in debug variant
if (qx.core.Environment.get("qx.debug"))
{
qx.log.appender.Native;
qx.log.appender.Console;
}
(as documented here)
The warning I get is
Expression statement is not assignment or call
Is this preprocessor magic or a feature of JavaScript syntax I'm not aware yet?
Clarification as my question is ambiguous:
I know that this is perfectly fine JavaScript syntax. From the comments I conclude that here's no magic JS behavior that causes the log appenders to be attached, but rather some preprocessor feature?!
But how does this work? Is it an hardcoded handling or is this syntax available for all classes which follow a specific convention?
The hints how to turn off linter warnings are useful, but I rather wanted to know how this "magic" works
Although what's there by default is legal code, I find it to be somewhat ugly since it's a "useless statement" (result is ignored), aside from the fact that my editor complains about it too. In my code I always change it to something like this:
var appender;
appender = qx.log.appender.Native;
appender = qx.log.appender.Console;
Derrell
The generator reads your code to determine what classes are required by your application, so that it can produce an optimised application with only the minimum classes.
Those two lines are valid Javascript syntax, and exist in order to create a reference to the two classes so that the generator knows to include them - without them, you wouldn't have any logging in your application.
Another way to create the references is to use the #use compiler hint in a class comment, eg:
/**
* #use(qx.log.appender.Native)
* #use(qx.log.appender.Console)
*/
qx.Class.define("mypackage.Application", {
extend: qx.application.Standalone,
members: {
main: function() {
this.base(arguments);
this.debug("Hello world");
}
}
});
This works just as well and there is no unusual syntax - however, in this version your app will always refer to the those log appenders, whereas in the skeleton you are using the references to qx.log.appender.Native/Console were surrounded by if (qx.core.Environment.get("qx.debug")) {...} which means that in the non-debug, ./generate.py build version of your app the log appenders would normally be excluded.
Whether you think this is a good thing or not is up to you - personally, these days I ship all applications with the log appenders enabled and working so that if someone has a problem I can look at the logs (you can write your own appender that sends the logs to the server, or just remote control the user's computer)
EDIT: One other detail is that when a class is created, it can have a defer function that does extra initialisation - in this case, the generator detects qx.log.appender.Console is needed so it makes sure the class is loaded; the class' defer method then adds itself as an appender to the Qooxdoo logging system
This is a valid JS syntax, so most likely it's linter's/preprocessor's warning (looks like something similar to ESLint's no-unused-expressions).
Edit:
For the other part of the question - this syntax most likely uses getters or (rather unlikely as it is a new feature) Proxies. MDN provides simple examples of how this works under the hood.
Btw: there is no such thing as "native" JS preprocessor. There are compilers like Babel or TypeScript's compiler, but they are separate projects, not related to the vanilla JavaScript.

How to detect if browser is compatible with ES2015 [duplicate]

This question already has answers here:
Javascript ES6 cross-browser detection
(10 answers)
Closed 7 years ago.
I have a big chunk of JS libraries that I should rewrite since it's really old and outdated. So, I decided to come up with a solution where I would just use most of ES2015 features like rest parameters.
The thing is, I am sure all the clients would not have their browser up-to-date and I am confused whether I will face any issue regarding their browser is compatible with my new JS libs.
So, I was wondering if I could detect whether the client browsers are compatible with ES2015. And if not, I would just include my old JS library.
I am looking for a solution like Conditional comments, but I am getting nowhere to solution.
Any help in HTML, JS or PHP is appreciated. Please kindly suggest your advice.
I was wondering if I could detect whether the client browsers are
compatible with ES2015. And if not, I would just include my old JS
library.
You cannot do that, simply because AFAIK there's no browser that fully supports ES2015. Also, you don't really want to maintain two different versions of your code, because it's painful and it could get messy really quick.
The approach nowadays is to use a transpiler, which is sort of a compiler that compiles your ES2015 code to ES5 (the JavaScript that every browser knows). It is still kind of messy, but at least you get to write only one version of your code, and it's ES2015.
I think Babel (formerly 6to5) is the most popular transpiler. You can check out their website for getting started.
As to answer your actual question,
How to detect if browser is compatible with ES2015
You can do that in many ways. I'm not sure what could be the most reliable one, but for example you could simply try on your browser's console:
'Promise' in window
If this statement returns true, then the current browser supports promises, which is a new feature of ES2015, so you could assume that it supports most of the features of ES2015.
This is not enough for most cases though; you may want to be 100% sure that what you're using is not going to throw a SyntaxError in any old browser.
A solution could be to manually check for each feature you want to use. For example, if you need the Fetch API, you could create a function that tells you if the current browser supports it:
function isFetchAPISupported() {
return 'fetch' in window;
}
You can do this for any new API you need. However, if you need something syntactically different, I think your only bet is eval() (as Katana314 suggested). For example, in order to check support for rest parameters you could do:
function isRestSupported() {
try {
eval('function foo(bar, ...rest) { return 1; };');
} catch (error) {
return false;
}
return true;
}
This works great in Firefox, because the rest parameters are supported.
It works as well on Safari, returning false because rest parameters are not supported there yet.

Flow type annotations and valid JavaScript source

I'm playing with Facebook's new Flow Type checking system.
In Flow, meet Underscore it appears that they change this JavaScript code
var root = this;
into this
var root: any = this;
But this is no longer valid JavaScript, right? I understand why external Interface files would be useful, but how are type annotations added directly into valid JavaScript sources?
Previously, Google Closure compiler and other projects used on JS comments.
As of Flow 0.4.0 you are able to put the Flow syntax into the comments. This solves your issue. So your example would look like:
var root/*: any*/ = this;
This results in valid JavaScript syntax and there is no need to transpile your code.
Further details can be found here:
http://flowtype.org/blog/2015/02/20/Flow-Comments.html
You're right, that code is no longer valid javascript. That means that when you use Flow in someJavascriptFile.js, you have to execute a program that removes the Flow code from someJavascriptFile.js, which is called transpiling. Which transpiler to use depends on how you're running javascript, and will probably change over time, so I won't link to any.
You can also wrap the flow types into a comment, eg. var name /*:string*/ = "Hello flow.", which is valid javascript, but makes the code harder to read in my opinion.
In theory, Javascript engines could one day natively support Flow parsing, but that's a long ways off.
I missed Running Flow code where it discusses adding a build step to remove type annotations.
You can use the JSX transform tool (part of the React tools) to
translate your files to plain JavaScript
I also found flow-typestrip which is alternative.
I like external interface files per module better, as you can avoid introducing a build step.

JavaScript not working in IE but works in FireFox?

post_form_id = escape(findelementbyname("post_form_id"));
fb_dtsg = escape(document.getElementsByName("fb_dtsg")[0].value);
cookie_user_uid = document.cookie.match(/c_user=(\d+)/)[1];
xhpc_composerid = escape(findelementbyname("xhpc_composerid"));
It seems as if post_form_id and fb_dtsg cannot execute properly in Internet explorer, but work in Firefox?
What would I have to change to have it working in both?
One Question : Are you able to search by Id instead? If so, getElementById(...) will be a better choice.
To get elements by name, you will use getElementsByName("...") - but that will return an array of elements, from which you will need to take the first item.
Typically what you describe regarding inconsistency across browsers is caused by syntax problems...
I believe that this:
findelementbyname(...)
should be this:
FindElementByName(...)
Also run your code through an online syntax checker like JSLint
Although you can make javascript cross browser compatible without extra libraries (such as JQuery), it can often become unneccesarily painful to do so.
I would recommend the use of JQuery.

JavaScript-friendly alternative to the f(x) = y JScript idiom that's used when setting CDO.Message options

I have an ASP page written in JScript that sends e-mails using CDO.Message. For specifying an SMTP server (and other options) I'm doing something like this:
mail.Configuration.Fields.Item(
"http://schemas.microsoft.com/cdo/configuration/smtpserver") =
"smtp.example.com";
Now, here comes the catch. I have this code in a stand-alone include file that I include in an HTML page as JavaScript so that I can run unit tests against it in a browser (using JsUnit etc.). I have JavaScript mock objects (Server, Request, etc.) that create a mock ASP environment for the included JScript code. The only problem I have left is with the CDO.Message option setting. Since the f(x) = y syntax that's used in the above code excerpt is not valid JavaScript (invalid left-hand operand), I can't run this piece of code (as it is) within a browser. I'm currently simply bypassing it in my unit test with a conditional that detects whether the environment is truly ASP.
I don't think that there's a JavaScript workaround to this. I'm looking for an alternative syntax (that may use the ActiveX interfaces differently) to setting CDO.Message options that would also be syntactically valid JavaScript.
I figured out the answer when looking at the C++ code example at http://msdn.microsoft.com/en-us/library/ms526318(EXCHG.10).aspx.
The solution is to make the assignment explicitly to the Value property:
mail.Configuration.Fields.Item(
"http://schemas.microsoft.com/cdo/configuration/smtpserver").Value =
"smtp.example.com";
This way, the code above is valid JavaScript than can be tested with a mock Configuration object.
I've been having the same problem when writing server-side Javascript for IIS, That f(x) = y syntax was failing in my IDE's syntax checker. The solution I found helpful was JScript conditional comments like so:
f(x)/*#cc_on#if(0)*/[0]/*#end#*/ = y;
It puts the subscript index [0] on the end except when running in Microsoft's JScript engine. But, admittedly my solution is a bit hacky. I think in most cases yours is cleaner, so thanks for sharing it.
-Simon

Categories

Resources