JSLint “eval is evil.” alternatives

后端 未结 7 1347
别那么骄傲
别那么骄傲 2021-02-13 22:49

I am have some JavaScript functions that run on both the client (browser) and the server (within a Java Rhino context). These are small functions - basically little validators

相关标签:
7条回答
  • 2021-02-13 23:12

    I would avoid using eval in all situations. There's no reason you can't code around it. Instead of sending code to the client, just keep it hosted on the server in one contained script file.

    If that's not doable, you can also have a dynamically generated javascript file then pass in the necessary parameters via the response, and then dynamically load the script on the client side. There's really no reason to use eval.

    Hope that helps.

    0 讨论(0)
  • 2021-02-13 23:20

    DRY is definitely something I agree with, however there is a point where copy+pasting is more efficient and easy to maintain than referencing the same piece of code.

    The code you're saving yourself from writing seems to be equivalent to a clean interface, and simple boiler plate. If the same code is being used on both the server and the client, you could simply pass around the common pieces of the function, rather than the whole function.

    Payload:
    {
        "name": "phoneNumber",
        "type": "regexCheck",
        "checkData": "/^\\+?([0-9\\- \\(\\)])*$/"
    }
    
    if(payload.type === "regexCheck"){
        const result = validPhoneFormat(fullObject, value, payload.checkData)
    }
    
    function validPhoneFormat(fullObject, value, regexPattern) {
    
        if (value && value.length && !regexPattern.test(value))
            return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
        else
            return [];
    }
    

    This would give you the ability to update the regex from a single location. If the interface changes it does need to be updated in 2 places, but I wouldn't consider that a bad thing. If the client is running code, why hide the structure?

    If you really, really want to keep both the object structure and the patterns in one place - extract it to a single API. Have a "ValidatePhoneViaRegex" api endpoint which is called by all places you'd be passing this serialized function to.

    If all of this seems like too much effort, set jslint to ignore your piece of code:

    "In JSHint 1.0.0 and above you have the ability to ignore any warning with a special option syntax. The identifier of this warning is W061. This means you can tell JSHint to not issue this warning with the /*jshint -W061 */ directive.

    In ESLint the rule that generates this warning is named no-eval. You can disable it by setting it to 0, or enable it by setting it to 1."

    https://github.com/jamesallardice/jslint-error-explanations/blob/master/message-articles/eval.md

    I would prefer to see copy+pasted code, a common api, or receiving parameters and copy+pasted boiler plate than magical functions passed in from the server to be executed.

    What happens if you get a cross-browser compatibility error with one of these shared functions?

    0 讨论(0)
  • 2021-02-13 23:21

    I wouldn't worry about it since you are only passing these function strings from the server to the client, and are thus in control of what will be evaluated.

    On the other hand, if you were going the other direction and doing the evals of client-passed code on the server, that would be an entirely different story...

    Update:

    As disabling the validation option in your comment may cause you to miss future errors, I would instead suggest passing the function name rather than the entire function and have the function library mirrored on the server and client. Thus, to call the function, you'd use the following code:

    var policyFunction = YourLibraryName[this.policies[j].policyFunctionName];
    var policyArguments = this.policies[j].policyArguments;
    
    policyFunction.apply(this, policyArguments); 
    

    Update 2:

    I was able to validate the following code with JSLint successfully, which essentially allows you to "turn off" validation for the vast minority of cases where eval is appropriate. At the same time, JSLint still validates normal eval calls, and all uses of this method should throw up flags for future developers to avoid using it/refactor it out where possible/as time allows.

    var EVAL_IS_BAD__AVOID_THIS = eval;
    EVAL_IS_BAD__AVOID_THIS(<yourString>);
    
    0 讨论(0)
  • 2021-02-13 23:22

    With very little parsing you could have had it like so:

    var body = this.policies[j].policyFunction.substr;
    body = body.substr(body.indexOf("(") + 1);
    var arglist = body.substr(1, body.indexOf(")"));
    body = body.substr(arglist.length + 1);
    var policyFunction = new Function(arglist, body);
    

    Which would provide a bit of validation, avoid the literal use of eval and work synchronously with the code. But it is surely eval in disguise, and it is prone to XSS attack. If the malevolent person can get their code loaded and evaluated this way - it will not save you. So, really, just don't do it. Add a <script> tag with the proper URL and that would be certainly safer. Well, you know, better safe then sorry.

    PS. My apologises if the code above doesn't work, it only shows the intent, I've not tested it, and if I made a mistake at counting parenthesis or some such - well, you should get the idea, I'm not advertising it by any means.

    0 讨论(0)
  • 2021-02-13 23:26

    Well, the first thing to bear in mind is that jsLint does make the point that "it will hurt your feelings". It's designed to point out where you're not following best practices -- but code that isn't perfect can still work just fine; there's no compulsion upon you to follow jsLint's advice.

    Having said that, eval is evil, and in virtually all cases there is always a way around using it.

    In this case, you could use a library such as require.js, yepnope.js or some other library that is designed to load a script separately. This would allow you to include the javascript functions you need dynamically but without having to eval() them.

    There are probably several other solutions as well, but that was the first one that came to my mind.

    Hope that helps.

    0 讨论(0)
  • 2021-02-13 23:33

    You can use

    setInterval("code to be evaluated", 0);
    

    Internally, if you pass setInterval a string it performs a function similar to eval().

    However, I wouldn't worry about it. If you KNOW eval() is evil, and take appropriate precautions, it's not really a problem. Eval is similar to GoTo; you just have to be careful and aware of what you're doing to use them properly.

    0 讨论(0)
提交回复
热议问题