ECMAScript 2020新增特性

ECMAScript 2020新特性

Jordan Harband提出的String.prototype.matchAll

String.prototype上的match()方法仅返回完全匹配,但是没有返回关于特定正则组的任意信息。感谢Jordan Harband关于String.prototype.matchAll的提案,可以返回比match()多很多的信息。返回的迭代器除了精确匹配外还给了我们访问所有的正则匹配捕获组。你还记得Gorkem Yakin和Daniel Ehrenberg添加到ECMAScript 2018的具名捕获组吗?matchAll()方法和此能很好的协调。通过下面例子来解释一下。

1
2
3
4
5
6
const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?<year>\d{4}).(?<month>\d{2}).(?<day>\d{2})/gu;
const results = text.match(regexp);

console.log(results);
// [ '2019.01.29', '2019.01.30' ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?<year>\d{4}).(?<month>\d{2}).(?<day>\d{2})/gu;
const results = Array.from(text.matchAll(regexp));

console.log(results);
// [
// [
// '2019.01.29',
// '2019',
// '01',
// '29',
// index: 5,
// input: 'From 2019.01.29 to 2019.01.30',
// groups: [Object: null prototype] { year: '2019', month: '01', day: '29' }
// ],
// [
// '2019.01.30',
// '2019',
// '01',
// '30',
// index: 19,
// input: 'From 2019.01.29 to 2019.01.30',
// groups: [Object: null prototype] { year: '2019', month: '01', day: '30' }
// ]
// ]

Domenic Denicola提出的import()

不同于ECMAScript 2015中介绍的静态模块,Domenic Denicola提案的动态导入可以实现按需加载。这个类似函数的格式(不是继承自Function .prototype)返回一个很强大的promise。使用场景比如: 按需导入,在一个脚本中计算模块名并加载执行变得可能。

1
2
3
4
5
const modulePage = 'page.js';
import(modulePage)
.then((module) => {
module.default();
});
1
2
3
4
5
(async () => {
const helpersModule = 'helpers.js';
const module = await import(helpersModule)
const total = module.sum(2, 2);
})();

Daniel Ehrenberg提出的BigInt-任意精度整数

感谢Daniel Ehrenberg, Number.MAX_SAFE_INTEGER不再是JavaScript中的一个限制。BigInt是一个能表示任意精度整数的新基础类型。你可以通过使用BigInt方法或者在一个数字后添加n后缀来把一个数字转换为一个新的bigint类型。

1
2
3
4
5
6
7
8
Number.MAX_SAFE_INTERGER
// 9007199254740991

Number.MAX_SAFE_INTEGER + 10 -10
// 9007199254740990 👎

BigInt(Number.MAX_SAFE_INTEGER) + 10n -10n
// 9007199254740991n 👍

Jason Williams, Robert Pamely and Mathias Bynens提出的Promise.allSettled

自从ECMAScript 2015以来,JavaScript仅支持两种promise组合: Promise.all()Promise.race()。感谢Jason Williams, Robert Pamely and Mathias Bynens,现在我们可以使用Promise.allSettled()。用这个方法来处理所有promise都解决时的场景(不管成功或失败)。看看下面的例子,并没有使用catch捕获异常!

1
2
3
4
5
Promise.allSettled([
fetch("https://api.github.com/users/pawelgrzybek").then(data => data.json()),
fetch("https://api.github.com/users/danjordan").then(data => data.json())
])
.then(result => console.log(`All profile settled`));

还有Promise.any()有潜力很快进入ECMAScript规范中,在文章“Promise组合解释”中介绍了相关内容。

Jordan Harband提出的globalThis

那么在JavaScript中什么是全局的this?是在浏览器中的window,在worker中的self,在Nodejs中的global或者其他… 这种混乱结束了!感谢Jordan Harband,我们现在可以使用globalThis关键字了。

Kevin Gibbons提出的for-in机制

ECMAScript遗留了一个关于for-in循环顺序的详细描述。感谢Kevin Gibbons所付出的努力,为for-in机制定义了一系列规则。(原文: Thanks to Kevin Gibbons who finally put some TLC and defined a set in stone set of rules for for-in mechanics.)

Gabriel Isenberg, Claude Pache and Dustin Savery提出的optional chaining

读取层次很深的对象属性时通常是容易出错并且对应代码也不易阅读。感谢Gabriel Isenberg, Claude Pache and Dustin Savery,这件事情现在变得简单了。如果你是一个TypeScript用户,那么你不会发现什么新的特性,因为在3.7版本中TypeScript已经实现了这个特性。喜欢!

1
2
3
4
5
// 之前
const title = data && data.article && data.article.title

// 现在
const title = data?.article?.title

Gabriel Isenberg 提出的空值联合

空值联合添加了一个新的短路原则操作符来处理默认值。Gabriel Isenberg做了很棒的工作。这个特性结合optional chanining特性使用。不同于||操作符,空值联合操作符??仅在左边的值为严格的nullundefined时起左右。

1
2
3
4
5
"" || "default value"
// default value

"" ?? "default value"
// ""
1
const title = data?.article?.title ?? "What's new in ECMAScript 2020"

Domenic Denicola提出的import.meta

Domenic Denicola提出的import.meta提案添加一个host相关的元数据对象到当前执行的模块中。

1
2
console.log(import.meta.url)
// file:///Users/pawelgrzybek/main.js

EXPORT * AS NS FROM “MOD”

这是一个添加到规范中的有用特性,可以让开发者导出其他模块命名空间下的对象到一个新的名称下。

1
export * as ns from "mod"

参考

React组件开发的十条最佳实践

原文地址: https://dev.to/selbekk/the-10-component-commandments-2a7f
译文地址: https://blog.bookcell.org/2020/03/22/the-10-react-component-best-practice/

译者备注: 这是一篇关于React组件开发最佳实践的文章,很值得一读,推荐有能力阅读英文的同学去读原文,翻译或多或少会丢失一些原意。

