2018
1. 人性的弱点 ---卡耐基
对个人的剖析
2. 你一年的 8760 小时 ---艾力
一切都不晚
3. 大数据时代:生活、工作与思维的大变革 ---维克托•迈尔•舍恩伯格
大数据下的我们是透明的
4. 编码:隐匿在计算机软硬件背后的语言 ---查尔斯•佩措尔德
从简单电路到逻辑门,到锁存器寄存器,再到整个系统。 从简单的 01 到复杂的图形图像等
5. Head First Python ---Paul Barry
适合新手学习 Python
6.像计算机科学家一样思考 Python ---艾伦 B. 唐尼
python2 的语法 适合入门
7. Python 编程:从入门到实践 ---埃里克·马瑟斯
很好的一本 python 书 语法为 Python3 内容切合书名、 前章讲 python 语法,还提到了测试驱动开发(TDD) 后面接着讲了一些框架,pygame, matplotlib, django
8. 重构-改善既有代码的设计 ---马丁•福勒
一本程序员的武功秘籍,时不时走一回心法
9. 你只是看起来很努力
路走过就一定有他的意义 感情最重要的是两个人拥有独立的心灵和共同进步,不是一个迁就另一个、一个牵制另一个 当你决定旅行的时候,最难的一步已经迈出来了。可是,他还有后面一旬,如果你第一步不迈出,永远不知道你 的梦想是多么容易实现。
10. 如何阅读一本书 ---轻阅读编写组
读书 4 问 转述,如果能将书的内容转述给其他尚未读过该书的人是一个很好的体现你对这本书的内容是否清楚明了。 人与书的交流,人与人的交流
11. 小王子 ---安托万•德•圣埃克苏佩里
我也不知道那只羊有没有把那朵花吃了
12. 一只特立独行的猪
- 感觉我还不能读进去
- 王小波的书可能目前我的心态,我的年龄暂时很难理解。
13. 万万没想到:用理工科思维理解世界
如题:理性
14. 4 点起床:最养生和高效的时间管理
3*8 = 24 小时
15. 追风筝的人
16. 活着
17. 必然
18. 未来简史
2019
1.一辈子很长,要和有趣的人在一起
2.Android 编程权威指南(第二版)
- 将 Android 开发架构、整体布局是如何的。
3.《汇编语言(第 3 版) 》王爽著
- 汇编可能离现在程序员很远,但还是有必要阅读的。了解计算机的底层是如何工作的。任何一门语言到最后都会变成汇编,这也是能和计算机真实交流的唯一途径。
4.The Great Gatsby
5.高性能 JavaScript
- 将所有
<script>
标签放在尽可能接近<body>
标签底部的位置,尽量减少对整个页面下载的影响* 浏览器遇到 script 会下载文件并执行,阻塞页面渲染。 - 每个 HTTP 请求都会产生额外的性能负担,下载一个 100KB 的文件比下载四个 25KB 的文件要快。
- defer 指明元素所含脚本不会修改 DOM,可以延迟执行。并行下载,onload 之前执行
- 当需要多次访问 DOM 时使用局部变量存储 DOM 引用
- 使用更快的 API
querySelectorAll
firstElementChild
- 使用事件委托
- 循环使用局部变量存储长度,每次循环 8 次操作
- 递归改迭代
- 浏览器一次同一个域名可以并行的发 6 个请求,所以不必要为了减少网络请求而网络请求
6.爱你就像有生命
7.倚天屠龙记
- 因新版倚天屠龙记上映,说是尊重原著,就看了看原著。
2020
1.圣女的救济
- 一次完美犯罪 1 年内凶手都在保护被害者,当需要杀害他的时候只需要什么都不做。
2.JavaScript DOM 编程艺术
- 古老的书了,现在手动操作 dom 编程已经很少了。
3.ECMAScript 6 入门
- ES6 入门的书,细节全面。
4.CSS 世界
- 优先级 min-height/width>>>max-height/width>>>width:!important>>> 内联 style 超越! important 超越最大
5.你不知道的 JavaScript 上卷
1.2 理解作用域
- 引擎会为变量 a 进行 LHS(左值)查询。另外一个查找的类型叫作 RHS(右值)
- RHS 查询与简单地查找某个变量的值别无二致,而 LHS 查询则是试图找到变量的容器本身,从而可以对其赋值。从这个角度说,RHS 并不是真正意义上的“赋值操作的右侧”,更准确地说是“非左侧”。
2.1 词法阶段
- 没有任何函数的气泡可以(部分地)同时出现在两个外部作用域的气泡中,就如同没有任何函数可以部分地同时出现在两个父级函数中一样。
2.2 欺骗词法
- 在执行
eval(..)
之后的代码时,引擎并不“知道”或“在意”前面的代码是以动态形式插入进来,并对词法作用域的环境进行修改的。引擎只会如往常地进行词法作用域查找 - with 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
3.2 隐藏内部实现
- 从所写的代码中挑选出一个任意的片段,然后用函数声明对它进行包装,实际上就是把这些代码“隐藏”起来了。
3.3 内容
- 把 configurable 修改成 false 是单向操作,无法撤销!要注意有一个小小的例外:即便属性是
writable:false
,我们还是可以把writable
的状态由 true 改为 false,但是无法由 false 改为 true。除了无法修改,configurable:false
还会禁止删除这个属性: - 是否会出现在对象的属性枚举中,比如说 for..in 循环。如果把 enumerable 设置成 false,这个属性就不会出现在枚举中,虽然仍然可以正常访问它。相对地,设置成 true 就会让它出现在枚举中。
- 如果你想禁止一个对象添加新属性并且保留已有属性,可以使用
Object.prevent Extensions(..)
: Object.preventExtensions(myObject)
;- Object.seal(..)
会创建一个“密封”的对象,这个方法实际上会在一个现有对象上调用
Object.preventExtensions(..)并把所有现有属性标记为
configurable:false。
Object.freeze(..)
会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal(..)
并把所有“数据访问”属性标记为writable:false
,这样就无法修改它们的值。- in
和
hasOwnProperty(..)的区别在于是否查找
[[Prototype]]链,然而,
Object.keys(..)和
Object.getOwnPropertyNames(..)`都只会查找对象直接包含的属性。
3.4 遍历
- 遍历对象属性时的顺序是不确定的,在不同的 JavaScript 引擎中可能不一样。因此,在不同的环境中需要保证一致性时,一定不要相信任何观察到的顺序,它们是不可靠的
- ES6 增加了一种用来遍历数组的 for..of 循环语法(如果对象本身定义了迭代器的话也可以遍历对象
- 数组有内置的@@iterator,因此 for..of 可以直接应用在数组上。
1 | const myArray = [ 1, 2, 3 ]; |
5.1 [[Prototype]]
- 对于默认的
[[Get]]
操作来说,如果无法在对象本身找到需要的属性,就会继续访问对象的[[Prototype]]
链:- 如果在
[[Prototype]]
链上层存在名为 foo 的普通数据访问属性并且没有被标记为只读(writable:false),那就会直接在 myObject 中添加一个名为 foo 的新属性,它是屏蔽属性。 - 如果在
[[Prototype]]
链上层存在 foo,但是它被标记为只读(writable:false),那么无法修改已有属性或者在 myObject 上创建屏蔽属性。如果运行在严格模式下,代码会抛出一个错误。否则,这条赋值语句会被忽略。总之,不会发生屏蔽。 - 如果在
[[Prototype]]
链上层存在 foo 并且它是一个 setter,那就一定会调用这个 setter。foo 不会被添加到(或者说屏蔽于)myObject,也不会重新定义 foo 这个 setter。
- 如果在
5.3 (原型)继承
- Bar.prototype = Object.create(Foo.prototype)。调用 Object.create(..)会凭空创建一个“新”对象并把新对象内部的
[[Prototype]]
关联到你指定的对象(本例中是 Foo.prototype)。换句话说,这条语句的意思是:“创建一个新的 Bar.prototype 对象并把它关联到Foo.prototype
”。 - // ES6 之前需要抛弃默认的 Bar.prototype Bar.ptototype = Object.create(Foo.prototype); // ES6 开始可以直接修改现有的 Bar.prototype Object.setPrototypeOf(Bar.prototype, Foo.prototype);
- bind(..)函数来生成一个硬绑定函数,该函数是没有
.prototype
属性的 - .proto`看起来很像一个属性,但是实际上它更像一个 getter/setter。
6.1 面向委托的设计
- Chrome 会动态跟踪并把实际执行构造过程的函数名当作一个内置属性,但是其他浏览器并不会跟踪这些额外的信息。
- Chrome 内部跟踪(只用于调试输出)“构造函数名称”的方法是 Chrome 自身的一种扩展行为,并不包含在 JavaScript 的规范中。
- JavaScript 中的函数之所以可以访问 call(..)、apply(..)和 bind(..)(,就是因为函数本身是对象。而函数对象同样有[[Prototype]]属性并且关联到 Function.prototype 对象,因此所有函数对象都可以通过委托调用这些默认方法。
6.4 更好的语法
- 匿名函数没有 name 标识符,这会导致:1.调试栈更难追踪;2.自我引用(递归、事件(解除)绑定,等等)更难;3.代码(稍微)更难理解。
6.生命不息,折腾不止
- 罗老师
7.React 技术栈
1 | componentWillUpdate |
8.高效能人的七个习惯
- 由内而外
- 积极主动
- 要事第一
- 统合综效
- 双赢
9.JavaScript 教程
10.《你不知道的 JavaScript(中卷)》
第 1 章 类型
- ECMAScript 语言类型包括
Undefined、Null、Boolean、String、Number和Object
。 - typeof null === "object"`; // true 正确的返回结果应该是"null",但这个 bug 由来已久,在 JavaScript 中已经存在了将近二十年,也许永远也不会修复,因为这牵涉到太多的 Web 系统,“修复”它会产生更多的 bug,令许多系统无法正常工作。
- vaScript 中的变量是没有类型的,只有值才有。
- 大多数开发者倾向于将 undefined 等同于 undeclared(未声明),但在 JavaScript 中它们完全是两回事。
1 | if (typeof DEBUG !== "undefined") { |
第 2 章 值
IEEE 754 标准来
JavaScript 使用的是“双精度”格
a.toExponential(); // "5e+10"
因此数字值可以调用 Number.prototype 中的方法
tofixed(..)
方法可指定小数部分的显示位数:
toPrecision(..)
方法用来指定有效数位的显示位数:
ES6 开始,严格模式(strict mode)不再支持 0363 八进制格式
1 | ES6支持以下新格式: |
二进制浮点数最大的问题(不仅 JavaScript,所有遵循 IEEE 754 规范的语言都是如此),是会出现如下情况: 0.1 + 0.2 === 0.3; // false
最常见的方法是设置一个误差范围值,通常称为“机器精度”(machine epsilon),对 JavaScript 的数字来说,这个值通常是 2^-52 (2.220446049250313e-16)。从 ES6 开始,该值定义在 Number.EPSILON 中,我们可以直接拿来用,也可以为 ES6 之前的版本写 polyfill:
1 | if (! Number.EPSILON) { |
能够被“安全”呈现的最大整数是2^53-1
,即9007199254740991
,在 ES6 中被定义为Number.MAX_SAFE_INTEGER
。最小整数是-9007199254740991
,在 ES6 中被定义为Number.MIN_SAFE_INTEGER
。
null 指空值(empty value) undefined 指没有值(missing value) 或者: undefined 指从未赋值• null 指曾赋过值,但是目前没有值 null 是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。然而 undefined 却是一个标识符,可以被当作变量来使用和赋值。
永远不要重新定义 undefined。
void 并不改变表达式的结果,只是让表达式不返回值:
简单值(即标量基本类型值,scalar primitive)总是通过值复制的方式来赋值/传递,包括 null、undefined、字符串、数字、布尔和 ES6 中的 symbol。
复合值(compound value)——对象(包括数组和封装对象,参见第 3 章)和函数,则总是通过引用复制的方式来赋值/传递。
第 3 章 原生函数
String.prototype.XYZ
简写为String#XYZ
第 4 章 强制类型转换
- 对普通对象来说,除非自行定义,否则 toString()(Object.prototype.toString())返回内部属性
[[Class]]
的值,如"[object Object]"
。 - 如果对象中定义了
toJSON()
方法,JSON 字符串化时会首先调用该方法,然后用它的返回值来进行序列化。 - toJSON()返回的应该是一个适当的值,可以是任何类型,然后再由
JSON.stringify(..)
对其进行字符串化。也就是说,toJSON()
应该“返回一个能够被字符串化的安全的 JSON 值”,而不是“返回一个 JSON 字符串”。 - 我们可以向 JSON.stringify(..)传递一个可选参数 replacer,它可以是数组或者函数,用来指定对象序列化过程中哪些属性应该被处理,哪些应该被排除,和 toJSON()很像。如果 replacer 是一个数组,那么它必须是一个字符串数组,其中包含序列化要处理的对象的属性名称,除此之外其他的属性则被忽略。如果 replacer 是一个函数,它会对对象本身调用一次,然后对对象中的每个属性各调用一次,每次传递两个参数,键和值。如果要忽略某个键就返回 undefined,否则返回指定的值。
- JSON.stringify 还有一个可选参数 space,用来指定输出的缩进格式。space 为正整数时是指定每一级缩进的字符数,它还可以是字符串,此时最前面的十个字符被用于每一级的缩进:
- ToNumber 对以 0 开头的十六进制数并不按十六进制处理,而是按十进制。
- 一元运算+被普遍认为是显式强制类型转换。
- 一元运算符+的另一个常见用途是将日期(Date)对象强制类型转换为数字,返回结果为 Unix 时间戳,以毫秒为单位(从 1970 年 1 月 1 日 00:00:00 UTC 到当前时间):
1 | var d = new Date( "Mon, 18 Aug 2014 08:53:06 CDT" ); |
- JavaScript 有一处奇特的语法,即构造函数没有参数时可以不用带()
- 字位运算符只适用于 32 位整数,运算符会强制操作数使用 32 位格式
- ~`。它首先将值强制类型转换为 32 位数字,然后执行字位操作“非”(对每一个字位进行反转)。
- x
大致等同于
-(x+1)。很奇怪,但相对更容易说明问题:
~42; // -(42+1) ==> -43 在
-(x+1)中唯一能够得到
0(或者严格说是-0)的x值是-1。也就是说如果x为-1时,
~`和一些数字值在一起会返回假值 0,其他情况则返回真值。~- `有什么用处了!~和 indexOf()一起可以将结果强制类型转换(实际上仅仅是转换)为真/假值:
~~
中的第一个~执行 ToInt32 并反转字位,然后第二个~
再进行一次字位反转,即将所有字位反转回原值,最后得到的仍然是 ToInt32 的结果。- ~~
我们要多加注意。首先它只适用于32位数字,更重要的是它对负数的处理与
Math.floor(..)`不同。 - x
能将值截除为一个32位整数,
x | 0`也可以,而且看起来还更简洁。 - Infinity(1/0 的结果)
parseInt("Infinity", 19)
。第一个字符是"I",以 19 为基数时值为 18。第二个字符"n"不是一个有效的数字字符,解析到此为止,和"42px"中的"p"一样。- 如果两边的值中有 true 或者 false,千万不要使用
==
。如果两边的值中有[]、""或者 0,尽量不要使用==。 - 根据规范 a <= b 被处理为 b < a,然后将结果反转
- JavaScript 中
<=
是“不大于”的意思(即!(a > b)
,处理为!(b < a)
)
第 5 章 语法
- 语句都有一个结果值
- 获得结果值最直接的方法是在浏览器开发控制台中输入语句,默认情况下控制台会显示所执行的最后一条语句的结果值。
- 规范定义 var 的结果值是 undefined
++a++
为例,它首先执行a++
(根据运算符优先级,如下),返回 42,然后执行++42,这时会产生 ReferenceError 错误,因为++无法直接在 42 这样的值上产生副作用。- 如果操作成功,delete 返回 true,否则返回 false。
- foo: bar()`这样奇怪的语法为什么也合法呢?这里涉及 JavaScript 中一个不太为人知(也不建议使用)的特性,叫作“标签语句”(labeledstatement)。foo 是语句 bar()的标签(后面没有;,参见 5.3 节)。标签语句具体是做什么用的呢?如果 JavaScript 有 goto 语句,理论上我们可以使用 goto foo 跳转到 foo 处执行。goto 被公认为是一种极为糟糕的编码方式,它会让代码变得晦涩难懂(也叫作 spaghetti code),好在 JavaScript 不支持 goto。
- JavaScript 通过标签跳转能够实现 goto 的部分功能。continue 和 break 语句都可以带一个标签,因此能够像 goto 那样进行跳转。例如:contine foo`并不是指“跳转到标签 foo 所在位置继续执行”,而是“执行 foo 循环的下一轮循环”。所以这里的 foo 并非 goto。标签的循环跳转一个更大的用处在于,和break 一起使用可以实现从内层循环跳转到外层循环。没有它们的话实现起来有时会非常麻烦:break foo 不是指“跳转到标签 foo 所在位置继续执行”,而是“跳出标签 foo 所在的循环/代码块,继续执行后面的代码”。因此它并非传统意义上的 goto。
- SON 属性名必须使用双引号
- 通过
<script src=..>
标签加载 JavaScript 文件,其中只包含 JSON 数据(比如某个 API 返回的结果),那它就会被当作合法的事实上 JavaScript 没有else if
,但 if 和 else 只包含单条语句的时候可以省略代码块的{ }else if极为常见,能省掉一层代码缩进,所以很受青睐。但这只是我们自己发明的用法,切勿想当然地认为这些都属于JavaScript语法的范畴。
- 运算符的优先级比=低
。所以
b = a++, a其实可以理解为
(b = a++), a - &&运算符的优先级高于||,而||的优先级又高于?:
10.《你不知道的 JavaScript(下卷)》
第 1 章 异步:现在与将来
- setTimeout(..)并没有把你的回调函数挂在事件循环队列中。它所做的是设定一个定时器。当定时器到时后,环境会把你的回调函数放在事件循环中,这样,在未来某个时刻的 tick 会摘下并执行这个回调。
- 并发是指两个或多个事件链随时间发展交替执行,以至于从更高的层次来看,就像是同时在运行(尽管在任意时刻只处理一个事件)。
第 5 章 程序性能
- Web Worker 的新增特性的探索过程中,这些都是很好的问题。这是浏览器(即宿主环境)的功能,实际上和 JavaScript 语言本身几乎没什么关系。也就是说,JavaScript 当前并没有任何支持多线程执行的功能。
- Worker 可以访问几个重要的全局变量和功能的本地复本,包括 navigator、location、JSON 和 applicationCache。
- 你还可以通过 importScripts(..)向 Worker 加载额外的 JavaScript 脚本: // 在 Worker 内部 importScripts( "foo.js", "bar.js" );这些脚本加载是同步的。也就是说,importScripts(..)调用会阻塞余下 Worker 的执行,直到文件加载和执行完成。
- Web Worker 通常应用于哪些方面呢?• 处理密集型数学计算• 大数据集排序• 数据处理(压缩、音频分析、图像处理等)• 高流量网络通信
- 当然,所有权传递是可以双向进行的。如果选择 Transferable 对象的话,其实不需要做什么。任何实现了 Transferable 接口(http://developer.mozilla.org/en-US/docs/Web/API/Transferable)的数据结构就自动按照这种方式传输(Firefox和Chrome都支持)。
11.《九型人格》
- 人类的三种体验世界的方式
- 思考
- 感觉
- 感官
- 九型人格
- 完美主义者
- 希望绝对
- 喜欢批判自己与他人
- 高标准
- 给予者
- 主动
- 乐于助人
- 乐观
- 慷慨大方
- 实践者
- 工作狂
- 浪漫主义者
- 艺术气质
- 多情
- 观察者
- 审慎
- 高度隐私
- 杰出的决策者和有创意的知识分子
- 质问者
- 把世界看作威胁
- 不喜欢权威
- 享乐主义者
- 乐观
- 精力充沛
- 迷人
- 难以捉摸
- 未来向导者
- 支配者
- 独断
- 有时具有攻击性
- 一不做二不休
- 领导或者极端孤立者
- 媒介者
- 和平使者
- 不知道自己想要什么
- 喜欢和谐而舒适的生活
- 完美主义者
graph RL; 完美主义者-->浪漫主义者; 给予者-->支配者; 实践者-->媒介者; 浪漫主义者-->给予者; 观察者-->享乐主义者; 质问者-->实践者; 享乐主义者-->完美主义者; 支配者-->观察者; 媒介者-->质问者;
12. 《编程珠玑》
给程序员的 10 条建议
- 解决正确的问题
- 探索所有可能的方案
- 观察数据
- 使用粗略计算
- 利用对称性
- 利用组件做设计
- 建立原型
- 必要时进行权衡
- 保持简单
- 追求完美
代码调优法则
- 时间换空间
- 空间换时间
- 循环法则
- 逻辑法则
- 等价的代数表达式换逻辑表达式
- 过程法则
- 内联
- 表达式法则
- if 替换取模% 运算
13. 《有些路,只能一个人走》
- 态度不可以改变世界,但可以改变自己
- 距离高考已经过去 4 年了,4 年里自己改变了什么,自己是否还记得高中时自己想要成为的那个自己。 生哥,“我不喜欢别人叫我生哥”。我似乎也忘了我曾经为什么要这么说,不过还有一个人记得。我得想想我当时这么说的原因。
- 别讲着别人的故事,忘了自己的。
- 时间是最伟大的治疗师。是这么个道理,4 年了,当初高中毕业时那种喜欢一个的人劲现在好像也不知还在不在,不知道如果现在我们又变成同桌我还会不会有从前的感觉了。可能留下的只是美好的祝愿。我现在还记得,我当初给自己的保证,保证自己一定能够回到从前。回到从前的那个灿烂。保证在现在依旧在内心有效,不过也不可能真实的去实现这个过程了。
- 你认为的不一定是你想的,你想的不一定是你看到的,你看到的不一定是真实的。同上,我认为我能保证,但是不是,也无从验证。
- 自我忍耐与调节:遇到成绩看窗外,遇到问题看镜子。
- 真正的爱情:未来
- 规划,倒推 OKR
- 是谁陪我们到最后的
14. 《代码整洁之道》
整洁的代码
- 优雅,高效,减少依赖,优美的散文,让你的营地比来时更干净
有意义的命名
下标的意义 说清楚 == -1
值的意义
要能读得出来
getActiveAccount() getActiveAccounts() getActiveAccountInfo()
不必使用成员变量前缘,调用者很快会无视这个前缀
类名和对象名应当是名词或者名词短语
方法名应该是动词或者动词短语
避免同一单词不同意义,双关语
添加有意义语境
- firstName,lastName,street,city,state,zipcode 放在一起时很明确是一个地址信息
- 当单独拆开时不明其意,可以添加适当的语境。addrFirstName, addrLastName,addrCity,addrZipcode
函数
- 第一规则:短小,第二规则:还要更短小。
- 只做一件事,做好这一件事。
- 自顶向下,每一个函数为一个抽象层级。看看源码
- 使用描述性名称,描述函数做的事
- 别害怕长名称,长而具有描述性的名称比短页而令人费解的名称好。
- getHomeOpenStatusByActivityId
- getHomeOpenStatusByDepId
- 前端在 webpack 打包时也会压缩
- 参数
- 无参数最理想
- 其次一个参数,两个参数
- 避免出现三个级以上参数
- 多个参数在写 test 的时候要能写出确保各种组合运行正常的测试用例
- 如果需要多个参数,那说明其中一些可以封装成类了
- 函数要么做什么事,要么回答什么事。
- 使用异常代替错误返回码
- 结构化编程
- 每个函数只有一个入口,一个出口( 一个 return)
- 循环中不能有 break 和 continue
注释
- 注释的恰当用法是弥补我们在用代码表达意图遭遇的失败
- 注释是一种失败
- 注释应当少
- 注释是对意图的解释
- 注释要能提供信息
- TODO 应当是程序员认为应该做的,但现在还没有做的工作
- 不要写无用的注释和废话注释
- 删掉注释的代码
类
- 一个类应该短小
- 单一权责原则
- 类中每个方法应当操作一个或者一种变量
- 开闭原则。对拓展开发,对修改封闭。jQuery.extend
15.张爱玲传
- 记得别人的小恩惠
- 你若了解的我过去,你便会原谅现在的我。
- 人总是容易崇拜一个在你弱势的方面显得强势的人。
- 生命中总有这样的时候,对我们重要的一些人有可能就在身边我们却不知,不到那一刻完全没明白宿命的安排,像面纱一样罩着。
- 一个天才的女人忽然结了婚。
- 中国人向来不喜欢异类。
- 爱情中的女人,一如既往的付出,为了对得起自己的青春。
- 性格相似的同类适合做朋友,但不适合生活在一起,性格互补的异性更适合在一起,因为很少有冲突,---只要互补的是个性,相似的是兴趣爱好,便是绝佳的组合。
- 精神是想通。
- 最擅长写爱情,却恋爱都没谈过。
- 噢,你也在这里吗?
- 定情信物。
- 溃烂早已愈合,那酱紫色的难堪却还在。
- 见了他,她变得很低很低,低到尘埃里,但她心里是欢喜的,从尘埃里开出花来。
- 最幸福的事莫过于你喜欢的人,他刚好也喜欢你。
- 生活是一袭华美的袍, 上面爬满了虱子。
- 年经的女孩子不需要美貌,只青春就够了。
- 五六十岁的外国背包客。
2021
1. 重构
- 重构本来就不是一件应该特别拨出时间做的事情,重构应该随时随地进行。你不应该为重构而重构,你之所以重构,是因为你想做别的什么事,而重构可以帮助你把那些事做好。
- 看见不规范的、可以优化的不敢改。
- 不敢改,你写什么代码嘛。
- 需要重构的是你不知这段代码在干什么,不了解它的行为。对于了解其行为的说明还不是那么迫切需要重构。
法则
- 事不过三,三则重构。
- 第一次做某件事时只管去做;第二次做类似的事会产生反感,但无论如何还是可以去做;第三次再做类似的事,就应该重构。
- 添加功能时重构
- 修补错误时重构 代码还不够清晰----没有清晰到让你能一眼看出 bug。
- 复审代码时重构 code review
坏代码
- 重复的代码
- 过长的函数
- 过大的类
- 过长的参数列表
- 发散式变化
- 由最初的功能单一在进行后期的迭代扩展后,功能不再单一,功能形成发散式的变化
- 霰弹式修改
- 遇到功能变化时需要在多个类中进行许多小修改
- 依恋情节
- 一个函数为计算某个值从某个类取了许多值,过渡依恋这个类,就可以把这个方法写入到这个类中
- 保证数据和操作数据的行为在一个地方
- 数据泥团
- 相同的几项数据,几个类拥有几个差不多的属性,几个方法的参数差不多
- switch
- 使用多态替换
- 过渡的消息链
- 用户向一个对象请求另一个对象,再通过这个获取的对象去获取另一个对象
- 但不是任何函数链都是坏代码
- 过多的注释
- 如果需要注释来解释一块代码做了什么,试着提炼出方式
- 如果还需要注释来解释其行为,试试修改函数名
- 如果还需要注释来说明某些系统的需求规格,试试引入断言
- 如果不知道要做什么,这个时候才该说注释
重构的前提需要一个可靠的测试环境,但对于前端来说,单测较少,更多的是需要 QA 的 RD 的自测,这可能也是在前端不愿意修改旧代码的原因。
重构列表(方法)
1.提炼函数
这也是我们在重构/编码过程中使用到最多的方式
让函数名表明它的意图,尽量让一个函数没有过多的注释来表明它的意图。
2.内联函数
当函数内部的代码足够简短到表达这个函数的意图时,可以将这个函数去掉。
或者在重构一个大的函数时,将内部的小函数进行重新拆解并重新组合。
3.内联临时变量
一个临时变量只被赋值过一次,且只被使用过一次时,就可以消除这个临时变量
4.以查询代替临时变量
临时变量是临时(计算出来)的,只有在函数内部使用,就可以通过将这变量包装成一个函数。
类似 vue 的计算属性
5.引入注释性变量
将一个复杂的表达式的结果放进一个临时变量,用变量名来解释对应的用途。
也类似 vue 的计算属性
6.分解临时变量
一个临时变量被多次赋值,但不同阶段表达的意思不同时,就可以使用多个临时变量代替
7.移出对参数的赋值
参数的值尽量只在函数被调用时赋值,函数体内不必再对这个参数进行重新赋值,提高代码的清晰度,在函数内部任何地方使用是,参数的指向都是唯一确定的
8.以函数对象取代函数
当存在一个大型的函数,内部局部变量使用的情况导致不能再提炼更小的函数时,将这个函数放入一个对象中,函数的局部变量就变成为个对象的字段,这个时候再把这个大型函数提炼成多个小的函数。
9.替换算法
换一种更清晰的算法
重构列表(在对象之间)
1.搬移函数
类 A 中的一个函数 F 与另一个类 B 进行的交流更多,F 调用类 B,B 调用 F。可以将这个 F 搬移到 B 中。
2.搬移字段
类 A 中的一个字段 P 与另一个类 B 进行的交流更多,P 调用类 B,B 调用 P。可以将这个 P 搬移到 B 中。
4.提炼类
一个类做了由两个类做的事,可以新建一个类,将相应的功能拆分。
5.内联类
一个类没有做太多的事,可以将其萎缩塞进另一个类中。
简化表达式
1.分解表达式
把多个 if-else 拆分成独立的函数,让函数表达该表达式的含义
2.合并表达式
判断条件不同,但行为是一致的(比如:return) 奖这个抽取成一个单独函数
3.合并重复的条件判断
一组表达式的所有分支都执行相应的代码,就可以抽取到外部
4.以卫语句取代嵌套条件表达式
卫语句: 单独检查的语句。代表它比较特殊,全部 if-else 会让每个条件都显得重要性一致,使用单独的判断表示这个条件的特殊性.
简化函数调用
1.给函数取个名字
函数的名称应该准确表达它的用途。给函数命名有一个好办法:首先考虑应该给这个函数写上一句怎样的注释,然后想办法将注释变成函数名称。
2.以明确函数取代参数
有一个函数,其中完全取决于参数值而采取不同行为。针对该参数的每一个可能值,建立一个独立函数。
3.以函数取代参数
当一个函数的参数为另一个函数的返回值时,让参数接受者内部去调用这个函数
3.隐藏函数
一个类的某些函数没有在其他地方使用时,将其设为 private
2.人月神话
杂
- 编程乐趣
- 一种创建事件的纯粹快乐
- 开发出对他人有用,自己的劳动成果能够被他人使用
- 系统开发过程的魅力,将各个零部件组装在一起,以精妙的方式运行着,并收到预期的效果。
- 凭自己的想象建造自己的城堡。
- 编程的苦恼
- 来自追求完美
- 对其他人的依赖是一件痛苦的事(在别人的项目上进行二次开发)
- 寻找 bug 是一个重复性的活动,枯燥。
- 投入大量时间当完成时,去显得陈旧过时。
- 这次肯定会运行,,我刚刚找出最后一个 bug
- 软件任务进度安排
- 1/3 计划
- 1/6 编码
- 1/4 软件测试和早期系统测试
- 1/4 系统测试,所有的构件已完成
- Brooks 法则
- 向进度落后的项目上增加人手,只会使项目更加落后。
外科手术队伍
graph TB; 外科医生 --> 管理员 管理员 --> 文秘1 外科医生 --> 编辑 编辑 --> 文秘2 外科医生 --> 副手 外科医生 --> 程序职员 外科医生 --> 工具维护人员 外科医生 --> 测试人员 外科医生 --> 语言专家
- 外科医生
- 首席程序员,定义功能和性能技术,设计程序,编制源代码、测试,技术文档
- 副手
- 设计的思考者、讨论者和评估人员。主要是讨论
- 管理员
- 外科医生的老板
- 在管理人员、薪酬、办公空间有决定权,但不能花太多时候
- 一个文秘
- 专业管理人员。
- 编辑
- 外科医生负责文档的生成。编辑根据外科医生的草稿,口述,进行分析和重组,提供各种文档
- 一个文秘
- 两个文秘
- 属于管理员和编辑
- 程序职员
- 所有的团队技术记录,接收文秘性质的培训,所有计算机输入的汇总点。
- 工具维护人员
- 检查外科医生需要的工具,需要开发一些实用程序。
- 测试人员
- 测试
- 语言专家
- 掌握复杂编程语言专家。
2.云边有个小卖部
我这一生只向世界问候过 3 次,刚好每次都遇到了你。
3. 时间的朋友(2015-2017)
4. 了不起的 Node.js
4. 更了不起的 Node.js 卷一
- 深入到源码,从源码理解 Node.js