Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得with语句在哪里有用?
Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得with语句在哪里有用?
当前回答
是的,是的,是的。有一个非常合理的用法。看:
with (document.getElementById("blah").style) {
background = "black";
color = "blue";
border = "1px solid green";
}
基本上任何其他DOM或CSS钩子都是with的奇妙用途。这并不是说“CloneNode”将是未定义的,并返回到全局作用域,除非你走出你的方式,决定让它成为可能。
Crockford对速度的抱怨是with创建了一个新的上下文。上下文通常是昂贵的。我同意。但如果你只是创建了一个div,没有一些框架来设置你的css,需要手动设置15个左右的css属性,那么创建一个上下文可能会比创建变量和15个解引用更便宜:
var element = document.createElement("div"),
elementStyle = element.style;
elementStyle.fontWeight = "bold";
elementStyle.fontSize = "1.5em";
elementStyle.color = "#55d";
elementStyle.marginLeft = "2px";
等等……
其他回答
下面是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");
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语句对性能没有负面影响,但它减少了代码大小,这影响了移动设备上的内存使用。
你可以在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;
}
我认为在将模板语言转换为JavaScript时,with语句可以派上用场。例如base2中的JST,但我更经常看到它。
我同意不使用with语句就可以编程。但因为它不会带来任何问题,所以它是一种合法的使用。
我认为对象文字的使用很有趣,就像使用闭包的一个插入式替换
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
(function(info)
{
nodes[i].onclick = function(){ showStuff(info) };
})(data[i]);
}
或者与闭包等价的with语句
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
with({info: data[i]})
{
nodes[i].onclick = function(){ showStuff(info) };
}
}
我认为真正的风险是不小心操纵不属于with语句的变量,这就是为什么我喜欢将对象文字传递给with,你可以确切地看到它将在代码中添加的上下文中。