正文从这里开始:

创建被许多人使用的组件是困难的。尤其当组件的属性作为公开API的一部分,你不得不仔细考虑哪些属性应该接受。

这篇文章会快速介绍一些在API设计时的通用最佳实践,并且给出10条明确的最佳实践指导你创建让同事开发者喜欢使用的组件。

image

API是什么?

API或者应用程序接口(Application Programming Interface),主要是指两部分代码相遇的地方。这是你的代码和其他世界接触的地方。我们称这个接触表面为接口。这些是可交互的动作集合或者数据点。

介于前端和后端之间的接口就是一个API。你可以通过这个API访问一系列特定的数据和功能。

介于一个类和调用代码之间接口也是一个API。你可以在类上调用方法,来获取数据或者触发封装在其中的功能。

沿着这个思路,你的组件接受的属性也是其API。这是你的用户和组件交互的方式,因此当你决定暴露哪些属性时有很多类似的规则和考虑可以应用。

API设计的部分最佳实践

那么在设计一个API时有哪些规则和考虑可以应用?在这方面我们做了一些调查,并找到了许多极好的资源。我们挑选了两篇文章,Josh Tauberer“What Makes a Good API?”和Ron Kurir的同名文章,从中提取了4条最佳实践来遵循。

稳定的版本管理

当你在创建一个API时要考虑的最重要的一点是尽可能保持稳定。这意味着破坏性变更的次数很少。如果你有破坏性的变更,确保写一份详细的升级指南,并且如果可能,提供一个重构件(code-mod)来给用户自动化处理这些变更。

如果你发布了API,确保遵守语义化版本。这让用户更容易决定使用什么版本。

描述性的错误信息

任何调用API出错的时候,你都应该尽可能的解释什么地方出错,并告知如何修复。返回一个错误使用且没有任何其他提示的响应会让使用者感到羞愧,这不是一种好的用户体验。

相反,提供描述性的错误来帮助用户修复他们调用API的方式。

少让开发者感到惊讶

开发者是脆弱的人类,因此当他们使用API时不应该让他们感到惊讶。换句话说,尽可能让API更直观。这可以通过遵守最佳实践和命名规范来达到。

另外需要放在心上是保持你的代码一致性。如果你在一处地方给布尔型属性名称前面添加了ishas,而在另外一处忽略了,这会让其他人感到困惑。

最小化API接口

当我们谈到最小化的时候-同样要最小化你的API。更多的特性当然是好的,但是API接口暴露得越少,使用者学习的成本也更低。从而让用户认为这是一个易用的API。

有很多方式可以控制API的规模,其中一个就是从旧的中重构一个新的来。

组件开发的十条最佳实践

image

这4条黄金法则在REST API和Pascal语言程序中使用得很好,那么如何将他们拿到React的现代世界中来呢?

像我们前面提到的,组件也有自己的API。我们称做props,这是给组件传递数据、回调和其他功能的方式。我们如何组织props对象才能不破坏上面的规则?我们如何开发组件才能让其他开发者在使用组件时更便捷?

我们创建了开发组件时的10条不错的规则清单,希望对你有帮助。

1. 组件使用文档

如果组件没有提供如何使用的文档,那么显然组件是无用的。好吧,大多时候,使用者总是可以通过查看实现来了解如何使用,但那很少是最好的用户体验。

有很多方式可以给组件编写文档,从我们的角度想推荐3个选项:

前两个在你开发组件时可以提供一个playground用来试验,第3个提供了MDX来更自由的书写文档。(注:最新版本三者都已支持Markdown语法)

不管选择哪一个,确保提供API文档,及组件如何、何时使用相关的文档。后者在共享组件库中更为重要,那样人们才能在合适的位置使用正确的按钮或者布局。

2. 允许上下文的语义

译者注: 标题的原文是Allow for contextual semantics,中文翻译不好把握供参考

HTML是一门以语义化方式组织信息的语言。但是大多数的组件是由<div />标签组成的。这在某种程度上是讲得通的,因为通用组件不能假设是否应该是<article /><section />或者一个<aside />,但是这并不是理想。

相反,我们建议允许组件接受一个as属性,用以覆盖被渲染的DOM元素。下面是一个如何实现的例子:

1
2
3
4
5
6
7
function Grid({ as: Element, ...props }) {
return <Eelement className="grid" {...props} />
}

Grid.defaultProps = {
as: 'div',
};

我们将as属性重命名为一个本地的变量Element,并在JSX中使用。我们提供了一个通用的默认值,在你明确不需要传递更具语义化HTML标签的情况下使用。

当我们使用<Grid />组件时,你仅需要传递正确的标签:

1
2
3
4
5
6
7
function App() {
return (
<Grid as="main">
<MoreContent />
</Grid>
);
}

注意这在使用React组件时同样适用。一个很好的例子是,当你有一个<Button />组件想要渲染成React Router的<Link />组件时:

1
2
3
<Button as={Link} to="/profile">
Go to Profile
</Button>

3. 避免布尔型属性

布尔型属性听起来是个极好的主意。你可以不需要传值的情况下使用,这看起来很优雅:

1
<Button large>BUY NOW!</Button>

但是即使他们看起来很不错,单布尔属性只能允许两种可能性。开和关,显示和隐藏,1和0。

任何时候当你开始引入像尺寸、变形、颜色或其他任何像下面所列可能有两个之外的值,你就会有麻烦了。

1
2
3
<Button large small primary disabled secondary>
WHAT AM I??
</Button>

换句话说,布尔属性通常无法适应需求变更。因此,尝试使用字符串类型的枚举来作为属性,这样就有机会使用任何值而不是仅有两个值的选择。

1
2
3
<Button variant="primary" size="large">
I am primarily a large button
</Button>

这并不代表布尔值属性没有一点用武之地。当然是有的。上面列的disabled属性就应该是布尔型,因为在启用和禁用之间没有中间状态。保留他们作为真正的两个选项使用。

