Skip to content

Commit

Permalink
205
Browse files Browse the repository at this point in the history
  • Loading branch information
ascoders committed Aug 9, 2021
1 parent e8ae855 commit 5962922
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 1 deletion.
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

前端界的好文精读,每周更新!

最新精读:<a href="./前沿技术/204.%E7%B2%BE%E8%AF%BB%E3%80%8A%E9%BB%98%E8%AE%A4%E3%80%81%E5%91%BD%E5%90%8D%E5%AF%BC%E5%87%BA%E7%9A%84%E5%8C%BA%E5%88%AB%E3%80%8B.md">204.精读《默认、命名导出的区别》</a>
最新精读:<a href="./前沿技术/205.%E7%B2%BE%E8%AF%BB%E3%80%8AJS%20with%20%E8%AF%AD%E6%B3%95%E3%80%8B.md">205.精读《JS with 语法》</a>

素材来源:[周刊参考池](https://github.com/ascoders/weekly/issues/2)

Expand Down Expand Up @@ -162,6 +162,7 @@
- <a href="./前沿技术/197.%E7%B2%BE%E8%AF%BB%E3%80%8A%E4%BD%8E%E4%BB%A3%E7%A0%81%E9%80%BB%E8%BE%91%E7%BC%96%E6%8E%92%E3%80%8B.md">197.精读《低代码逻辑编排》</a>
- <a href="./前沿技术/202.%E7%B2%BE%E8%AF%BB%E3%80%8AReact%2018%E3%80%8B.md">202.精读《React 18》</a>
- <a href="./前沿技术/204.%E7%B2%BE%E8%AF%BB%E3%80%8A%E9%BB%98%E8%AE%A4%E3%80%81%E5%91%BD%E5%90%8D%E5%AF%BC%E5%87%BA%E7%9A%84%E5%8C%BA%E5%88%AB%E3%80%8B.md">204.精读《默认、命名导出的区别》</a>
- <a href="./前沿技术/205.%E7%B2%BE%E8%AF%BB%E3%80%8AJS%20with%20%E8%AF%AD%E6%B3%95%E3%80%8B.md">205.精读《JS with 语法》</a>

### 设计模式

Expand Down
94 changes: 94 additions & 0 deletions 前沿技术/205.精读《JS with 语法》.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
with 是一个不推荐使用的语法,因为它的作用是改变上下文,而上下文环境对开发者影响很大。

本周通过 [JavaScript's Forgotten Keyword (with)](https://dev.to/mistval/javascript-s-forgotten-keyword-with-48id) 这篇文章介绍一下 with 的功能。

## 概述

下面是一种使用 with 的例子:

```javascript
with (console) {
log('I dont need the "console." part anymore!');
}
```

我们往上下文注入了 `console` 对象,而 `console.log` 这个属性就被注册到了这个 Scope 里。

再比如:

```javascript
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:

```javascript
with ({ myProperty: 'Hello world!' }) {
console.log(myProperty); // Logs "Hello world!"
}
```

那为什么不推荐使用 with 呢?比如下面的情况:

```javascript
function getAverage(min, max) {
with (Math) {
return round((min + max) / 2);
}
}

getAverage(1, 5);
```

注入的上下文可能与已有上下文产生冲突,导致输出结果为 `NaN`

所以业务代码中不推荐使用 with,而且实际上在 **严格模式** 下 with 也是被禁用的。

## 精读

由于 with 定义的上下文会优先查找,因此在前端沙盒领域是一种解决方案,具体做法是:

```javascript
const sandboxCode = `with(scope) { ${code} }`
new Function('scope', sandboxCode)
```

这样就把所有 scope 定义的对象限定住了。但如果访问 scope 外的对象还是会向上冒泡查找,我们可以结合 Proxy 来限制查找范围,这样就能完成一个可用性尚可的沙盒。

第二种 with 的用法是前端模版引擎。

我们经常看到模版引擎里会有一些 `forEach``map` 等特殊用法,这些语法完全可以通过 with 注入。当然并不是所有模版引擎都是这么实现的,还有另一种方案是,现将模版引擎解析为 AST,再根据 AST 构造并执行,如果把这个过程放到编译时,那么 JSX 就是一个例子。

最后关于 with 注入上下文,还有一个误区,那就是认为下面的代码仅仅注入了 `run` 属性:

```javascript
with ({ run: () => {} }) {
run()
}
```

其实不然,因为 with 会在整个原型链上查找,而 `{}` 的原型链是 `Object.prototype`,这就导致挂在了许多非预期的属性。

如果想要挂载一个纯净的对象,可以使用 `Object.create()` 创建对象挂载到 with 上。

## 总结

with 的使用场景很少,一般情况下不推荐使用。

如果你还有其他正经的 with 使用场景,可以告知我,或者给出评论。

> 讨论地址是:[精读《JS with 语法》· Issue #343 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/343)
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**

> 关注 **前端精读微信公众号**
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">

> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)

0 comments on commit 5962922

Please sign in to comment.