Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得with语句在哪里有用?
Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得with语句在哪里有用?
当前回答
不推荐使用with,在ECMAScript 5严格模式下禁止使用。推荐的替代方法是将您想要访问其属性的对象分配给一个临时变量。
来源:Mozilla.org
其他回答
Visual Basic。NET有一个类似的With语句。我使用它的一个比较常见的方法是快速设置一些属性。而不是:
someObject.Foo = ''
someObject.Bar = ''
someObject.Baz = ''
,我可以这样写:
With someObject
.Foo = ''
.Bar = ''
.Baz = ''
End With
这不仅仅是懒惰的问题。它还使代码可读性更强。与JavaScript不同的是,它不会出现歧义,因为您必须在受语句影响的所有内容前加上a。(点)。所以,下面两个是明显不同的:
With someObject
.Foo = ''
End With
vs.
With someObject
Foo = ''
End With
前者是someObject.Foo;后者是someObject作用域外的Foo。
我发现JavaScript缺乏区分使得它远不如Visual Basic的变体有用,因为歧义的风险太高了。除此之外,with仍然是一个强大的想法,可以提高可读性。
我认为最明显的用途是作为捷径。例如,如果你初始化一个对象,你只需节省大量输入“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”时,这是一个更明显的快捷方式。但是还是。
CoffeeScript的Coco fork有一个with关键字,但它只是简单地将this(在CoffeeScript/Coco中也可以写成@)设置为块中的目标对象。这消除了歧义,实现了ES5严格模式兼容:
with long.object.reference
@a = 'foo'
bar = @b
正如Andy E在Shog9回答的评论中指出的那样,当with与对象文字一起使用时,会发生这种潜在的意想不到的行为:
for (var i = 0; i < 3; i++) {
function toString() {
return 'a';
}
with ({num: i}) {
setTimeout(function() { console.log(num); }, 10);
console.log(toString()); // prints "[object Object]"
}
}
并不是说意想不到的行为不是他的标志。
如果您仍然想使用这种技术,至少使用一个具有空原型的对象。
function scope(o) {
var ret = Object.create(null);
if (typeof o !== 'object') return ret;
Object.keys(o).forEach(function (key) {
ret[key] = o[key];
});
return ret;
}
for (var i = 0; i < 3; i++) {
function toString() {
return 'a';
}
with (scope({num: i})) {
setTimeout(function() { console.log(num); }, 10);
console.log(toString()); // prints "a"
}
}
但这只适用于ES5+。也不要用with。
我一直使用with语句作为范围导入的简单形式。假设您有某种标记构建器。而不是写:
markupbuilder.div(
markupbuilder.p('Hi! I am a paragraph!',
markupbuilder.span('I am a span inside a paragraph')
)
)
你可以这样写:
with(markupbuilder){
div(
p('Hi! I am a paragraph!',
span('I am a span inside a paragraph')
)
)
}
对于这个用例,我没有做任何赋值,所以我没有与之相关的歧义问题。