Alan Storm的评论是对我关于with
语句回答的回应,这让我开始思考。我很少找到使用这个特定语言功能的原因,并且从未考虑过它可能会引起麻烦。现在,我想知道如何有效地使用with
,同时避免其缺点。
你在哪里发现with
语句有用?
Alan Storm的评论是对我关于with
语句回答的回应,这让我开始思考。我很少找到使用这个特定语言功能的原因,并且从未考虑过它可能会引起麻烦。现在,我想知道如何有效地使用with
,同时避免其缺点。
你在哪里发现with
语句有用?
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();
}
with
。我敦促你查看他关于with
及其替代方案的博客文章这里。我真的不认为使用with比直接输入object.member更易读。我不认为它不易读,但我也不认为它更易读。
就像lassevk所说的那样,我肯定可以看出使用with比使用非常明确的“object.member”语法更容易出错。
with
关键字,但它只是在块内将this
(在CoffeeScript/Coco中也可写为@
)设置为目标对象。这消除了歧义并实现了ES5严格模式的兼容性:with long.object.reference
@a = 'foo'
bar = @b
我的
switch(e.type) {
case gapi.drive.realtime.ErrorType.TOKEN_REFRESH_REQUIRED: blah
case gapi.drive.realtime.ErrorType.CLIENT_ERROR: blah
case gapi.drive.realtime.ErrorType.NOT_FOUND: blah
}
boils down to
with(gapi.drive.realtime.ErrorType) {switch(e.type) {
case TOKEN_REFRESH_REQUIRED: blah
case CLIENT_ERROR: blah
case NOT_FOUND: blah
}}
你能相信如此低质量的代码吗?不,我们看到它完全无法阅读。这个例子无可否认地证明了,如果我理解得正确的话,就没有必要使用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等与主程序中的不同,我无法实现与这些全局对象完全兼容的module
和require
(因为我无法重构核心模块)。最终,我找到了 "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);
};
这个代理对象可以截获所有变量的搜索,并返回:“是的,我有那个变量。”如果这个代理对象实际上没有该变量,则将其值显示为undefined
。
通过这种方式,如果宏code
中使用var
语句定义了任何变量,我都可以在上下文对象(如vm模块)中找到它。但是使用let
或const
定义的变量仅在此时可用,并且不会保存在上下文对象中(vm模块保存它们,但不公开它们)。
性能: 这种方法的性能比vm.runInContext
更好。
安全性: 如果您想在沙盒中运行代码,这种方法不安全,您必须使用vm模块。它只提供一个新的命名空间。
with
在需要将对象结构从平面转换为分层时,与简写对象符号一起使用非常有用。因此,如果您有:
var a = {id: 123, name: 'abc', attr1: 'efg', attr2: 'zxvc', attr3: '4321'};
var b = {
id: a.id,
name: a.name
metadata: {name: a.name, attr1: a.attr1}
extrastuff: {attr2: a.attr2, attr3: a.attr3}
}
你可以简单地写:
with (a) {
var b = {
id,
name,
metadata: {name, attr1}
extrastuff: {attr2, attr3}
}
}
with
的一个好用法:基于存储在该对象中的值,向对象文字添加新元素。以下是我今天刚使用的示例:types.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");
在使用 require.js 时,您可以使用 with
来避免显式管理参数数量:
var modules = requirejs.declare([{
'App' : 'app/app'
}]);
require(modules.paths(), function() { with (modules.resolve(arguments)) {
App.run();
}});
requirejs.declare的实现:
requirejs.declare = function(dependencyPairs) {
var pair;
var dependencyKeys = [];
var dependencyValues = [];
for (var i=0, n=dependencyPairs.length; i<n; i++) {
pair = dependencyPairs[i];
for (var key in dependencyPairs[i]) {
dependencyKeys.push(key);
dependencyValues.push(pair[key]);
break;
}
};
return {
paths : function() {
return dependencyValues;
},
resolve : function(args) {
var modules = {};
for (var i=0, n=args.length; i<n; i++) {
modules[dependencyKeys[i]] = args[i];
}
return modules;
}
}
}
with
,所以这个东西已经不存在了。 - Thomas Aylott