Javascript equivalent of Rails try method

后端 未结 6 791
醉话见心
醉话见心 2021-02-05 01:56

In Rails I can do this:

 x = user.try(:name)

this method returns nil if user is nil else user.name

相关标签:
6条回答
  • 2021-02-05 02:12

    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

    0 讨论(0)
  • 2021-02-05 02:21

    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;
    
    0 讨论(0)
  • 2021-02-05 02:23

    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.
    
    0 讨论(0)
  • 2021-02-05 02:30

    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.

    0 讨论(0)
  • 2021-02-05 02:31

    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'                 |
    +--------------+-----------------------+
    
    0 讨论(0)
  • 2021-02-05 02:35

    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;
    }
    
    0 讨论(0)
提交回复
热议问题