ziyi2 / ziyi2.github.io

www.ziyi2.cn
53 stars 5 forks source link

2019 前端之路 #11

Open ziyi2 opened 4 years ago

ziyi2 commented 4 years ago

前言

从未写过年度总结,恰逢今年是变化较大的一年,所以需要有一个总结仪式。同时希望在未来的每一年都能有一次年度总结,看看当前走过的路,也回望以往的不足。毕竟,前端一世,草木一秋。

关于我的年度总结,这里主要分为以下几个模块(文章篇幅很长,大家可以按需阅读):

「技术」模块主要讲解这一年来自我技术方面的创新以及实践。「学习」模块会讲解 2019 的一些学习内容以及前端新认知,并且也会讲解自我的学习方法,希望对在校以及刚入职前端工作的同学有所帮助(鉴于很多掘友高频询问如何学习前端)。「招聘」是今年最有感触的一块,会重点讲解自己在阿里的招聘感受,希望对想入职阿里工作的同学有所启迪。

抱歉说明:这里对掘友们说一声抱歉,在回复问题时由于工作忙碌而不够耐心(问相同问题的人太多),接下来的文章会重点针对高频问题在「学习」和「招聘」模块做一些阐述。

技术

今年是技术成长最多的一年,也是自我转变最快的一年。以下是自己总结的一张技术结构图,其中标红的部分是今年有所接触或深入的部分:

对我而言,今年技术创新的关键词是「UI 框架 / 脚手架」和「低代码(Low Code)」,技术实践的关键词是「桌面端」。

UI 框架 / 脚手架设计

今年年初的主要工作是对基础组件库进行框架重构以及对业务组件库进行框架设计,这是自我感觉最快乐的时光,因为一直不停的需要解决一些棘手的问题(往往困难是自我成长的机会点)。接下来将从以下四个方面讲解 UI 框架 / 脚手架设计的过程:

UI 框架重构前提

公司现有的基础组件库 1.x 基于 Element UI 框架进行设计,在开发的过程中发现 Element UI 框架带来了以下一些问题(相对我司而言):

友情提示:如果 UI 框架的一些能力(例如 utilscommonjs2 版本的各个组件按需引入umd 版本)根据公司自身的情况并不需要,那么完全可以砍掉从而大幅度简化 Webpack 配置(除非未来想要开源)。

为了解决上述问题,对公司现有的基础组件库 1.x 版本进行了框架重构。

基础组件库的框架重构

首先重点研究了 Element UI 框架的设计,其次在此基础上对组件库进行了框架的重构设计,重构成 2.x 版本后的框架大致如下图所示:

从图中可以发现, 2.x 版本的 UI 组件库特性如下:

额外吐槽:这个过程中遇到了贼多的坑,深入解读了一些 Vue CLI 3.x 的源码,顺便给 Vue CLI 3.x 提出了一些 Issue。除此之外,全量接入 Vuepress 0.x / 1.x 也是一个非常辛酸的过程(连主管都去解读 Vuepress 源码了,你还有什么理由不努力)。

业务组件库的框架设计

通用业务组件库是在基础组件库的基础上,为了满足各个 BU 通用业务场景的诉求而衍生出来的组件库。各个 BU 可以单独创建自己的业务组件库,但是可能造成以下问题:

因此构建一个跨 BU 的通用业务组件库是有必要的,但同时这个业务组件库需要符合以下特性:

基于以上一些特性需求,采用了 Lerna + Vue CLI 3.x + Webpack + Babel 进行了业务组件库的框架设计:

该业务组件库在基础组件库 2.x 特性的基础上,还存在如下特性:

额外吐槽:这种按需加载的模式最好是和 Vue CLI 3.x 建立配套体系,例如业务项目的脚手架是基于 Vue CLI 3.x 设计的,那么天然可以进行无缝适配。

UI 脚手架的设计

由于 Vue CLI 3.x 提供了插件化的开发方式,于是基于业务组件库的框架设计抽离了一套 UI 脚手架,从而可以快速构建一个新的组件库。该脚手架在业务组件库的特性基础上,还存在如下特性:

当然这个 UI 脚手架的设计也存在一些缺陷:

通过一键命令生成的 UI 组件库结构大致如下:

