精读《JS with 语法》
with 是一个不推荐使用的语法,因为它的作用是改变上下文,而上下文环境对开发者影响很大。
本周通过 JavaScript's Forgotten Keyword (with) 这篇文章介绍一下 with 的功能。
概述
下面是一种使用 with 的例子:
with (console) {
log('I dont need the "console." part anymore!');
}
【精读《JS with 语法》】我们往上下文注入了
console
对象,而 console.log
这个属性就被注册到了这个 Scope 里。再比如:
with (console) {
with (['a', 'b', 'c']) {
log(join(''));
// writes "abc" to the console.
}
}
通过嵌套,我们可以追加注入上下文。其中
with (['a', 'b', 'c'])
其实是把 ['a', 'b', 'c']
的返回值对象注入到了上下文,而数组对象具有 .join
成员函数,所以可以直接调用 join('')
输出 "abc"
。为了不让结果这么 Magic,建议以枚举方式申明要注入的 key:
with ({ myProperty: 'Hello world!' }) {
console.log(myProperty);
// Logs "Hello world!"
}
那为什么不推荐使用 with 呢?比如下面的情况:
function getAverage(min, max) {
with (Math) {
return round((min + max) / 2);
}
}getAverage(1, 5);
注入的上下文可能与已有上下文产生冲突,导致输出结果为
NaN
。所以业务代码中不推荐使用 with,而且实际上在 严格模式 下 with 也是被禁用的。
精读 由于 with 定义的上下文会优先查找,因此在前端沙盒领域是一种解决方案,具体做法是:
const sandboxCode = `with(scope) { ${code} }`
new Function('scope', sandboxCode)
这样就把所有 scope 定义的对象限定住了。但如果访问 scope 外的对象还是会向上冒泡查找,我们可以结合 Proxy 来限制查找范围,这样就能完成一个可用性尚可的沙盒。
第二种 with 的用法是前端模版引擎。
我们经常看到模版引擎里会有一些
forEach
、map
等特殊用法,这些语法完全可以通过 with 注入。当然并不是所有模版引擎都是这么实现的,还有另一种方案是,现将模版引擎解析为 AST,再根据 AST 构造并执行,如果把这个过程放到编译时,那么 JSX 就是一个例子。最后关于 with 注入上下文,还有一个误区,那就是认为下面的代码仅仅注入了
run
属性:with ({ run: () => {} }) {
run()
}
其实不然,因为 with 会在整个原型链上查找,而
{}
的原型链是 Object.prototype
,这就导致挂在了许多非预期的属性。如果想要挂载一个纯净的对象,可以使用
Object.create()
创建对象挂载到 with 上。总结 with 的使用场景很少,一般情况下不推荐使用。
如果你还有其他正经的 with 使用场景,可以告知我,或者给出评论。
讨论地址是: 精读《JS with 语法》· Issue #343 · dt-fe/weekly如果你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。
关注 前端精读微信公众号
文章图片
版权声明:自由转载-非商用-非衍生-保持署名( 创意共享 3.0 许可证)
推荐阅读
- 慢慢的美丽
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 《跨界歌手》:亲情永远比爱情更有泪点
- 诗歌:|诗歌: 《让我们举起世界杯,干了!》
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- 人间词话的智慧
- 《一代诗人》37期,生活,江南j,拨动心潭的一泓秋水
- 广角叙述|广角叙述 展众生群像——试析鲁迅《示众》的展示艺术
- 书评——《小行星》