4. 使用props.children

React有一些与其他属性略有不同的特殊属性。一个是key,在列表项中被用来跟踪顺序,另一个是children

任何放置在组件开和闭标签间的内容都会被放在props.children属性中。因此,你应该尽可能经常使用。

原因是这样做比通过添加一个content属性或者其他专门类似文本简单值属性的方式要更加容易使用。

1
2
3
4
5
<TableCell content="Some text" />

// 对比

<TableCell>Some text</TableCell>

使用props.children有很多积极的意义。第一点,这有点类似平常HTML的工作方式。第二,你可以自由地传递任何你想要传的内容。不用添加leftIconrightIcon属性到你的组件中,仅仅只要传到props.children属性中即可。

1
2
3
<TableCell>
<ImportantIcon /> Some text
</TableCell>

你可能会争辩组件应该只允许接收并渲染普通文本,这在某些情况下可能是对的。至少现在,通过使用props.children,能实现一个适应未来需求变更的组件。

5. 让父组件接入内部逻辑

有时我们会创建有很多内部逻辑和状态的组件,例如自动补全的下拉组件或者交互式图表。

这些类型的组件通常都会涉及比较繁琐的接口,其中一个原因就是要支持后续的一系列覆盖和特殊使用场景。

如何能做到仅仅提供一个简单、标准化属性来让用户控制、响应或者覆盖默认组件行为呢?

Kent C.Dodds写了一篇关于“state reducers”概念的好文章,关于概念本身,和另外一篇如何用React Hooks实现

快速总结一下,这个模式通过传递一个“state reducer”函数给组件,从而让父组件可以访问任何在你的组件中派发的action。你可以改变状态,或者触发边界效应等。这是一个极好的实现高级定制的方式,而不用借助其他属性。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function MyCustomDropdown(props) {
const stateReducer = (state, action) => {
if (action.type === Dropdown.actions.CLOSE) {
buttonRef.current.focus();
}
};

return (
<>
<Dropdown stateReducer={stateReducer} {...props} />
<Button ref={buttonRef}>Open</Button>
</>
)
}

顺便说一下,你当然也可以创建更简单的方式来响应事件。上面的例子中提供一个onClose属性可能会更好的用户体验。保留好state reducer模式以备不时之需。

6. 展开剩余属性

任何时候当你创建一个新的组件时,确保展开剩余的属性到有意义的元素上。

你不需要持续添加那些原本在父组件或父元素上并会传递到组件上的属性到你的组件中。这会让你的API更稳定,并且不会因其他开发者需要一个新的事件监听或者arial标签而发布许多小的版本。

可以像下面这样做:

1
2
3
function ToolTip({ isVisivle, ...rest }) {
return isVisible ? <span role="tooltip" {...rest} /> : null;
}

任何时候你的组件传递一个属性到你的实现中,像一个类名或者一个onClick处理函数,确保外部的使用者同样可以做同样的事情。在类的情况,使用好用的classnames软件包来追加类名(或者使用字符串拼接)。

1
2
3
4
5
6
7
8
9
10
import classNames from 'classnames';

function ToolTip(props) {
return (
<span
{...prpos}
className={classNames('tooltip', props.className)}
/>
)
}

对于点击事件处理函数或者其他回调,通过一个辅助函数来组合一个单独的函数,这里有一种实现方式:

1
2
3
4
5
6
function combine(...functions) {
return (...args) =>
functions
.filter(func => typeof func === 'function')
.forEach(func => func(...args));
}

这里我们创建一个函数来接受一系列函数并组合,返回一个新的依次使用对应参数调用他们的回调函数。

你可以像这样使用:

1
2
3
4
5
6
7
8
9
10
11
function ToolTip(props) {
const [isVisible, setVisible] = React.useState(false);
return (
<span
{...props}
className={classNames('tooltip', props.className)}
onMouseIn={combile(() => setVisible(true), props.onMouseIn)}
onMouseOut={combile(() => setVisible(false), props.onMouseOut)}
/>
);
}

7. 设置足够的默认值

无论何时如果可以的话,确保给你的属性提供足够的默认值。这样做的话,可以最小化必须要传递的属性数量,并且这样能非常简化你的实现。

举一个onClick处理函数的例子。如果在你的代码中不强制要求,那么可以提供一个空函数作为默认属性。这样的话,你可以在代码中跟一直有传递对应属性一样调用。

另一个例子例如定制的输入。除非用户提供,否则的话假设输入的字符串是一个空字符串。这可以确保总是在处理一个字符串对象,而不是undefined或null。

8. 不要重命名HTML属性

HTML作为一门语言同样有其自己的属性,而这就是HTML元素自身的API。为什么不继续保持使用这个API呢?

就如我们之前提到的,最小化API接口暴露和保持某种程度的直观是两种改善组件API的极好方式。因此比起创建自己的screenReaderLabel属性,为何不直接使用HTML已经提供给你的aria-label呢?

因此不要为了自己的方便使用而去重命名既有的HTML属性。这样并不是用一个新的API来替换既存的API,而是在顶层添加一个自己的。人们通常还可以继续和你的screenReaderLabel属性一起传递aria-label,那么最终哪个才是该使用的呢?

再说一点,确保永远不要在组件中覆盖HTML属性。一个比较好的例子就是<button />元素的type属性,具有submit(默认)、button或者reset。然而,许多开发者倾向于把这个属性用于表示按钮的可视化类型(如primary, cta等等)。

属性他用之后,你必须要添加其他新的属性来覆盖表示type属性,这样会导致困惑、疑虑和让用户愤怒。

相信我,我一次又一次的犯了这个错误,我承认这真是一个狼狈的决定。

9. 属性类型定义

没有文档能比在代码中的文档更好的。React通过prop-types软件包提供了极好的方式来声明组件API。现在就开始使用吧。

