Skip to content

Commit 5962922

Browse files
committed
205
1 parent e8ae855 commit 5962922

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

readme.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

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

9-
最新精读:<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>
9+
最新精读:<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>
1010

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

@@ -162,6 +162,7 @@
162162
- <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>
163163
- <a href="./前沿技术/202.%E7%B2%BE%E8%AF%BB%E3%80%8AReact%2018%E3%80%8B.md">202.精读《React 18》</a>
164164
- <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>
165+
- <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>
165166

166167
### 设计模式
167168

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
with 是一个不推荐使用的语法,因为它的作用是改变上下文,而上下文环境对开发者影响很大。
2+
3+
本周通过 [JavaScript's Forgotten Keyword (with)](https://dev.to/mistval/javascript-s-forgotten-keyword-with-48id) 这篇文章介绍一下 with 的功能。
4+
5+
## 概述
6+
7+
下面是一种使用 with 的例子:
8+
9+
```javascript
10+
with (console) {
11+
log('I dont need the "console." part anymore!');
12+
}
13+
```
14+
15+
我们往上下文注入了 `console` 对象,而 `console.log` 这个属性就被注册到了这个 Scope 里。
16+
17+
再比如:
18+
19+
```javascript
20+
with (console) {
21+
with (['a', 'b', 'c']) {
22+
log(join('')); // writes "abc" to the console.
23+
}
24+
}
25+
```
26+
27+
通过嵌套,我们可以追加注入上下文。其中 `with (['a', 'b', 'c'])` 其实是把 `['a', 'b', 'c']` 的返回值对象注入到了上下文,而数组对象具有 `.join` 成员函数,所以可以直接调用 `join('')` 输出 `"abc"`
28+
29+
为了不让结果这么 Magic,建议以枚举方式申明要注入的 key:
30+
31+
```javascript
32+
with ({ myProperty: 'Hello world!' }) {
33+
console.log(myProperty); // Logs "Hello world!"
34+
}
35+
```
36+
37+
那为什么不推荐使用 with 呢?比如下面的情况:
38+
39+
```javascript
40+
function getAverage(min, max) {
41+
with (Math) {
42+
return round((min + max) / 2);
43+
}
44+
}
45+
46+
getAverage(1, 5);
47+
```
48+
49+
注入的上下文可能与已有上下文产生冲突,导致输出结果为 `NaN`
50+
51+
所以业务代码中不推荐使用 with,而且实际上在 **严格模式** 下 with 也是被禁用的。
52+
53+
## 精读
54+
55+
由于 with 定义的上下文会优先查找,因此在前端沙盒领域是一种解决方案,具体做法是:
56+
57+
```javascript
58+
const sandboxCode = `with(scope) { ${code} }`
59+
new Function('scope', sandboxCode)
60+
```
61+
62+
这样就把所有 scope 定义的对象限定住了。但如果访问 scope 外的对象还是会向上冒泡查找,我们可以结合 Proxy 来限制查找范围,这样就能完成一个可用性尚可的沙盒。
63+
64+
第二种 with 的用法是前端模版引擎。
65+
66+
我们经常看到模版引擎里会有一些 `forEach``map` 等特殊用法,这些语法完全可以通过 with 注入。当然并不是所有模版引擎都是这么实现的,还有另一种方案是,现将模版引擎解析为 AST,再根据 AST 构造并执行,如果把这个过程放到编译时,那么 JSX 就是一个例子。
67+
68+
最后关于 with 注入上下文,还有一个误区,那就是认为下面的代码仅仅注入了 `run` 属性:
69+
70+
```javascript
71+
with ({ run: () => {} }) {
72+
run()
73+
}
74+
```
75+
76+
其实不然,因为 with 会在整个原型链上查找,而 `{}` 的原型链是 `Object.prototype`,这就导致挂在了许多非预期的属性。
77+
78+
如果想要挂载一个纯净的对象,可以使用 `Object.create()` 创建对象挂载到 with 上。
79+
80+
## 总结
81+
82+
with 的使用场景很少,一般情况下不推荐使用。
83+
84+
如果你还有其他正经的 with 使用场景,可以告知我,或者给出评论。
85+
86+
> 讨论地址是:[精读《JS with 语法》· Issue #343 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/343)
87+
88+
**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。**
89+
90+
> 关注 **前端精读微信公众号**
91+
92+
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
93+
94+
> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)

0 commit comments

Comments
 (0)