Are there legitimate uses for JavaScript's “with” statement?

后端 未结 30 1755
伪装坚强ぢ
伪装坚强ぢ 2020-11-22 04:22

Alan Storm\'s comments in response to my answer regarding the with statement got me thinking. I\'ve seldom found a reason to use this particular language feature, and had ne

相关标签:
30条回答
  • 2020-11-22 05:12

    I created a "merge" function which eliminates some of this ambiguity with the with statement:

    if (typeof Object.merge !== 'function') {
        Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
            for(var i in o2) { o1[i] = o2[i]; }
            return o1;
        };
    }
    

    I can use it similarly to with, but I can know it won't affect any scope which I don't intend for it to affect.

    Usage:

    var eDiv = document.createElement("div");
    var eHeader = Object.merge(eDiv.cloneNode(false), {className: "header", onclick: function(){ alert("Click!"); }});
    function NewObj() {
        Object.merge(this, {size: 4096, initDate: new Date()});
    }
    
    0 讨论(0)
  • 2020-11-22 05:12

    CoffeeScript's Coco fork has a with keyword, but it simply sets this (also writable as @ in CoffeeScript/Coco) to the target object within the block. This removes ambiguity and achieves ES5 strict mode compliance:

    with long.object.reference
      @a = 'foo'
      bar = @b
    
    0 讨论(0)
  • 2020-11-22 05:14

    As my previous comments indicated, I don't think you can use with safely no matter how tempting it might be in any given situation. Since the issue isn't directly covered here, I'll repeat it. Consider the following code

    user = {};
    someFunctionThatDoesStuffToUser(user);
    someOtherFunction(user);
    
    with(user){
        name = 'Bob';
        age  = 20;
    }
    

    Without carefully investigating those function calls, there's no way to tell what the state of your program will be after this code runs. If user.name was already set, it will now be Bob. If it wasn't set, the global name will be initialized or changed to Bob and the user object will remain without a name property.

    Bugs happen. If you use with you will eventually do this and increase the chances your program will fail. Worse, you may encounter working code that sets a global in the with block, either deliberately or through the author not knowing about this quirk of the construct. It's a lot like encountering fall through on a switch, you have no idea if the author intended this and there's no way to know if "fixing" the code will introduce a regression.

    Modern programming languages are chocked full of features. Some features, after years of use, are discovered to be bad, and should be avoided. Javascript's with is one of them.

    0 讨论(0)
  • 2020-11-22 05:14

    I don't ever use with, don't see a reason to, and don't recommend it.

    The problem with with is that it prevents numerous lexical optimizations an ECMAScript implementation can perform. Given the rise of fast JIT-based engines, this issue will probably become even more important in the near future.

    It might look like with allows for cleaner constructs (when, say, introducing a new scope instead of a common anonymous function wrapper or replacing verbose aliasing), but it's really not worth it. Besides a decreased performance, there's always a danger of assigning to a property of a wrong object (when property is not found on an object in injected scope) and perhaps erroneously introducing global variables. IIRC, latter issue is the one that motivated Crockford to recommend to avoid with.

    0 讨论(0)
  • 2020-11-22 05:15

    Yes, yes and yes. There is a very legitimate use. Watch:

    with (document.getElementById("blah").style) {
        background = "black";
        color = "blue";
        border = "1px solid green";
    }
    

    Basically any other DOM or CSS hooks are fantastic uses of with. It's not like "CloneNode" will be undefined and go back to the global scope unless you went out of your way and decided to make it possible.

    Crockford's speed complaint is that a new context is created by with. Contexts are generally expensive. I agree. But if you just created a div and don't have some framework on hand for setting your css and need to set up 15 or so CSS properties by hand, then creating a context will probably be cheaper then variable creation and 15 dereferences:

    var element = document.createElement("div"),
        elementStyle = element.style;
    
    elementStyle.fontWeight = "bold";
    elementStyle.fontSize = "1.5em";
    elementStyle.color = "#55d";
    elementStyle.marginLeft = "2px";
    

    etc...

    0 讨论(0)
  • 2020-11-22 05:15

    The with statement can be used to decrease the code size or for private class members, example:

    // demo class framework
    var Class= function(name, o) {
       var c=function(){};
       if( o.hasOwnProperty("constructor") ) {
           c= o.constructor;
       }
       delete o["constructor"];
       delete o["prototype"];
       c.prototype= {};
       for( var k in o ) c.prototype[k]= o[k];
       c.scope= Class.scope;
       c.scope.Class= c;
       c.Name= name;
       return c;
    }
    Class.newScope= function() {
        Class.scope= {};
        Class.scope.Scope= Class.scope;
        return Class.scope;
    }
    
    // create a new class
    with( Class.newScope() ) {
       window.Foo= Class("Foo",{
          test: function() {
              alert( Class.Name );
          }
       });
    }
    (new Foo()).test();
    

    The with-statement is very usefull if you want to modify the scope, what is necessary for having your own global scope that you can manipulate at runtime. You can put constants on it or certain helper functions often used like e.g. "toUpper", "toLower" or "isNumber", "clipNumber" aso..

    About the bad performance I read that often: Scoping a function won't have any impact on the performance, in fact in my FF a scoped function runs faster then an unscoped:

    var o={x: 5},r, fnRAW= function(a,b){ return a*b; }, fnScoped, s, e, i;
    with( o ) {
        fnScoped= function(a,b){ return a*b; };
    }
    
    s= Date.now();
    r= 0;
    for( i=0; i < 1000000; i++ ) {
        r+= fnRAW(i,i);
    }
    e= Date.now();
    console.log( (e-s)+"ms" );
    
    s= Date.now();
    r= 0;
    for( i=0; i < 1000000; i++ ) {
        r+= fnScoped(i,i);
    }
    e= Date.now();
    console.log( (e-s)+"ms" );
    

    So in the above mentioned way used the with-statement has no negative effect on performance, but a good one as it deceases the code size, what impacts the memory usage on mobile devices.

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