你可以指定任意类型和形式的必选和可选属性,并可以通过JSDoc注释来改善。

如果你忽略了一个必选的属性,或者传递一个无效、非期望的值,那么你会在控制台中得到运行时警告。这对开发来讲是极好的,并可以在生产打包时被删掉。

如果你是通过TypeScript或Flow来开发React应用,那么你可以通过语言特性获得这种API文档。这可以获得更好的工具支持,和更好的用户体验。

如果你自己没有使用具有类型的JavaScript,那么你应该始终考虑给你的用户提供类型定义。这样,他们在使用你的组件时会更加容易。

10. 为开发者设计

最后,最重要的一个规则。确保你的API和组件体验是为那些将会使用的人优化的–你的同事开发者。

一种改善开发者体验的方式是为不合理使用提供足够的错误信息,并在有更好的方式使用组件的情况下提供仅在开发环境的警告。

当在提供错误和警告时,尽量通过链接引用你的文档或者提供简单的代码示例。让用户越快找到错误并修复,这会让用户感到你的组件越好用。

事实证明,这些冗长的错误和警告并不会影响最终打包的大小。感谢无用代码精简的帮助,在构建生产包的时候这些文本和错误的代码都会被移除。

在这方面做得非常好的一个库就是React本身。任何时候当你忘记在列表项中指定一个key时,或者拼错一个生命周期函数,忘记继承正确的基类或者用不正确的方式调用hook时,你会在控制台中得到大量的错误信息。为什么你的组件使用人员要期望的更少呢?

因此为你的未来用户设计,为5周后的你自己设计,为当你离开后必须要接手维护你代码的可怜家伙设计!为开发者设计。

总结

从经典的API设计中我们可以学到许多很好的建议。通过遵循文中的建议、技巧、规则和最佳实践,你应该可以创建简单易用,容易维护,直观并在需要的时候非常灵活的组件。

那么你在创建一个出色的组件时有哪些最喜欢的建议?

如何阅读一本书-笔记

笔记浓缩《如何阅读一本书》的精华,方便大家学习到阅读的要点。

阅读的目标与艺术

阅读的目标:为获得资讯而读,以及为求得理解而读

阅读的艺术: 这是一个凭借着头脑运作,除了玩味读物中的一些字句之外,不假任何外助,以一己之力来提升自我的过程。

阅读的层次

大多数人,即使是许多优秀的阅读者,都忽略了检视阅读的价值。他们打开一本书,从第一页开始读起,孜孜不倦,甚至连目录都不看一眼。因此,他们在只需要粗浅翻阅一本书的时候,却拿出了仔细阅读、理解一本书的时间。这就加重了阅读的困难。第三种层次的阅读,我们称之为分析阅读(analytical reading)。

检视阅读

检视阅读一:有系统的略读或粗读

略读或粗读是检视阅读的第一个子层次。你脑中的目标是要发现这本书值不值得多花时间仔细阅读。其次,就算你决定了不再多花时间仔细阅读这本书,略读也能告诉你许多跟这本书有关的事。

略读的建议:

  1. 先看书名页,然后如果有序就先看序。
  2. 研究目录页,对这本书的基本架构做概括性的理解。
  3. 如果书中附有索引,也要检阅一下——大多数论说类的书籍都会有索引。
  4. 如果那是本包着书衣的新书,不妨读一下出版者的介绍。
  5. 从你对一本书的目录很概略,甚至有点模糊的印象当中,开始挑几个看来跟主题息息相关的篇章来看。
  6. 最后一步,把书打开来,东翻翻西翻翻,念个一两段,有时候连续读几页,但不要太多。

检视阅读二:粗浅的阅读

头一次面对一本难读的书的时候,从头到尾先读完一遍,碰到不懂的地方不要停下来查询或思索。

阅读的速度

所谓阅读速度,理想上来说,不只是要能读得快,还要能用不同的速度来阅读——要知道什么时候用什么样的速度是恰当的。

略读或粗读一本书总是个好主意。尤其当你并不清楚手边的一本书是否值得细心阅读时(经常发生这种情况),必须先略读一下。略读过后,你就会很清楚了。一般来说,就算你想要仔细阅读的书也要先略读一下,从基本架构上先找到一些想法。

如何做一个自我要求的读者

主动的阅读基础:一个阅读者要提出的四个基本问题

你在阅读时要提出问题来—在阅读的过程中,你自己必须尝试去回答的问题。

  1. 整体来说,这本书到底在谈些什么?你一定要想办法找出这本书的主题,作者如何依次发展这个主题,如何逐步从核心主题分解出从属的关键议题来。
  2. 作者细说了什么,怎么说的?你一定要想办法找出主要的想法、声明与论点。这些组合成作者想要传达的特殊讯息。
  3. 这本书说得有道理吗?是全部有道理,还是部分有道理?
  4. 这本书跟你有什么关系?

任何一种超越基础阅读的阅读层次,核心就在你要努力提出问题(然后尽你可能地找出答案)。

如何让一本书真正属于你自己

要真正完全拥有一本书,必须把这本书变成你自己的一部分才行,而要让你成为书的一部分最好的方法——书成为你的一部分和你成为书的一部分是同一件事——就是要去写下来。

做笔记和标记的方法:

  1. 画底线——在主要的重点,或重要又有力量的句子下画线。
  2. 在画底线处的栏外再加画一道线——把你已经画线的部分再强调一遍,或是某一段很重要,但要画底线太长了,便在这一整段外加上一个记号。
  3. 在空白处做星号或其他符号——要慎用,只用来强调书中十来个最重要的声明或段落即可。你可能想要将做过这样记号的地方每页折一个角,或是夹一张书签。
  4. 在空白处编号——作者的某个论点发展出一连串的重要陈述时,可以做顺序编号。
  5. 在空白处记下其他的页码——强调作者在书中其他部分也有过同样的论点,或相关的要点,或是与此处观点不同的地方。
  6. 将关键字或句子圈出来——这跟画底线是同样的功能。
  7. 在书页的空白处做笔记——在阅读某一章节时,你可能会有些问题(或答案),在空白处记下来,这样可以帮你回想起你的问题或答案。

