Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得with语句在哪里有用?
Alan Storm对我关于with声明的回答的评论引起了我的思考。我很少找到使用这个特殊语言特性的理由,也从来没有想过它可能会带来什么麻烦。现在,我很好奇如何有效地利用with,同时避免它的陷阱。
你觉得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;
}
其他回答
对代理对象使用“with”语句
我最近想为babel写一个支持宏的插件。我想有一个单独的变量名称空间来保存我的宏变量,我可以在这个空间中运行我的宏代码。此外,我想检测宏代码中定义的新变量(因为它们是新的宏)。
首先,我选择了vm模块,但我发现vm模块中的全局变量,如Array, Object等与主程序不同,我无法实现模块并要求与该全局对象完全兼容(因为我无法重构核心模块)。最后,我找到了“with”语句。
const runInContext = function(code, context) {
context.global = context;
const proxyOfContext = new Proxy(context, { has: () => true });
let run = new Function(
"proxyOfContext",
`
with(proxyOfContext){
with(global){
${code}
}
}
`
);
return run(proxyOfContext);
};
这个代理对象捕获所有变量的搜索,并说:“yes, I have that variable.”如果代理对象实际上没有该变量,则将其值显示为undefined。
这样,如果在宏代码中使用var语句定义了任何变量,我可以在上下文对象中找到它(如vm模块)。但是用let或const定义的变量只在该时间内可用,不会保存在context对象中(vm模块保存它们,但不公开它们)。
性能:该方法性能优于vm.runInContext。
安全:如果你想在沙箱中运行代码,这在任何方面都不安全,你必须使用vm模块。它只提供一个新的名称空间。
我认为with的有用性取决于你的代码写得有多好。例如,如果你写的代码是这样的:
var sHeader = object.data.header.toString();
var sContent = object.data.content.toString();
var sFooter = object.data.footer.toString();
然后你可以这样说with可以提高代码的可读性:
var sHeader = null, sContent = null, sFooter = null;
with(object.data) {
sHeader = header.toString();
sContent = content.toString();
sFooter = content.toString();
}
相反,你可能会认为你违反了得墨忒耳定律,但是,话说回来,也许没有。我跑题了。
最重要的是,要知道Douglas Crockford建议不要使用with。我敦促你看看他的博客文章关于与它的替代品在这里。
只是想添加你可以得到“with()”功能与漂亮的语法和没有歧义与你自己的聪明的方法…
//utility function
function _with(context){
var ctx=context;
this.set=function(obj){
for(x in obj){
//should add hasOwnProperty(x) here
ctx[x]=obj[x];
}
}
return this.set;
}
//how calling it would look in code...
_with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)({
a:"letter a",
b:"letter b",
c:"letter c",
d:"letter a",
e:"letter b",
f:"letter c",
// continue through whole alphabet...
});//look how readable I am!!!!
..或者,如果你真的想使用"with()"而不带歧义和自定义方法,可以将它包装在匿名函数中并使用.call
//imagine a deeply nested object
//Hemisphere.Continent.Nation.Language.Dialect.Alphabet
(function(){
with(Hemisphere.Continent.Nation.Language.Dialect.Alphabet){
this.a="letter a";
this.b="letter b";
this.c="letter c";
this.d="letter a";
this.e="letter b";
this.f="letter c";
// continue through whole alphabet...
}
}).call(Hemisphere.Continent.Nation.Language.Dialect.Alphabet)
然而,正如其他人所指出的,这有点毫无意义,因为你可以做……
//imagine a deeply nested object Hemisphere.Continent.Nation.Language.Dialect.Alphabet
var ltr=Hemisphere.Continent.Nation.Language.Dialect.Alphabet
ltr.a="letter a";
ltr.b="letter b";
ltr.c="letter c";
ltr.d="letter a";
ltr.e="letter b";
ltr.f="letter c";
// continue through whole alphabet...
有使用Delphi的经验,我会说使用with应该是最后的大小优化方法,可能由某种javascript最小化算法执行,并访问静态代码分析以验证其安全性。
随意使用with语句可能会遇到范围问题,这是一个非常痛苦的问题,我不希望任何人经历调试会话来弄清楚他…,却发现它捕获了一个对象成员或错误的局部变量,而不是您期望的全局变量或外部作用域变量。
VB的with语句更好,因为它需要点来消除范围的歧义,但Delphi的with语句是一把上膛的枪,带有一发之机,在我看来,javascript的with语句与之相似,足以保证同样的警告。
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仍然是一个强大的想法,可以提高可读性。