.
├── packages                        # workspaces
│   ├── alert                       # 警告(不进行 Webpack 构建)
│   │     ├── alert.vue             # 组件源码
│   │     ├── index.js              # npm包入口文件
│   │     └── package.json          # npm包描述文件
│   ├── btn                         # 按钮(进行 Webpack 构建)
│   │     ├── lib                   # 目标文件
│   │     │    └── lib.common.js    # npm包入口文件
│   │     ├── btn.vue               # 组件源码
│   │     ├── index.js              # 构建入口文件
│   │     ├── package.json          # npm包描述文件(需要vue cli的开发态依赖)
│   │     └── vue.config.js         # 构建配置文件
│   ├── locale                      # 国际化
│   │     ├── lang                  # 语言包
│   │     │    ├── enjs         # 英文
│   │     │    └── zh_CN.js     # 中文
│   │     ├── mixins            # 各个组件调用的国际化API
│   │     ├── src               # 源码
│   │     ├── index.js              # npm包入口文件
│   │     └── package.json          # npm包描述文件
│   ├── theme                       # 样式
│   │     ├── lib                   # 目标文件
│   │     │    ├── alert.css        # 警告样式
│   │     │    ├── btn.css          # 按钮样式
│   │     │    ├── index.css        # 总体样式
│   │     │    └── select.css       # 选择器样式
│   │     ├── src                   # 源文件
│   │     │    ├── utils        # 通用方法和变量
│   │     │    ├── alert.less       # 警告样式
│   │     │    ├── btn.less         # 按钮样式
│   │     │    ├── index.less       # 总体样式
│   │     │    └── select.less      # 选择器样式
│   │     ├── gulpfile.js               # 构建配置文件
│   │     └── package.json          # npm包描述文件
│   └── utils                       # 工具方法
│         ├── lib               # 目标文件(这里也可以采用lodash的方式,去掉lib文件夹这一层)
│         ├── src               # 源文件
│         ├── babel.config.js       # 构建配置文件
│         └── package.json          # npm包描述文件
├── public                          # 公共资源目录
├── src                             # 开发态目录
├── .browserslistrc                     # UI框架目标浏览器配置
├── .cz-config.js                       # cz定制化提交说明配置
├── .gitignore                          # git忽略配置
├── .lintstagedrc           # lint-staged配置
├── babel.config.js         # vue cli的babel配置
├── lerna.json              # lerna配置
├── package.json            # vue cli容器描述文件(容器不是npm包)
├── postcss.config.js           # postcss配置
├── README.md               # 说明
└── vue.common.js           # 通用的组件构建配置文件

友情延伸:专门写了一篇关于 UI 脚手架设计的文章,重点讲解了 Element UI 框架的设计原理以及 UI 脚手架的整体框架设计方案,感兴趣的同学具体可查看 Vue CLI 3 结合 Lerna 进行 UI 框架设计

低代码(Low Code)设计

低代码解决方案是年中的时候设计的,主要源于业务的诉求(需要注意技术都是源于业务的诉求,不要凭白造轮子)。低代码的设计主要经历了以下几个阶段(加粗的部分由其他同事实现或者和其他同事一起协作实现):

额外补充:当时视图渲染器在逻辑设计以及数据处理上没有完全想清楚,当然后续还需要设计视图拖拽引擎,最终实现可视化低代码的设计。

除了自己参与的低代码设计,也深刻学习了阿里的低代码中台产品,这个体会就深了,由于没有开源这里不再赘述。

桌面端开发

桌面端是年末才接触的,对于桌面端的开发主要经历了以下几个阶段:

现有 PC 桌面端的开发框架

个人认知的现有 PC 桌面端的开发类型主要分为以下几种类型:

