JavaScript with 语句的陷阱与替代方案

作者:半夏

时间:2026-10-27

浏览:420

本文深入解析JavaScript中with语句的使用机制及其潜在风险。通过具体测试案例,揭示在with块内修改对象属性时可能出现的数值不同步问题,指出其作为隐藏Bug的隐患。文章最后推荐通过创建局部变量引用父节点来替代with语句,从而保证代码的简洁性与数据一致性。

文章目录

with语句的引入与简化作用

熟悉Java和.NET开发的开发者对包或命名空间的概念应当不陌生,这一机制有效保障了代码的简洁性与可读性。JavaScript设计之初引入with语句,其初衷可能与上述概念有相似之处,旨在简化深层对象访问。例如:


代码如下:

 
apple.banana.candy.dog.egg.fog.god.huh.index = 0;
doSomething(apple.banana.candy.dog.egg.fog.god.huh.index);

借助with语句,上述代码可以简化为:


代码如下:

 
with(apple.banana.candy.dog.egg.fog.god.huh) {
c = 0;
doSomething(index);
} 

with语句的潜在缺陷测试

这种写法看似简洁优美,实则存在严重缺陷。接下来通过几个测试用例来验证其潜在问题。



1. 在 with 语句内部通过内部变量修改数值


代码如下:

 
var root = {
branch: {
node: 1
} 
}; 
with(root.branch) {
node = 0;
// 显示 0, 正确!
alert(node);
} 
// 显示 0, 正确!
alert(root.branch.node);

2. 在 with 语句内部通过对象节点修改数值


代码如下:

 
var root = {
branch: {
node: 1
} 
}; 
with(root.branch) {
root.branch.node = 0;
// 显示 0, 正确!
alert(node);
} 
// 显示 0, 正确!
alert(root.branch.node);

经过测试 1 和测试 2, 乍看没什么问题, 但是... 请看测试 3.



3. 在 with 语句内部通过对象父节点修改数值


代码如下:

 
var root = {
branch: {
node: 1
} 
}; 
with(root.branch) {
root.branch = {
node: 0
}; 
// 显示 1, 错误!
alert(node);
} 
// 显示 0, 正确!
alert(root.branch.node);

由上面的测试 3 可知, with 语句内部的节点父节点修改后, 不会同步到节点本身. 也就是说, 不能保证内外数值的一致性. 这是可能成为项目里面隐藏性很高的 bug.


替代方案:使用局部变量引用

那我们该怎么办呢? 接受那很长的一串逐级访问, 还是另有他法?



方法是有的. 我们可以通过别名引用父节点的方式来调用节点对象, 如:


代码如下:

 
var root = {
branch: {
node: 1
} 
}; 
var quote = root.branch;
quote.node = 0;
// 显示 0, 正确!
alert(root.branch.node);

我相信很少人会用 with 语句, 也不会有很多人知道这个关键字, 但我觉得这是个有问题的语句, 压根就不应该使用, 所以写个小文记录一下.

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章