Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。

你觉得with语句在哪里有用?


当前回答

实际上,我最近发现with语句非常有用。直到我开始了我目前的项目——一个用JavaScript编写的命令行控制台,我才真正意识到这个技术。我试图模拟Firebug/WebKit控制台api,其中特殊命令可以输入到控制台,但它们不会覆盖全局作用域中的任何变量。当我试图解决我在Shog9的精彩答案的评论中提到的一个问题时,我想到了这个。

为了达到这个效果,我使用了两个with语句将一个作用域“分层”到全局作用域后面:

with (consoleCommands) {
    with (window) {
        eval(expression); 
    }
}

这种技术的优点在于,除了性能方面的缺点外,它不会遭受with语句通常带来的恐惧,因为无论如何我们都是在全局作用域中求值——没有伪作用域之外的变量被修改的危险。

让我惊讶的是,当我设法找到在其他地方使用的相同技术时,我受到了启发,发布了这个答案——Chromium源代码!

InjectedScript._evaluateOn = function(evalFunction, object, expression) {
    InjectedScript._ensureCommandLineAPIInstalled();
    // Surround the expression in with statements to inject our command line API so that
    // the window object properties still take more precedent than our API functions.
    expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
    return evalFunction.call(object, expression);
}

编辑:刚刚检查了Firebug的源代码,它们将4条语句链接在一起,形成更多的层。疯了!

const evalScript = "with (__win__.__scope__.vars) { with (__win__.__scope__.api) { with (__win__.__scope__.userVars) { with (__win__) {" +
    "try {" +
        "__win__.__scope__.callback(eval(__win__.__scope__.expr));" +
    "} catch (exc) {" +
        "__win__.__scope__.callback(exc, true);" +
    "}" +
"}}}}";

其他回答

我认为最明显的用途是作为捷径。例如,如果你初始化一个对象,你只需节省大量输入“ObjectName”。有点像lisp的“带槽”,让你可以写

(with-slots (foo bar) objectname
   "some code that accesses foo and bar"

这和写作是一样的吗

"some code that accesses (slot-value objectname 'foo) and (slot-value objectname 'bar)""

当你的语言允许“Objectname”时,这是一个更明显的快捷方式。但是还是。

使用with还会使代码在许多实现中变慢,因为现在所有内容都被包装在一个额外的查找范围中。在JavaScript中使用with没有合理的理由。

不推荐使用with,在ECMAScript 5严格模式下禁止使用。推荐的替代方法是将您想要访问其属性的对象分配给一个临时变量。

来源:Mozilla.org

你可以定义一个小的帮助函数来提供with的好处,而不会产生歧义:

var with_ = function (obj, func) { func (obj); };

with_ (object_name_here, function (_)
{
    _.a = "foo";
    _.b = "bar";
});

我只是不明白使用with比直接输入object。member有什么更好读的地方。我不认为它的可读性有任何下降,但我也不认为它的可读性有任何提高。

就像lassevk说的,我可以肯定地看到使用with比使用非常显式的“object”更容易出错。成员”语法。