桌面客户端类型 比喻 特性
纯 Native 开发(C++、Objective-C、C#、duilib) 汽车 性能好、安装包小、XP兼容性好、开发周期长、难以实现快速迭代、跨平台开发困难
纯 Web 开发(Node.js、JavaScript) 电动车 跨平台、性能相对较差、内存占用高
Hybrid 混合开发(C++、JavaScript) 油电混合动力车 安装包大、性能相对 Native 较差,相对纯 Web 较好、复杂界面和动画效果、跨平台、可实现快速迭代、框架开源且升级快

其中涉及到 Web 前端的桌面端应用开发框架如下(这里只是做简单调研):

客户端开发框架 类型 特性 应用
Nw.js 纯 Web 开发 内存占用高、支持XP 系统、启动速度、性能较差 DingTalk、Mongo Management Studio、Soundnode
Electron 纯 Web 开发 不支持 XP 系统(定制低版本可以)、最低支持 Win 7(2B/2G 有一定的量)、与 Native UI 框架融合难度高 Atom、Visual Studio Code、Skype
Chromium Embedded Framework(CEF) Hybrid 混合开发 基于 Google Chromium 项目开源(兼容性好)、支持 XP 系统、可方便定制和融合 Native UI 框架、内存占用等性能良好 DingTalk、有道、网易云音乐、Github

开发纯 Native 应用的成本较高,一般对性能要求极高的产品才会选择此类开发方式(例如微信)。通常而言,从开发成本、操作系统兼容性、跨平台能力、UI 效果以及产品的迭代速度等方面而言,采用纯 Web 的开发方式是大部分公司都会选择的高性价比开发方式。当然像 DingTalk 这样的产品在考虑整体性价比的同时也会对标微信的性能体验,选择 Hybrid 混合开发是一种非常高效的迁移方案(不仅可以提升产品的性能,实现部分高性能需求的 UI Native 化,还可以从 Nw.js 进行部分应用的平稳迁移)。

优化现有 PC 桌面端的 CEF 开发框架

公司现有的桌面端应用采用 CEF 多容器隔离的框架进行设计,大致的框架图如下所示:

从图中可以发现,通过 CEF 多容器隔离,每一个应用都可以被理解为一个独立的 SPA 应用(多容器隔离可以简单理解为多页应用)。那么这个框架所产生的问题如下:

为了解决以上问题,构思了新的框架设计进行桌面端开发:

友情提示:这里的公共服务很多,例如还包括 Native API、本地存储、TypeScript 公共类型定义等。

约束应用的开发规范

脚手架只是约束了应用的技术栈(包括开发、校验、构建和测试流程等),除此之外还需要约束工程项目内部更加细致的开发规范,后续更利于多人协作和维护。这里对每个应用的开发做出了如下的规范约束(2 个月的 React 开发经验提出的规范,如果不够完善请大家多多补充):

友情提示:如果是 React Hooks 开发(React Hooks Redux),可以去除应用视图 / 容器应用视图 / 业务是按照业务模块进行划分(能形成一定的通用性更优)。应用视图 / 容器应用视图 / 业务形成一一对应关系,除了担任控制器的作用,还可以起到跨业务模块通信的能力。应用视图 / 布局可快速适应应用视图 / 业务模块的需求变化,形成新的布局能力。如果是 TypeScript 开发,那么应用视图层级建议平铺,否则会造成Props 多层级传递的声明冗余(当然 TypeScript 声明应该按照应用视图 / 容器进行继承划分,传递 Props 的时候声明会变的更加清晰简洁)。

学习(针对新人,大佬跳过)

2019 学习

对我而言,今年学习实践的关键词是「Vue 2.x 以及 Vue CLI 3.x 源码解读」、「算法学习」和「重拾 React 」。学习认知的关键词是「Graphql & BFF」、「中台」、「微前端」和「Serverless」。

源码解读

很多人可能对于源码解读会产生一定的误解,他们的认知往往是这样的:

但是当他们遇到稍微难以解决的问题时往往是这样的:

源码解读当然是为了让你更了解你所使用的框架,从而让你可以快速定位技术 / 业务问题从而高效的解决问题,快速设计解决业务的可行方案以及设计一些通用的技术方案等等。但是源码解决往往确实是复杂困难的,一般我的做法如下:

友情提示:这里附上我的 Vue 源码解读实践文章 基于Vue实现一个简易MVVM 以及 JQuery 源码分析 (JQuery 源码分析是我实习的时候参考《锋利的jQuery》/《jQuery技术内幕》/《JavaScript高级程序设计》/《JavaScript权威指南》一行行代码调试并且一行行注释解读出来的,加了很多对于 JavaScript 基础知识的理解。那个时候时间较多,纯粹是一件既笨又无聊还低效且需要耐心坚持的事情,大概花了几个月的时间,如果是技术小白还是建议可以看看的)。

算法学习

算法学习是从面试中萌发出来的念头。当时参加有赞面试被算法题按在了地上摩擦,决定好好重新学习一下算法。 I-Algorithms 是参考了《算法导论》/ javascript-algorithm / CLRS 打造的一个简单易懂的 JavaScript 算法学习教程文档。 当然这一块中途被放下了,因为重新入职后根本没时间......不过后面等我适应了阿里的工作,我还是会重拾这一块的,感兴趣的同学可以查看一下,目前学习的内容如下:

第一章:算法基础

第二章:函数的增长

友情提示:感兴趣的同学可以查看 Github 仓库的算法学习介绍 I-Algorithms(本身这个项目也有值得小白学习的地方哦),也可以查看文档的线上学习地址 I-Algorithms

重拾 React

这个就没多少可以说的余地了,2016年实习的时候正好搞过 React SSR (那时候连一行 JQuery 都不会写。由于之前是做嵌入式开发,相对于转学 React 不算是什么困难的事情,把官网过了一遍重新回忆了一下 React,简单基于 Create React App ( Vue CLI 3.x 的插件系统真香)写了一个 React 教程了解一下 React 周边,主要包括了(也是半途而废):

以下是半途而废的部分

那这里遇到一些从 Vue 转 React 或者两者都会的面试者时,我往往会问他们对于这两个框架的看法,其实这种问题往往只是想听听他们的理解而已。那对于我而言,React 和 Vue 相比:

友情提示:如果是 Vue 开发者想尝尝 React 的鲜,可以看看我写的这个仓库 React-Tutorial(半途而废系列)。

我是如何学习前端的

鉴于很多加我的掘友都高频询问前端应该如何学习,我这里额外将以前学习前端的方法列举一下,供掘友们参考。我的学习方法大致分为以下几个过程:

友情提示:笨鸟先飞。

书籍

如果想要系统的学习一个专业,那么肯定是需要静下心来花时间系统的学习跟这个专业相关的任何基础知识,书籍当然是最好的途径。我这里将之前学习的书籍列举一下,大概如下图所示:

友情提示:读书是很花时间的,如果你觉得自己静不下心来读书,我觉得看看视频也是不错的。如果你静的下心来读书,那就好好读几本自己欠缺的书籍。当然除了一些技术书籍,平常也应该注意阅读一些能够改善思维的书籍(辛亏小时候养成了阅读文学作品的好习惯)。

笔记

好记性当然不如烂笔头,有些书你读着读着就变得难以理解,或者你读着读着就忘记了。这个时候最笨但最有效的方法是边读边实践边记录。记录和实践的过程一方面可以帮助你理解书中的阐述,另外一方面当然也可以帮助你日后快速回忆书本的大致内容(尤其是面试前特别管用),达到抛开书本提取精华的目的。这里我将我之前的笔记整理出来供大家参考:

以下是早期的笔记(很 Low 的 Word 文档),但是有好几百页几万字的那种(现在自己看看都蛮佩服自己的),那时候还不知道用 MD 格式:

友情延伸ziyi2/awesome-front-end 是自己整理的一个前端大杂烩,除了笔记、书籍和博客之外,还有我珍藏多年的书签(不定时更新)。

文档(英文)

文档部分主要强调的是阅读能力和书写能力:

阅读能力:这里需要强调的是培养自己阅读英文文档的能力(尽量阅读官方文档,除非你很难看懂文档到底说了什么)。如果你觉得阅读比较吃力可以配套一些 Chrome 翻译插件(例如 Google 翻译)。通常在研究一些新技术的时候需要阅读一些官方文档(这些文档大比例都是英文文档,而且一般情况下英文文档的更新会比中文文档更新的更快),所以阅读英文文档是一个非常重要的能力。 书写能力:书写文档能力是一种非常非常非常重要的能力,它可以很大程度上减少设计和沟通成本(防遗忘 / 防重复说明等)。当然书写规范也是很重要的,你可以参考一些开源作品的官方文档书写风格,也可以参考一些特定的书写规范(例如阮一峰的中文技术文档的写作规范)。当然写文档也需要养成实时更新的好习惯,否则过时的内容反而会导致设计和沟通成本的提升。

友情延伸:如果公司能够使用语雀,推荐语雀作为技术文档产品是一个不错的选择。如果不能使用外部产品,可以自行建立文档预览站点,例如使用 VuePress / React Static 等。

博客

写技术博文是今年开始才真正养成的习惯,虽然自己曾经有一个博客站点 www.ziyi2.cn,但其实更多的是记录一些学习笔记或者生活。今年开始在 Github 上使用 Issue 书写技术博客(以前总觉得要有一个自己的域名站点且网页要酷炫,现在是真的觉得要好用且实在,不搞花里胡哨的东西):

使用 Github 记录博客的好处是你可以关联给三方库提的 Issue,也可以博文之间互相关联,还可以去实时评论和关闭 Issue。当然玩法只会更多(例如基于 Issues 生成静态站点等),对于我来说这些功能就够了(之前看到一篇写的非常好的 Github Issue 博客教程,暂时找不到了)。

差不多上面截图的文章是我今年产出的所有博客文章(下半年换公司后只在公司的内部站点发表了一篇文章),如果对其中某些博文感兴趣的同学可以查看 Ziyi2 Github Issues

杂七杂八

跳槽

其实今年本来没有想过跳槽,只是觉得到明年年中就工作三年了(三年经验比较好换工作,且确实自己想换个离家近一点的公司,阿里当然成了首要目标),今年可以先出来试试水,看看是不是从物联网公司往互联网公司跳槽会比较难。结果一不小心就面上了,最终走的也很匆忙。当然从年初到年末升了两次工资也是蛮爽的,或许以后再也不会有这么大的工资涨幅了,啊哈哈。

PPT

以前对于写代码的不如写 PPT 的没有多少体感,因为前公司真的不需要做什么 PPT,唯一做的几次 PPT 也不是为了向上级进行述职,而是对其他 BU 进行技术分享,哪怕是晋升也不需要做 PPT。来了阿里之后发现写好一个 PPT 确实需要技术含量,当然讲 PPT 更需要技术含量(如何在有限的时间内最大化体现你的工作成果)。

运动

今年上半年4月开始到8月半基本上不下雨的话每天坚持从住的地方跑步去公司上班,但是来了阿里以后就打破了两年的作息习惯,再也无法7点半起床,再也无法早到公司多学习一个小时了(读书的时间都是挤出来的)!希望后续自己能够慢慢调整回来!

招聘

来了阿里之后,很多地方和原来的公司还是有很大的差异。比如更加自由(上下班不用打卡,如果加班很晚第二天可以中午到公司......)、更加忙碌(各种评审会、周会、双周会以及月会等)、更加独立自主(很多业务有人催但没人管,你需要自己为你的业务买单,是一种自下而上的模式而非自上而下的模式)、更加多面(跨部门协作、移动办公、技术培训、文化培训等等)。我觉得挺好,因为我不单单只是在写代码。除此之外,同事都很厉害,如果你遇到解决不了的问题几乎只要一脑暴,立马就有了解决方案。

说了那么多当然是希望大家能来应聘,因为真的缺人。当然为了让大家能够更加熟悉我们这边的招聘流程,这里会从以下三个方面简单说说我当面试官的一些感受:

简历评估

评估简历是招聘流程中的第一步,如果简历评估不过关那么将不会有接下来的面试流程。很多加我的掘友都会让我帮忙看看简历做的是否合理(往往这些掘友对自己都不够自信),其实简历大多数是由各位的学习和工作经历决定的,没有合理不合理的说法,只有合适或者不合适应聘岗位的情况。当然对于众多投递的简历还是会先做第一步筛选(这不是我自认为的简历评估方法):

以上是我作为一面面试官的评估方法,这是一个很现实的问题(有些评估方面怕引起众多掘友不良反应,这里就不一一列举了),因为很难从一堆简历中去精准的挑选出一个合适的简历(事实上大部分简历都千篇一律,因为大家写简历的形式真的都差不多),所以得有一套基本的评估方法。当然如果没有筛选出以上信息,我还会从以下信息进行二次筛选:

除此之外当然也会有一些硬性过滤的指标:

友情延伸:千万要留神专业技能,切忌写一些面试官一看就没兴趣的技能(你感觉会很多基础技能,写的越多越好,殊不知大家都会,甚至稍稍一深入询问你就怀疑自己是不是真的会了,还不如不写),很多技能信息你可以在项目经历中间接的透露出来。如果想了解更多如何写简历的技巧,可查看我的另外一篇文章 面试分享:两年工作经验成功面试阿里P6总结 / 简历

面试过程

目前国内的面试环境确实比较恶劣,记得之前看到有人在某社区评论说 Redux 作者如果来面试国内的三四线公司,可能连一面二面都过不了。这里我谈谈我自己对于面试的看法,我想说面试不是为了为难大家,也不是为了体现面试官多么牛逼之类的,面试是为了挖掘大家的能力和潜力。当然,每一个面试官的面试风格都不一样,大家不要再问我下一面是不是会问 XXX 问题,下一面是不是会有在线笔试等等,我不是下一个面试官。必须每一个人,每一个 BU、每一个公司、每一个国家、每一个行星、每一个星系面试的风格都不一样(啊哈哈哈,别再问我类似的问题啦,不要让你自己显得很...)。总之一句话,做好自己,做那个不能被替代的自己,不要让自己过于被动,好好准备,应付可能发生的一切。

由于刚进公司,我一般会承接一面的面试官,那我的面试风格是这样的:

友情提示:我喜欢根据简历做一些深度面试,但事实上一面更多的应该是做一些广度面试,不仅仅是根据简历已有的内容进行面试。

这里给出面试过程的几点建议:

对于我而言影响面试过于不过的因素大致有以下几点:

后续流程

如果你过了一面,那么后面基本上还有一轮基础面,一轮 Leader 面,一轮大 Leader 面,一轮 HR 面。所以总体而言,应该是 5 面左右。

关于我们

真香警告:写了这么多重点终于来了 😂😂😂

大家好,我们是阿里巴巴新成立的 BU,目前还有大量的 Web 前端 HC 空缺,希望正在找工作的同学们可以来试试:

机会非常难得,如果想更多了解我们 BU 并找我内推的同学加我微信(加我时记得备注内推并自带简历哦,当然如果是技术交流或者纯粹交朋友也可以哦,不过我不一定能保证仔细认真的回答问题哦):18768107826

友情提示:已经有掘友通过我的推荐成功加入阿里巴巴了呦!

掘金

我是一个惰社交人员(不玩知乎,不玩微博,不玩...),今年 1 月份加入掘金的初衷是希望自己多和社区保持信息同步,不会被面试信息淘汰。但加入掘金之后发现我的初衷慢慢被改变,掘金对我产生了一些意想不到的影响(不管是生活上还是工作上):

额外发现:每天早上醒来的第一件事情可能是刷沸点,也可能是直接起床。坐在马桶上的第一件事情可能是刷沸点,也可能是刷今日头条。出行地铁的时候可能是看热门文章,也可能是纯听歌。中午吃饭的时候肯定是先刷沸点。晚上睡觉前可能是刷沸点可能是刷抖音也可能是刷朋友圈。

于是憋了好久鼓足勇气在掘金发了第一篇技术文章 Vue CLI 3 结合 Lerna 进行 UI 框架设计,收获了一些赞,但是并没有想象中的那么好。不过万事开头难嘛,只要自己坚持,总能慢慢使自己的文章带来更多的普惠。

今年在掘金陆续发了 4 篇技术类文章,1 篇面试类文章,其中自认为写的最好的文章 基于 Vue 实现一个简易 MVVM 点赞数最少,相反自己没那么用心的面试文章 面试分享:两年工作经验成功面试阿里 P6 总结 反而点赞数很高且被各种公众号转载。从中猜测大家可能不喜欢既啰嗦又消耗脑力的文章,大家喜欢既精简又科普还不消耗耐性的文章(有点故事会的感觉)。

我个人喜欢写那种既啰嗦又长还不会分(一)、(二)、(三)的文章(真的需要耐心阅读的那种),事实上我总是想把我知道的事情说的既仔细又具体,哪怕它可以说的更精简。当然,写任何的文章都要认真仔细,要对读者的阅读时间负责(我会反复修订反复修订反复修订,直到满意为止)。

在掘金的第一年收获了很多粉丝,有很多掘友加我交流,但是可能我的沟通能力和社交能力真的有所欠缺,有些时候因为工作忙或者被相同问题困扰会导致我没有耐心回答掘友们的问题,希望在这篇又臭又长的文章中给大家带来一些些收获。

额外链接

这里推荐阅读之前写的文章(前面 2 篇实用型,后面 3 篇对面试应该会有帮助,尤其是后面 3 篇一定要看哦):