JavaScript 的 “with” 语句是否有合法用途?
2022-08-29 23:33:05
艾伦·斯托姆(Alan Storm)在回应我关于与
声明的答案时的评论引起了我的思考。我很少找到使用这个特定语言功能的理由,也从未考虑过它如何引起麻烦。现在,我很好奇如何在避免陷阱的同时有效利用 。with
你在哪里发现这个声明有用?with
艾伦·斯托姆(Alan Storm)在回应我关于与
声明的答案时的评论引起了我的思考。我很少找到使用这个特定语言功能的理由,也从未考虑过它如何引起麻烦。现在,我很好奇如何在避免陷阱的同时有效利用 。with
你在哪里发现这个声明有用?with
今天我遇到了另一个用途,所以我兴奋地搜索了网络,发现了一个现有的提及:在块范围内定义变量。
尽管 JavaScript 表面上与 C 和 C++ 相似,但它并没有将变量的范围限定在它们所定义的块中:
var name = "Joe";
if ( true )
{
var name = "Jack";
}
// name now contains "Jack"
在循环中声明闭包是一项常见任务,这可能会导致错误:
for (var i=0; i<3; ++i)
{
var num = i;
setTimeout(function() { alert(num); }, 10);
}
由于 for 循环不会引入新作用域,因此所有三个函数都将共享相同的作用域(值为 )。num
2
let
with
随着 ES6 中语句的引入,在必要时引入新作用域以避免这些问题变得容易:let
// variables introduced in this statement
// are scoped to each iteration of the loop
for (let i=0; i<3; ++i)
{
setTimeout(function() { alert(i); }, 10);
}
甚至:
for (var i=0; i<3; ++i)
{
// variables introduced in this statement
// are scoped to the block containing it.
let num = i;
setTimeout(function() { alert(num); }, 10);
}
在ES6普遍可用之前,这种使用仍然仅限于愿意使用转译器的最新浏览器和开发人员。但是,我们可以使用以下方法轻松模拟此行为:with
for (var i=0; i<3; ++i)
{
// object members introduced in this statement
// are scoped to the block following it.
with ({num: i})
{
setTimeout(function() { alert(num); }, 10);
}
}
循环现在按预期工作,创建三个值介于 0 到 2 之间的独立变量。请注意,块内声明的变量的作用域不限于它,这与C++中块的行为不同(在C中,变量必须在块的开头声明,因此在某种程度上它是相似的)。这种行为实际上与早期版本的Mozilla浏览器中引入的let
block语法非常相似,但在其他地方并未被广泛采用。
我一直在使用 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')
)
)
}
对于这个用例,我没有做任何赋值,所以我没有与此相关的歧义问题。