你读完一本书,在最后的空白页写下个人的索引后,再翻回前面的空白页,试着将全书的大纲写出来,用不着一页一页或一个重点一个重点地写(你已经在书后的空白页做过这件事了),试着将全书的整体架构写出来,列出基本的大纲与前后篇章秩序。

在检视阅读中,要回答的问题是:第一,这是什么样的一本书?第二,整本书在谈的是什么?第三,作者是借着怎样的整体架构,来发展他的观点或陈述他对这个主题的理解?

要做这些笔记最好的地方是目录页,或是书名页,这些是我们前面所提的笔记方式中没有用到的页数。

分析阅读

分析阅读的三阶段

一、分析阅读的第一阶段:找出一本书在谈些什么的规则

  1. 依照书的种类与主题来分类。
  2. 使用最简短的文字说明整本书在谈些什么。
  3. 将主要部分按顺序与关联性列举出来。将全书的大纲列举出来,并将各个部分的大纲也列出来。
  4. 确定作者想要解决的问题。

二、分析阅读的第二阶段:诠释一本书的内容规则

  1. 诠释作者的关键字,与他达成共识。
  2. 由最重要的句子中,抓住作者的重要主旨。
  3. 知道作者的论述是什么,从内容中找出相关的句子,再重新架构出来。
  4. 确定作者已经解决了哪些问题,还有哪些是没解决的。再判断哪些是作者知道他没解决的问题。

三、分析阅读的第三阶段:像是沟通知识一样地评论一本书的规则

A.智慧礼节的一般规则

  1. 除非你已经完成大纲架构,也能诠释整本书了,否则不要轻易批评。(在你说出:“我读懂了 !” 之前,不要说你同意、不同意或暂缓评论。)
  2. 不要争强好胜,非辩到底不可。
  3. 在说出评论之前,你要能证明自己区别得出真正的知识与个人观点的不同。

B.批评观点的特别标准

  1. 证明作者的知识不足。
  2. 证明作者的知识错误。
  3. 证明作者不合逻辑。
  4. 证明作者的分析与理由是不完整的。

主题阅读

TBD


笔记变更记录

初版 2020.1.30

2019年的总结

即将步入而立之年,回望2019年,工作上有些许波动也在稳步前进,宝宝也在逐步成长,家庭今年和谐相处,整体上来看还不错,也还有很多要努力提高的地方,希望2020年继续前进。

工作

年初从爱云出来,到了苏宁短暂停留,中间歇了将近两个月,最终到了华为,过程稍显折腾,结果倒也令人满意,遇到一群很不错的小伙伴。

在爱云待了将近三年,从零参与了物联网使能平台前端的搭建和成长,再到卖出第一单,技术支持,从中能够体会到创业的艰辛,也能体会到成功的喜悦,虽然物联网的道路还很漫长,我也还是相信物联网会给我们带来很多便利。在这里,老板的人格魅力是无穷的,同事们的氛围也很融洽,一起打羽毛球,一起讨论技术。

在苏宁,原本以为会在一个新项目中,中间发生一些变动,实际上到了易购的一个部门,遇到了朱总,很有趣的一个兄弟,在这里也学到了不少东西。到这里也是临时顶上去做营销活动的项目,赶着项目上线也是比较辛苦的,最终项目安稳上线,也算是一点安慰。最终,个人感觉不太能接受这边的企业文化,选择了离开。

休息期间,看了南京的不少互联网企业,较多的是创业公司,本来打算要去一家创业公司的前端架构组的,机缘巧合,华为这边也联系了面试,面下来感觉还不错,结果就到了现在这边,主要负责前端的业务开发,也会兼顾一些前端新技术的分享和工程化。

总结毕业之后的工作历程,每一次的更换都是一种成长,对应的是自己对未来方向的选择。从一开始的迷茫,到逐渐发现自己想要走的技术方向,一步一步都有很多付出和有这相应的收获。现阶段的目标,沿着前端这个方向继续深入,深度掌握JS语言(阅读和理解ECMAScript Spec)的同时,兼顾工程化的调研,同时补充自己的CS基础知识(2020年的一个阅读目标是精读SICP)。

生活

宝宝今年不知不觉两周岁了,从年初刚学会走路,到现在可以跑过来跑过去的一个大宝宝。接下来,让他在愉快玩耍的童年里,也要学点东西,我想让他学点古文(四书五经、阳明心学)、简单的英语和数学。

年中和老婆实现了一趟日本自由行,通过之前刚毕业时候学的日语,基本能用在购物和问路上面。玩过之后,觉得日本是个不错的地方,能够发展强大,确实有其过人之处,尤其在文化传承上,值得我们的学习。另外,对于环境生态的保护做得也很好。

这一年,在健身方面的投入较少,工作的的更换是其中一个原因,更多的是自己的原因。接下来一年,要更多关注锻炼健身,保持坚持。饮食上坚持多吃面食,遵循苏东坡先生的方法“已饥而食,未饱先止”,今年着实吃了很多馒头和饺子,作为一个南方人,吃北方人喜欢吃的面食也是不错的。

精神

自从接触了阳明心学,觉得一步步在深入儒家之路,去年读了《传习录》,因为其中涉及很多四书五经的引用讨论,今年接着在读《论语》,读的是李泽厚先生的《论语今读》,属于译注,包括翻译和注解,方便理解。12月份,听了南京师范大学郦波教授的《五百年来王阳明》,加深了之前对阳明心学的认识,不过认识的程度还远远不够,因此2020年的另一个阅读目标,准备读一读《华杉读透王阳明<传习录>》并结合着阅读《王阳明全集》。

针对阳明先生的几个理论,值得在生活工作中不断的练习和领悟。

