Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得with语句在哪里有用?
Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得with语句在哪里有用?
当前回答
with语句可用于减少代码大小或用于私有类成员,例如:
// 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();
如果你想要修改作用域,with语句是非常有用的,这对于拥有自己的全局作用域是必要的,可以在运行时操作。你可以在它上面放置常量或者某些常用的辅助函数,比如:“toUpper”,“toLower”或“isNumber”,“clipNumber”麻生..
关于糟糕的性能,我经常读到:作用域函数不会对性能产生任何影响,事实上,在我的FF中,有作用域的函数比无作用域的函数运行得更快:
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" );
所以在上面提到的方式中使用with语句对性能没有负面影响,但它减少了代码大小,这影响了移动设备上的内存使用。
其他回答
我认为在将模板语言转换为JavaScript时,with语句可以派上用场。例如base2中的JST,但我更经常看到它。
我同意不使用with语句就可以编程。但因为它不会带来任何问题,所以它是一种合法的使用。
你可以在W3schools http://www.w3schools.com/js/js_form_validation.asp上看到javascript表单的验证,其中对象表单被“扫描”,以找到名称为“email”的输入
但我已经修改了它,从任何形式的所有字段验证为不空,无论名称或数量的字段在一个形式。我只测试了文本字段。
但是with()使事情变得更简单。代码如下:
function validate_required(field)
{
with (field)
{
if (value==null||value=="")
{
alert('All fields are mandtory');return false;
}
else
{
return true;
}
}
}
function validate_form(thisform)
{
with (thisform)
{
for(fiie in elements){
if (validate_required(elements[fiie])==false){
elements[fiie].focus();
elements[fiie].style.border='1px solid red';
return false;
} else {elements[fiie].style.border='1px solid #7F9DB9';}
}
}
return false;
}
它很适合将在相对复杂的环境中运行的代码放入容器中:我使用它来为“窗口”创建本地绑定,从而运行用于web浏览器的代码。
我一直使用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')
)
)
}
对于这个用例,我没有做任何赋值,所以我没有与之相关的歧义问题。
下面是with的一个很好的用法:根据存储在Object中的值向Object Literal添加新元素。这是我今天用的一个例子:
我有一组可能使用的瓷砖(面向顶部、底部、左侧或右侧),我想快速添加一个瓷砖列表,在游戏开始时始终放置并锁定这些瓷砖。我不想一直输入类型。tbr用于列表中的每种类型,所以我只使用with。
Tile.types = (function(t,l,b,r) {
function j(a) { return a.join(' '); }
// all possible types
var types = {
br: j( [b,r]),
lbr: j([l,b,r]),
lb: j([l,b] ),
tbr: j([t,b,r]),
tbl: j([t,b,l]),
tlr: j([t,l,r]),
tr: j([t,r] ),
tl: j([t,l] ),
locked: []
};
// store starting (base/locked) tiles in types.locked
with( types ) { locked = [
br, lbr, lbr, lb,
tbr, tbr, lbr, tbl,
tbr, tlr, tbl, tbl,
tr, tlr, tlr, tl
] }
return types;
})("top","left","bottom","right");