JavaScript 中被遗忘的关键字(with)
目录
用法
“with”是什么意思?
不要使用它
在严格模式下禁止这样做
意外阴影
表现
排斥
结论
成为一名 JavaScript 开发人员是一份令人兴奋的工作。几乎每天你都会遇到一些神秘莫测、超乎寻常的事物。有时这是一种奇妙的体验,有时则令人毛骨悚然。
本文将探讨关键字“with”。它是编程语言中一个鲜为人知的角落,即使是经验丰富的开发者也常常对此一无所知。
用法
让我们使用with关键字来帮助我们向控制台记录消息:
with (console) {log('I dont need the "console." part anymore!');
} 让我们用它来帮助我们把数组连接成一个字符串:
with (console) {with (['a', 'b', 'c']) {log(join('')); // writes "abc" to the console.}
}
是的,朋友们,信不信由你,这就是 JavaScript。
“with”是什么意思?
以下是来自 MDN 的解释:
JavaScript 会通过搜索与包含该不限定名称的脚本或函数的执行上下文关联的作用域链来查找该名称。`with` 语句会在其语句体执行期间将给定对象添加到此作用域链的头部。如果语句体中使用的不限定名称与作用域链中的某个属性匹配,则该名称会绑定到该属性以及包含该属性的对象。否则,将抛出 `ReferenceError` 异常。
简单来说:当你在代码中编写一个标识符(例如log上面join的代码片段中的标识符)时,JavaScript 会检查一系列对象,如果其中一个对象具有与你在代码中编写的标识符同名的属性,则 JavaScript 会使用该属性的值。
该with关键字允许你将任意对象插入到该链的前端。以下示例或许能更清楚地说明这一点:
with ({ myProperty: 'Hello world!' }) {console.log(myProperty); // Logs "Hello world!"
} 不要使用它
很棒,对吧?嗯,也许未必。
在大多数情况下,只需使用临时变量即可达到同样的效果,自从解构出现以来,这比以往任何时候都更容易。
此外,MDN还列出了一些陷阱:
在严格模式下禁止这样做
您无法with在严格模式下使用。考虑到ES 模块和类默认处于严格模式,这一限制使得在许多现代用例中根本无法使用with。
意外阴影
以下代码用于计算两个数的平均值并将结果四舍五入为整数:
function getAverage(min, max) {with (Math) {return round((min + max) / 2);}
}getAverage(1, 5);
这将返回 NaN NaN。为什么?因为Math.min()`and`Math.max()会遮蔽函数的参数,所以我们最终计算的是两个函数的和,这当然是 NaN。
基本上,如果你使用 `this` with,就必须更加谨慎地选择标识符。你需要检查传递给 `this` 的参数,with确保它不包含可能无意中覆盖更高层级其他属性的属性。
这种行为也可能引入安全漏洞。如果攻击者能够向您传递的对象添加属性with,那么他们就可以篡改您的标识符,并以意想不到的方式修改您的代码行为。
例如,将从未经验证的 JSON HTTP 请求正文中解析出的对象传递出去with是极其危险的。
表现
通过向作用域链中添加内容,几乎每一行代码的运行速度都会变慢,因为需要搜索的对象数量会增加,才能将标识符解析为值。
排斥
如果你用那个with关键词,大家都会觉得你疯了,在餐厅里都会躲着你。或者他们只会用奇怪的眼神看你。
无论哪种方式,使用别人不知道的魔法语言特性都会使你的代码更难维护,而且在这种情况下,也不会给你带来多少好处。
结论
该with关键字为语言添加了一些有趣的功能,但最终它的缺点太多,优点太少,因此我无法推荐使用它。
当然,这并非我的一家之言。MDN似乎对此深恶痛绝,而且在严格模式下被禁止也是有原因的。
我写 JavaScript 已经超过五年了,但令我惊讶的是,直到今天我仍然会学到一些根本不陌生的语言关键字。还有什么其他东西可能隐藏在知识库里呢?
它从何而来with?是谁构想的?为什么?他们想要类似 C++ 命名空间的东西吗?是通灵板指示他们这么做的吗?
无论如何,这句早已被人遗忘的with话语似乎将永远被历史的尘埃掩埋。
虽然它和许多黑魔法一样,玩起来很有趣!