“心即理、心外无物”、“知行合一”、“致良知”。

另外一个收获,读了二战期间奥地利的一个心理医生弗兰克尔写的《活出生命的意义》,作者是一名被德国人关押在集中营的犹太人,九死一生最终解放集中营后逃出并写出来自己的经历感悟和一种心理治疗方法。其中,提到的什么是生命的意义,我个人颇为赞同:

  1. 生活的苦难
  2. 亲情、爱情、友情
  3. 艺术和创作

我们都可以在这其中找到自己生命的意义。

心理学的经典著作对个人的帮助确实很大,之前在《少有人走的路》里,作者提出了一个观点,每一个人或多或少都有一些心理上的问题,在于自己愿不愿意去承认罢了,新的一年,我还是给自己准备了一个《自卑与超越》的心理学书籍,作者是和弗兰克尔同时代的一个著名心理学家阿德勒,值得期待。


临近新的一年,希望接下来一年工作顺利、家里人身体棒棒、和谐相处。

2019.12.31

2020年的计划阅读书单

基于2019年的阅读进度,2020年计划阅读20本,不再按照季度平均分配,根据阅读书籍的难易和厚度分配时间。

方法

  • 【略读】
  • 【精读】
  • 【主题阅读】

技术

  • 【精读】《你不知道的JavaScript下卷》
  • 【精读】《计算机程序的构造和解释》
  • 【主题阅读】《ECMAScript Spec 2019》
  • 【精读】《计算机网络》Andrew S.Tanenbaum 著 潘爱民 译
  • 【精读】《代码整洁之道》[美]Robert C. Martin
  • 【精读】《重构: 改善既有代码的设计》第2版 Martin Fowler

文学

  • 【略读】《三体》刘慈欣
  • 【略读】《伊利亚特》荷马
  • 【略读】《王阳明全集》
  • 【主题阅读】《华杉讲透王阳明《传习录》》华杉

经济

  • 【略读】《思考致富》拿破仑·希尔

传记

  • 【略读】《我的世界观》爱因斯坦
  • 【略读】《爱因斯坦传》艾萨克森

历史

  • 【略读】《显微镜下的大明》马伯庸

政治

  • 【略读】《自由的阶梯:美国文明札记》
  • 【略读】《自由的基因:自由主义的历史变迁》
  • 【略读】《自由的刻度:缔造美利坚的40篇经典文献》

心理学

  • 【略读】《自卑与超越》阿德勒
  • 【略读】《自控力》 kelly McGonigal

其他

  • 【略读】《你的灯亮着吗——发现问题所在》 康纳德.高斯 杰拉尔德.温伯格 著 俞月圆 译
  • 【略读】《Thinking, Fast and Slow》 by Daniel Kahneman

2019年的阅读总结

这是下半年去的培荣书屋,汪涵给他父亲开的一家书店

2019年共阅读了23本书,年初计划的24本书中,尚有13本未读完,期间也读了一些非计划内的书。因此2020年准备计划阅读的书单会减少一些数量,并且会更注重精读的质量。

个人比较推荐的有弗兰克尔的《活出生命的意义》、乔治奥威尔的《1984》和《动物农场》、还有吴军的《见识》。

书籍短评

下面是阅读过的书籍短评:

《Web前端开发修炼之道》

  • 阅读时间 2018.12.15~2019.1.3
  • 心得: 前端前辈的心得,部分技术已经过时,有一些思想还可借鉴。前端已经从jQuery时代,进入React/Vue/Angular时代。

《异类-不一样的成功启示录》by 马尔科姆·格拉德威尔

  • 阅读时间 2018.12.20~2019.1.4
  • 心得: 书中提到成功有几方面的因素,10000小时的练习、机遇、文化背景,其中机遇是影响最重大的一个因素,所谓时势造英雄。

《失控》by KK

  • 阅读时间 2018~2019.1.16
  • 心得: 一本巨大的作品,涉及的知识面很广,富有前瞻性,谈到了许多人类的未来可能。其中有两点,我觉得比较有意思,一个是构建生态系统;另一个是生物特性和人工智能的结合。

《CSS禅意花园》by Shea Dove

  • 阅读时间 2018.12 ~.2019.1.28
  • 心得:大概的翻了一遍,书中罗列了几十种实现禅意花园的CSS方案,点出其中的设计思路和难点、注意点,面向的读者更偏向设计人员。

《生命之书》

  • 阅读时间 2018.12~2019.1.30
  • 心得: 有关人生哲学的一本书,比较深奥,有点佛学的味道。

《未来世界的幸存者》阮一峰

  • 阅读时间 2019.2.11~2019.1.13
  • 心得: 讲述技术带来的冲击以及有关职业人生的未来思考,值得一看。

《活出生命的意义》弗兰克尔

  • 阅读时间: 2019.3.6~2019.3.8
  • 心得: 从二战德国集中营幸存下来的心理医生弗兰克尔讲述自身经历,并提出心理学“意义疗法”,寻找到生命的意义是活下去的根本。

《穷查理宝典》查理芒格

  • 阅读时间: 2019.2.1~2019.3.12
  • 心得: 收录查理芒格的演讲稿及他的一些思考,印象深刻的是他对终身学习重要性的强调,以及对普世智慧的见解。

《JavaScript语言精粹》道格拉斯·克劳福德

  • 阅读时间: 2019.2.15~2019.3.17
  • 心得: 大师利用浓缩式的方式讲述JS语言的知识点,并列举了语言的精华和糟粕,主要针对ES3标准。

《你不知道的JavaScript 上卷和中卷》

  • 阅读时间: 2019.3.18~2019.4.18
  • 心得: 深度讲解作用域、this、继承、原型链,值得再细读一遍。讲解比较深入,但是个人感觉,没有红宝书的作者扎卡斯写的容易理解。

