Alan Storm的评论是对我关于with
语句回答的回应,这让我开始思考。我很少找到使用这个特定语言功能的原因,并且从未考虑过它可能会引起麻烦。现在,我想知道如何有效地使用with
,同时避免其缺点。
你在哪里发现with
语句有用?
Alan Storm的评论是对我关于with
语句回答的回应,这让我开始思考。我很少找到使用这个特定语言功能的原因,并且从未考虑过它可能会引起麻烦。现在,我想知道如何有效地使用with
,同时避免其缺点。
你在哪里发现with
语句有用?
我正在开发一个项目,允许用户上传代码以修改应用程序的部分行为。在这种情况下,我使用with
子句来防止他们修改我不想让他们乱搞的范围之外的任何内容。我用以下简化了的代码片段来实现这个功能:
// this code is only executed once
var localScope = {
build: undefined,
// this is where all of the values I want to hide go; the list is rather long
window: undefined,
console: undefined,
...
};
with(localScope) {
build = function(userCode) {
eval('var builtFunction = function(options) {' + userCode + '}');
return builtFunction;
}
}
var build = localScope.build;
delete localScope.build;
// this is how I use the build method
var userCode = 'return "Hello, World!";';
var userFunction = build(userCode);
这段代码(在某种程度上)确保用户定义的代码既不能访问任何全局作用域对象,如window
,也不能通过闭包访问我的任何本地变量。
顺便提醒一句,我仍然需要对用户提交的代码执行静态代码检查,以确保他们没有使用其他狡猾的方式来访问全局作用域。例如,以下用户定义的代码直接访问了window
:
test = function() {
return this.window
};
return test();
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]"
}
}
并不是意料之外的行为不是with
的标志。
如果你真的还想使用这种技术,至少使用一个原型为空的对象。
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()”功能...
//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...
with
,所以这个东西已经不存在了。 - Thomas Aylott