Strange JavaScript assignment with logical or - javascript

I'm building a JavaScript parser and got an error when testing it on jQuery on line 496:
isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
},
I have reduced it down to this:
a = b || function() {}
Is this valid ECMA-262 or is it a feature that has been added since then? Either way, how do I express it in terms of a parser?
My abstract syntax tree for an assignment expression is:
data Assignment
= CondExpr CondExpr
| Assign LeftExpr AssignOp Assignment
| AssignFuncDecl FuncDecl
This doesn't support assignments in the above format.
I can explain my AST more if needed. Thanks for any help you can give!

You should look for "ecma bnf". Here's one of the links.

Related

What is the javascript `_|_`?

I was looking through a solution to a problem in javascript, namely parsing a string into its constituent names, operators, and brackets, when I saw this expression:
return accept(")") ? _|_ : e;
What is that _|_? Is that using node's _ feature? I've looked for documentation but not found any.
When I try using it myself, this happens:
> 5
5
> true ? _|_ : 0
ReferenceError: _ is not defined
at eval:1:1
at eval
at n.<anonymous>
As a clarification, the variable _ was not defined anywhere in the code.
This was run on Node v8.1.3, but also works fine on chrome native browser JS.
Here is the code:
function tokenise(string) {
const tokens = string.match( /[a-z]+|\(|\)|[!#$%&*+\-\/<=>#^_.,;]+/gi ) || [];
const accept = s => s===tokens[0] && tokens.shift() ;
const unaccept = s => s!==tokens[0] && tokens.shift() ;
const singles = (e) => ( e = unaccept(")") ) ? [ e, ...brackets() ] : [] ;
const brackets = (e) => accept("(") ? ( e = brackets(), accept(")") || _|_ , [ e, ...brackets() ] ) : singles() ;
try { let e = brackets(); return accept(")") ? _|_ : e ; }
catch(_) { return null; }
}
_|_ has no special meaning in JavaScript, it's just a | (bitwise OR) expression with the identifier _ on both sides of it.
That code checks the result of calling accept and, if it's truthy, returns the result of the | operation; if not it returns the value of e.
Is that using node's _ feature?
_ isn't special in Node code. In the REPL (only), it's a variable that receives the result of the most recently evaluated expression; details here.
As a clarification, the variable _ was not defined anywhere in the code.
That means that if accept(")") returns a truthy value, the code will throw a ReferenceError because _ is an undeclared identifier. If that's what the author intended, there's no need for the | operator at all, but in a now-deleted answer, georg pointed out that they may have used _|_ as an attempt to express the mathematical concept of bottom ("a computation which never completes successfully"), the symbol for which is ⊥. In any case, the author seems to use it to force an exception in an expression context (since throw is a statement; there's talk of possibly allowing it in expression contexts at some point, though).
It take a variable _ and uses a bitwise OR | with itself.
As result, you get a 32 bit integer number.
In addition to what has already been explained here in details, that your code is quite regular JavaScript, with nothing special about it...
I've come across similar code in more than one programming language when the syntax verbosity was used to generate supposedly funny expressions that resemble Text Art, aka ASCII Art, ones that while make the code look weird, are also 100% valid code.
Your code example reminds one of those stupid jokes, just like when someone introduces a function with a paragraph-long name.

JSON stringify behaving differently on two different chrome tabs [duplicate]

I'm trying to figure out what's gone wrong with my json serializing, have the current version of my app with and old one and am finding some surprising differences in the way JSON.stringify() works (Using the JSON library from json.org).
In the old version of my app:
JSON.stringify({"a":[1,2]})
gives me this;
"{\"a\":[1,2]}"
in the new version,
JSON.stringify({"a":[1,2]})
gives me this;
"{\"a\":\"[1, 2]\"}"
any idea what could have changed to make the same library put quotes around the array brackets in the new version?
Since JSON.stringify has been shipping with some browsers lately, I would suggest using it instead of Prototype’s toJSON. You would then check for window.JSON && window.JSON.stringify and only include the json.org library otherwise (via document.createElement('script')…). To resolve the incompatibilities, use:
if(window.Prototype) {
delete Object.prototype.toJSON;
delete Array.prototype.toJSON;
delete Hash.prototype.toJSON;
delete String.prototype.toJSON;
}
The function JSON.stringify() defined in ECMAScript 5 and above (Page 201 - the JSON Object, pseudo-code Page 205), uses the function toJSON() when available on objects.
Because Prototype.js (or another library that you are using) defines an Array.prototype.toJSON() function, arrays are first converted to strings using Array.prototype.toJSON() then string quoted by JSON.stringify(), hence the incorrect extra quotes around the arrays.
The solution is therefore straight-forward and trivial (this is a simplified version of Raphael Schweikert's answer):
delete Array.prototype.toJSON
This produces of course side effects on libraries that rely on a toJSON() function property for arrays. But I find this a minor inconvenience considering the incompatibility with ECMAScript 5.
It must be noted that the JSON Object defined in ECMAScript 5 is efficiently implemented in modern browsers and therefore the best solution is to conform to the standard and modify existing libraries.
A possible solution which will not affect other Prototype dependencies would be:
var _json_stringify = JSON.stringify;
JSON.stringify = function(value) {
var _array_tojson = Array.prototype.toJSON;
delete Array.prototype.toJSON;
var r=_json_stringify(value);
Array.prototype.toJSON = _array_tojson;
return r;
};
This takes care of the Array toJSON incompatibility with JSON.stringify and also retains toJSON functionality as other Prototype libraries may depend on it.
Edit to make a bit more accurate:
The problem key bit of code is in the JSON library from JSON.org (and other implementations of ECMAScript 5's JSON object):
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
The problem is that the Prototype library extends Array to include a toJSON method, which the JSON object will call in the code above. When the JSON object hits the array value it calls toJSON on the array which is defined in Prototype, and that method returns a string version of the array. Hence, the quotes around the array brackets.
If you delete toJSON from the Array object the JSON library should work properly. Or, just use the JSON library.
I think a better solution would be to include this just after prototype has been loaded
JSON = JSON || {};
JSON.stringify = function(value) { return value.toJSON(); };
JSON.parse = JSON.parse || function(jsonsring) { return jsonsring.evalJSON(true); };
This makes the prototype function available as the standard JSON.stringify() and JSON.parse(), but keeps the native JSON.parse() if it is available, so this makes things more compatible with older browsers.
I'm not that fluent with Prototype, but I saw this in its docs:
Object.toJSON({"a":[1,2]})
I'm not sure if this would have the same problem the current encoding has, though.
There's also a longer tutorial about using JSON with Prototype.
This is the code I used for the same issue:
function stringify(object){
var Prototype = window.Prototype
if (Prototype && Prototype.Version < '1.7' &&
Array.prototype.toJSON && Object.toJSON){
return Object.toJSON(object)
}
return JSON.stringify(object)
}
You check if Prototype exists, then you check the version. If old version use Object.toJSON (if is defined) in all other cases fallback to JSON.stringify()
Here's how I'm dealing with it.
var methodCallString = Object.toJSON? Object.toJSON(options.jsonMethodCall) : JSON.stringify(options.jsonMethodCall);
My tolerant solution checks whether Array.prototype.toJSON is harmful for JSON stringify and keeps it when possible to let the surrounding code work as expected:
var dummy = { data: [{hello: 'world'}] }, test = {};
if(Array.prototype.toJSON) {
try {
test = JSON.parse(JSON.stringify(dummy));
if(!test || dummy.data !== test.data) {
delete Array.prototype.toJSON;
}
} catch(e) {
// there only hope
}
}
As people have pointed out, this is due to Prototype.js - specifically versions prior to 1.7. I had a similar situation but had to have code that operated whether Prototype.js was there or not; this means I can't just delete the Array.prototype.toJSON as I'm not sure what relies on it. For that situation this is the best solution I came up with:
function safeToJSON(item){
if ([1,2,3] === JSON.parse(JSON.stringify([1,2,3]))){
return JSON.stringify(item); //sane behavior
} else {
return item.toJSON(); // Prototype.js nonsense
}
}
Hopefully it will help someone.
If you don't want to kill everything, and have a code that would be okay on most browsers, you could do it this way :
(function (undefined) { // This is just to limit _json_stringify to this scope and to redefine undefined in case it was
if (true ||typeof (Prototype) !== 'undefined') {
// First, ensure we can access the prototype of an object.
// See http://stackoverflow.com/questions/7662147/how-to-access-object-prototype-in-javascript
if(typeof (Object.getPrototypeOf) === 'undefined') {
if(({}).__proto__ === Object.prototype && ([]).__proto__ === Array.prototype) {
Object.getPrototypeOf = function getPrototypeOf (object) {
return object.__proto__;
};
} else {
Object.getPrototypeOf = function getPrototypeOf (object) {
// May break if the constructor has been changed or removed
return object.constructor ? object.constructor.prototype : undefined;
}
}
}
var _json_stringify = JSON.stringify; // We save the actual JSON.stringify
JSON.stringify = function stringify (obj) {
var obj_prototype = Object.getPrototypeOf(obj),
old_json = obj_prototype.toJSON, // We save the toJSON of the object
res = null;
if (old_json) { // If toJSON exists on the object
obj_prototype.toJSON = undefined;
}
res = _json_stringify.apply(this, arguments);
if (old_json)
obj_prototype.toJSON = old_json;
return res;
};
}
}.call(this));
This seems complex, but this is complex only to handle most use cases.
The main idea is overriding JSON.stringify to remove toJSON from the object passed as an argument, then call the old JSON.stringify, and finally restore it.

javascript conditional expression parser

I am working in JavaScript. I want to parse and evaluate conditional expression.
ex:
var param1=1;
var param2=2;
var param3=3;
var expression="(param1==param2)||(param3<param1)";
I want to write a function which will accept 'expression' as a input and parse the expression as well as evaluate expression and return evaluated result.
Please let me know for any suggestions.
Thanks in advance.
Here is the evil one: eval();
var param1=1;
var param2=2;
var param3=3;
var expression=eval("(param1==param2)||(param3<param1)");
Then your function comes,
function myEvaluator(s) {
return eval(s);
}
You must have variables in expression public.
This is a really old question and I am surprised that no libraries came out since to help with this.
Out of necessity, I built a library called angel-eval that does exactly that. It parses a string expression and evaluates with a context object. It uses a parser generator called Nearley under the hood and does not use eval or new Function(…).
To use, install: npm i angel-eval
const { evaluate } = require("angel-eval");
evaluate("(param1===param2)||(param3<param1)", { param1: 1, param2: 2, param3: 3 });
angel-eval does not support == or != so you need to use === and !==.
Here is a sandbox:
There are a few expression parsers out there, but I would like to suggest mine. It's called swan-js and it doesn't use eval or new Function.
Installation:
npm install #onlabsorg/swan-js
Usage (it works both in NodeJS and in the browser):
const swan = require('#onlabsorg/swan-js');
const evaluate = swan.parse("param1 == param2 | param3 < param1");
const context = swan.createContext({param1:1, param2:2, param3:3});
const value = await evaluate(context); // false

Ruby's ||= (or equals) in JavaScript?

I love Ruby's ||= mechanism. If a variable doesn't exist or is nil, then create it and set it equal to something:
amount # is nil
amount ||= 0 # is 0
amount ||= 5 # is 0
I need to do something similar in JavaScript now. What's the convention or proper way to do this? I know ||= is not valid syntax. 2 obvious ways to handle it are:
window.myLib = window.myLib || {};
// or
if (!window.myLib)
window.myLib = {};
Both are absolutely correct, but if you are looking for something that works like ||= in ruby. The first method which is variable = variable || {} is the one you are looking for :)
You can use the logical OR operator || which evaluates its right operand if lVal is a falsy value.
Falsy values include e.g null, false, 0, "", undefined, NaN
x = x || 1
The operator you asked about has been proposed as a feature in JavaScript. It is currently at Stage 4, and it will be introduced in the next ECMAScript standard, which is expected to be published in 2021.
You can use it now using the plugin-proposal-logical-assignment-operators Babel plugin. I have never used that plugin, so I have no idea how well it works.
If you're working with objects, you can use destructuring (since ES6) like so:
({ myLib: window.myLib = {} } = window);
...but you don't gain anything over the accepted answer except confusion.
As of 2021, you can use ||= with identical behavior to Ruby as long as you are transpiling or don't care about Opera/IE.
Logical OR assignement, ||= is now supported natively in javascript on all major browsers except Opera and IE. Current caniuse matrix. MDN reference.
Typescript added support for the operator in version 4. If you need to support IE/Opera you can use the babel plugin to transpile for broad compatibility.
Logical nullish assignment (??=)
x ??= 23
Documentation & Browser compatibility
Ruby's ||= operator short circuits assignment. It can be thought of like this:
return a || a = b
So in javascript, this looks very similar:
return a || (a = b);
It seems as pointed out in the comments below however, that this literal ruby form is less efficient than the standard javascript idiom a = a || b.
For reference:
http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html
You can achieve the desired behaviour using |= operator in javascript for integers only. But you have to define the variable first.
let a = 0
a |= 100
console.log(a) // 100
For objects
let o = {}
o.a |= 100
console.log(o) // {a: 100}
For Arrays
let arr = []
arr[0] |= 100
console.log(arr) // [100]

Javascript equivalent of Rails try method

In Rails I can do this:
x = user.try(:name)
this method returns nil if user is nil else user.name. Here name is a method defined on the user object.
I know it can be done using if..then..else in Javascript but is there an equivalent compact method to do the same in Javascript?
Googling points to Javascript's try command which is not what I am looking for.
You can use optional chaining
Examples:
// Access Properties
user?.name; // user might be null/undefined
user.name?.firstName // user will be available however name is not guaranteed.
// Access array values
addresses?.[index]; // array addresses might be undefined
// May be function??
user.getGeolocation?.(); // If the function exists execute it.
Slightly unrelated but something around handling of null/undefined is another feature called Nullish coalescing operator ??
// Example:
function foo(input) // some Array as input {
//.. Some stuff
return [input??[]].concat(bar); //if input is empty ignore and concat bar on an empty array and return.
}
//----
const defaultVal = 'someVal';
...
const val = this.someObj.prop1??defaultVal;
Below is the outdated solution prior to Optional chaining became native to Javascript:
You can do this way, as there is no built in way of doing that:
var x = (user || {}).name;
If user is not defined/null you will get undefined
If user is defined you will get the name property (which may be set or undefined).
This won't break the script if user is not defined (null).
But user variable has to be declared some where in the scope, even though its value is not defined. Otherwise you will get the err saying user is not defined.
Similarly if is in global scope then you can explicitly check for this variable as a property of global scope, to avoid the error as mentioned above
ex:
var x = (window.user || {}).name; // or var x = (global.user || {}).name;
For safe execution of functions,
var noop = function(){}; //Just a no operation function
(windowOrSomeObj.exec || noop)(); //Even if there is no property with the name `exec` exists in the object, it will still not fail and you can avoid a check. However this is just a truthy check so you may want to use it only if you are sure the property if exists on the object will be a function.
Optional Chaining Operator
Is a new proposal for ECMAScript.
It is in an early stage but we can start using it with babel.
This is the problem:
const person = {name: 'santiago'}
let zip = person.address.zip // Cannot read property 'zip' of undefined
This is how it works:
const person = {name: 'santiago'}
let zip = person?.address?.zip // undefined
To start using it we need babel alpha 7:
npm install --save-dev babel-cli#7.0.0-alpha.19
npm install --save-dev babel-plugin-transform-optional-chaining#^7.0.0-alpha.13.1
And we need to add the plugin to our .babelrc
{
"plugins": ["transform-optional-chaining"]
}
Adam Bene Medium Post which explains how to use it and another use cases
You can use logical AND (&&) operator. It works differently than in most of the languages because its result is not a boolean. For example:
const x = user && user.name;
The table below shows all possible outcomes of using this operator:
+--------------+-----------------------+
| user | x = user && user.name |
+--------------+-----------------------+
| undefined | undefined |
| null | null |
| {} | undefined |
| {name:''} | '' |
| {name:'Jon'} | 'Jon' |
+--------------+-----------------------+
Isn't that the same as what this gives you in Javascript:
user['name']
user.name
This returns undefined instead of nil but that's equivalent in most cases. I think the reason Rails needs the try method is because you cannot access instance variables unless they are made accessible.
To add to #PSL's approach, I usually do something like:
var x = user || {},
y = x.name || {},
z = y.first_name;
In Rails4, try does this:
Invokes the public method whose name goes as first argument just like public_send does, except that if the receiver does not respond to it the call returns nil rather than raising an exception.
In Rails3, try is like try! in Rails4 and that's the same as try except that it complains if the object doesn't understand the method you're trying to call. The original intent of try was to hide a bunch of nil checks so that you could say:
o.try(:m)
instead of
o.nil?? nil : o.m
The Rails4 version also hides a check if the object understands the method you want to call.
There's no special syntax for this in JavaScript but you can sweep the ugliness into a function.
The Rails4 version of try would look like this function in JavaScript:
function rtry(obj, m) {
if(obj == null)
return null;
if(typeof obj[m] === 'function')
return obj[m].apply(obj, [].slice.call(arguments, 2));
return null;
}
and you'd say things like x = rtry(obj, 'method_name', arg1, arg2, ...) and x would be null if obj didn't understand method_name (including if obj is null or undefined).
Demo: http://jsfiddle.net/ambiguous/BjgjL/
A Rails3 version is simple, that's just a null check:
function rtry(obj, m) {
if(obj == null)
return null;
return obj[m].apply(obj, [].slice.call(arguments, 2));
}
and JavaScript itself will raise an exception of obj doesn't have an m method. This version is equivalent to the "is it a function" version of CoffeeScript's ? existential operator.
Demo: http://jsfiddle.net/ambiguous/FQCS2/
As usual, things might not work out so well if you're dealing with native methods rather than methods that you've written in JavaScript. typeof (6).toString might be 'function' in one JavaScript environment but I don't think it is guaranteed to always be 'function' everywhere. The primary use (i.e. hide null and undefined checks) should work everywhere though.
I don't think so. Why not roll your own? Not exactly equivalent but does the job.
function tryMe(obj) {
return obj === null || obj === undefined ? null : obj;
}

Categories