《1984》乔治奥威尔

  • 阅读时间: 2019.4.10~2019.4.20
  • 心得:
    奥威尔在1948年描绘1984年未来世界中极权主义下的生活,发人深省,以及对于自由的追求。

《动物农场》乔治奥威尔

  • 心得: 讲述一个关于极权统治的童话故事

《如何不为钱发愁》

  • 时间:2019.5.15-2019.6.2
  • 心得: 干货不多,主要从哲学角度分析财务问题,主要的理解在于欲望与实际需求的一种平衡。

《如何用一年的时间获得10年的经验》郝培强

  • 时间: 2019.6.10-2019.7.12
  • 心得: 主要是作者的一些思考,关键的一些观点,多读书,注意做事的方法,大神其实没有什么特殊的只是比你多做了一点努力,执行力要强。

《软技能》

  • 时间:2019.6~2019.7.22
  • 心得: 作者讲述了包括自我营销、学习方法、工作方法、健身、理财、调整心态等各方面的知识,更像是一个过来人给你传授经验,有一些方法是值得学习的。

《Web前端开发最佳实践》

  • 时间:2019.5.15-2019.7.22
  • 心得: 主要是前端开发中的一下经验之谈,有一些方法可以参考,也有一些技术已经过时了,参考价值不是很大。

《清醒思考的艺术》罗尔夫•多贝里

  • 时间:2019.7.5~2019.8.10
  • 心得: 作者提出了日常生活中多个方面存在的思维误区,不时的回顾一下这些思维误区,能够让我们少犯错误。

《哲学简史》冯友兰

  • 时间:2019.6.16~2019.8.20
  • 心得: 讲述先秦时期的哲学各家,涉及儒家、佛家、道家、法家、阴阳家等,以及近现代的理学、心学等,是了解中国哲学史的一本好书,概览全貌。

《下一个倒下的会不会是华为》

  • 时间:2019.8.24-2019.8.31
  • 心得: 讲述了华为的核心价值观,华为成长起来过程中遭遇的变革和突破,以及任正非的思考和决策。从赞许和批判的角度均有涉及,相对比较客观。华为核心价值观,以客户为中心,以奋斗者为本,长期坚持艰苦奋斗。

《价值为纲》

  • 时间:2019.8.30~2019.8.31
  • 心得: 主要讲述华为的财务政策。

《见识》吴军

  • 时间: 2019.9.6~2019.10.6
  • 心得: 讲述作者对于人生各方面的经验和看法,对于年轻人有一定的参考意义,值得多看几遍。

《论语今读》李泽厚

  • 时间:2019.1.1~2019.12.9
  • 心得: 对论语的解读,包括翻译和注解,有引经据典的说明,也有个人的见解,帮助理解论语。论语是孔子及弟子的言语记录,表达对于为人处事的方法,从现在看来,依然值得一读,根据这次的阅读体验,阅读古文经典,还是应该找一本名家注解版阅读比较好理解,最好是大家认可度比较高的注解版本。

《习惯的力量》

  • 时间: 2019.12.1~2019.12.29
  • 心得: 通过许多实例讲述习惯的形成和改变,主要涉及一个循环,惯常行为-暗示-奖励,学会习惯背后的规律,有助于改善旧的习惯,养成新的好习惯。

2019年第14届D2参会记录

一年一度的D2论坛,今年第14届依然和上一届一样,在同一个酒店-杭州和达希尔顿逸林酒店,这次和两个小伙伴一起同行,早上5点半起床赶高铁,正好9点左右到会场,赶上圆心的开场演讲。

2019年,对于前端来讲,有很多大的变化,serverless的逐步流行,TypeScript逐渐成为前端项目开发的首选,微前端的落地等等,这些趋势在会上的主题演讲中也有体现。

六大主题

本次大会安排了6个专场:

  • 语言框架
  • 智能化
  • 微前端
  • Serverless
  • 工程化
  • 多样化领域

这些主题的选取也体现阿里前端技术委员会对前端趋势的理解,几个方向的演讲都有小伙伴们在探索实践,就如圆心在开场所讲,前端在垂直领域以及深度方面有更多可以探索的内容。具体的演讲主题可参考D2官网

听讲主题

圆心 - 开场演讲

圆心,作为阿里前端委员会的老板,每届会议的Keynote主持人。本次开场,讲到了这几个方面:

  1. 前端领域在扩大
  2. 2C -> 2B在慢慢增长,垂直领域出现更多机会
  3. 云端机会,业务和稳定性的要求提高
  4. 智能化,减少重复劳动,投入到业务及深度的探索
  5. 关注语言的底层,寻找参与制定标准的机会
  6. 多端一体化,wasm、IDE等

克军 - 微前端架构体系

久闻克军大佬之名,这次终于见到真容。讲得是云时代的前端架构,微前端架构体系,这是一个体系,并不单单指某一个微前端的框架或者库,包含了从前到后的几大方面。

从前端架构历史演进着手,逐步说明了微前端带来的变化,我的个人理解,微前端主要在中大型项目中为项目的灵活维护和部署提供了一个手段,并且可以将不同技术栈的前端应用集成在一起。

克军提出的微前端体系,包括了这几个部分:

  • 微前端基础设施
  • 微前端配置中心(版本管理、发布策略、动态构建)
  • 微前端观察工具(运维职责:可见、可控性)

微前端的主要原理,通过一个主应用来协调各应用之间的切换,实现协同工作。

甄子 - 前端智能化实践

这个主题演讲是关于智能化的,对应的开源项目是阿里imgcook,利用Tensorflow.js机器学习实现自动切图,由设计稿到逻辑代码。介绍了背后实现的思路,整体下来听着比较枯燥,表示没太明白。

其中提到了一个阿里近期开源的项目pipcook

陈垒 - fibjs 模块重构 - 从回调到协程

这个主题主要讲后端nodejs相关的开发,通过对比nodejs回调和fibjs库中同步调用的性能对比,讲解重构和推广fibjs,没有听完。

