In Rails I can do this:
x = user.try(:name)
this method returns nil
if user
is nil
else user.name
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
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;
You can do this way, as there is no built in way of doing that:
var x = (user || {}).name;
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.
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.
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' |
+--------------+-----------------------+
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;
}