张伟、马航 - 前端工程下一站:IDE

IDE最近也是一个很热门的方向,有很多公司都在做,不管是云端的WebIDE还是桌面端,通过Electron技术可以将web技术栈的实现转为桌面端。由于这几年VSCode编辑器大火,很多项目基于VSCode开发了自己的IDE,服务于他们的配套产品,例如小程序等等。

这里介绍的是阿里开天的项目,兼容VSCode的一个IDE。

Nicolò Ribaudo - Babel: Under the Hood

一个意大利大学数学系的小哥来讲了Babel背后的原理,主要介绍了一下Babel的主要工作流程以及涉及到哪些核心的库。

Babel主要是基于AST来对代码进行解析和转译。

玄寂 - 基于浏览器的实时构建探索之路

这个主题介绍了在浏览器上的构建方式,比较熟悉的产品有CodeSandboxStackblitz

从这几个方面介绍了如何实现浏览器的构建:

  • 加载器
  • 文件系统
  • 编译系统
  • 包管理

Ahmad Amireh - Distributed Front-End Architecture

这是HappyPack的作者,分布式前端架构,其实概念上和微前端的类似的,不过演讲中提到他们的实践中用了例如consul的服务发现工具,以及如何去实现应用的切换,还是蛮精彩的一个演讲。

前端未来

对前端的未来做一下展望,有很多新的技术有望落地发展壮大,

  • ES2020有望新增几个实用的特性
  • 智能切图的准确率提高,这一点我还是有点抱怀疑态度,实用性和准确性达到的程度
  • 微前端逐步标准化,成为大型单页应用的开发模式
  • Serverless的推广,提高前端的地位,往后再走一步,并且关注运维而不用被运维拖累
  • WebIDE让编码构建更美好
  • 多领域开花

关于前端2019年的总结和未来展望,这里有一篇文章不错,有原文和译文,值得一读。

JSConf China 2019

上周末刚参加JSconf China 2019, 在这里聊聊记录一下感受。

大会简介

本次在上海举办的第7届JSConf China大会,也是我第一次参加JSConf China,参加完这次会议,也完成了年初给自己定下来的一个目标,一年参加两次技术会议,上一次会议是D2(其实也顺带参加了SEE Conf,蚂蚁金服举办的,同一个周末)。

几个主题

具体聊一下印象比较深刻的几个主题演讲:

The Beauty of TypeScript,这个主题由微软中国的工程师韩骏分享的,介绍了TS的优点,主要是解决JS开发时的痛点,引入类型,支持编译并兼容JS,适用于多人大型的项目开发。介绍了@ts-check、@ts-uncheck、@ts-ignore和any作为从JS迁移TS的一些辅助手段。

面向传统,Serverless 进化之路,这个主题由阿里的大佬陈仲寅分享淘系前端在Serverless的探索和落地经验,从他们的实践上看,上了Serverless之后相对原来的资源消耗,在双十一的情况节约30%左右,平时可节约40%,还是一个不错的表现。另外,好处有几个方面,降低运维的难度,自动扩容和监控,方便发布,集成特定的环境不用浪费时间在安装组件和兼容性方面;另一个方面,服务由函数来实现,原服务端的功能由前端来实现,也就加重了前端的工作量,这一点不能说是坏事,前端的工程领域更加扩大,其实在nodejs做bff的场景下,前端已经往后端走了一小步。

中间一个小插曲,腾讯云来做了一波推广,用他们的服务做了一个现场演示,FaaS支持比较方便的编写和发布,现场险些翻车,演示了一个圣诞帽戴在头像上方。

write code to refactor code, 这是一个妹纸介绍了使用AST(抽象语法树)的方法,来进行代码重构。通过写一些脚本,分析出代码结构,从而进行一些重构的工作,比如替换等。另外,使用AST还可以做很多有趣的事情,转译、Lint等等。

去除迷雾,漫谈WebAssembly, 一个小哥讲述了WebAssembly的运行过程,以及介绍了相关的使用资源,https://wapm.io/是一个WebAssembly的包管理器,类似于NPM的角色。介绍了Rust与WebAssembly的关联,可比较方便的从Rust转换代码到Wasm。

会上的前端趋势

从这次大会上看前端的一些趋势,其实几个热门主题这几年一直都比较火,很多大会都有安排相应的演讲:

  • TypeScript和Vs Code编辑器很火,用得人也很多,从现场的提问来看,大家普遍对TS比较关心
  • GraphQL很香,但是用的人并不多,或许上的成本比较高,而且有坑
  • Serverless前景还不错,提高生产力和降低成本,但是路还很漫长,感觉适合小型团队或者个人
  • WebAssembly正在逐步被接受和落地

感受

大会的整体感受,内容比较偏入门,深度和可欣赏性不够,干货不多,与门票的价格不相符。其中有两场Nike的演讲,与前端貌似没有多大关联。下一届应该不会参加了。具体的吐槽可以看看知乎上的回答

接下来就看12月份D2的表现了。

实现一个简单版React Router v4理解其原理

对于React-Router的实现原理,参考自Build your own React Router v4这篇英文原文,另外,React-Router底层库history的源码也值得一读。

欢迎访问博客文章

接下来是关于React-Router v4的一个简单版实现,通过这个实现来理解路由的原理,这里可能不会完全按照英文原文翻译,会有些意译或者省略的地方。

在单页应用中,应用代码和路由代码是极其重要的两部分,两者是相辅相成的,你是否对这两者有一些困惑。

关于路由的一些疑问点:

  1. 路由通常是相对比较复杂的,这让很多库的作者,在如何找到合适的路由抽象变得更加复杂。
  2. 因为这些复杂的原因,路由库的使用者倾向于盲目的相信库本身的抽象,而不是去理解背后的原理。

本文会通过实现一个简易版的React Router v4版本来点亮前一个问题的灯塔,并且让你了解背后的原理后去判断这样的抽象是否合适。

阅读更多