寻找海蓝
寻找海蓝
本文于2019年首发于掘金 --- ## 前言 设计前端组件是最能考验开发者基本功的测试之一,因为调用Material design、Antd、iView 等现成组件库的 API 每个人都可以做到,但是很多人并不知道很多常用组件的设计原理。 能否设计出通用前端组件也是区分前端工程师和前端api调用师的标准之一,那么应该如何设计出一个通用组件呢? > 下文中提到的**组件库**通常是指单个组件,而非集合的概念,集合概念的组件库是 Antd iView这种,我们所说的组件库是指集合中的单个组件,集合性质的组件库需要考虑的要更多. ## 文章目录 1. 前端组件库的设计原则 2. 组件库的技术选型 3. 如何快速启动一个组件库项目 4. 如何设计一个轮播图组件 ## 1.前端组件库的设计原则 ### 1.1 细粒度的考量 我们在学习设计模式的时候会遇到很多种设计原则,其中一个设计原则就是**单一职责原则**,在组件库的开发中同样适用,我们原则上一个组件只专注一件事情,单一职责的组件的好处很明显,由于职责单一就可以最大可能性地复用组件,但是这也带来一个问题,过度单一职责的组件也可能会导致过度抽象,造成组件库的碎片化。...
本文于2018年首发于掘金 --- ## **前言** 自 Backbone 之后前端框架就如同雨后春笋般出现,我们已经习惯了用各种框架进行开发,但是前端框架出现的意义是什么?我们为什么要选择前端框架进行开发呢? > **提前声明:** 我们没有对传入的参数进行及时判断而规避错误,仅仅对核心方法进行了实现. ## 文章目录 1. 前端框架的根本意义 2. 一个完整的前端框架是怎样的 3. 基于Proxy如何实现响应式系统 ## 前端框架的根本意义 ### 1.1 前端框架的好处 最开始学习前端框架的时候(我第一个框架是 React)并不理解框架能带来什么,只是因为大家都在用框架,最实际的一个用途就是所有企业几乎都在用框架,不用框架就 out 了. 随着使用的深入我逐渐理解到框架的好处: 1. 组件化:...
> 本文于2020年发布于掘金 --- 动态规划(Dynamic programming,简称DP)是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 从面试的角度看,动态规划是正规算法面试中无论如何都逃不掉的必考题,曾经有一个伟人说过这样一句话:  那么为什么动态规划会在面试中这么重要? 其实最主要的原因就是动态规划非常适合面试,因为动态规划没办法「背」。 我们很多求职者其实是通过背题来面试的,而之前这个做法屡试不爽,什么翻转二叉树、翻转链表,快排、归并、冒泡一顿背,基本上也能在面试中浑水摸鱼过去,其实这哪是考算法能力、算法思维,这就是考谁的备战态度好,愿意花时间去背题而已,把连背都懒得背的筛出去就完事了。 但是随着互联网遇冷,人才供给进一步过热,背题的人越来越多,面试的门槛被增加了,因此这个时候需要一种非常考验算法思维、变化多端而且容易设计的题目类型,动态规划就完美符合这个要求。 比如 LeetCode 中有1261道算法类题目,其中动态规划题目占据了近200道,动态规划能占据总题目的 1/6 的比例,可见其火热程度。 更重要的是,动态规划的题目难度以中高难度为主:  所以,既然我们已经知道这是算法面试的必考题了,我们怎么准备都不为过,本文尽笔者最大努力把动态规划讲清楚。 ## 从「钱」讲起 我们在前面内容了解到了贪心算法可以解决「硬币找零问题」,但是那只是在部分情况下可以解决而已,因为题目中给出的钱币面值为 1、5、25,我们现实生活中我们现行的第五套人民币面值分别为100、50、20、10、5、1,我们的人民币是可以用贪心算法找零的。 那么有什么情况下不能用贪心算法吗?比如一个算法星球的央行发行了奇葩币,币值分别为1、5、11,要凑够15元,这个时候贪心算法就失效了。 我们可以算一下,按照贪心算法的策略,我们先拿出最大面值的11,剩下的4个分别对应四个1元的奇葩币,这总共需要五个奇葩币才能凑够15元。 而实际上我们简单一算,就知道最少情况是拿出3个五元的奇葩币才能凑够15元。 这里就有问题了,贪心算法的弊端在这种特殊面值钱币面前展露无疑,原因就在于「只顾眼前,无大局观」,在先拿出最大的 11 面值的奇葩币后就彻底把周旋余地堵死了,因为剩下的 4...
> 本文于2019年首发于掘金 --- 对于不少开发者而言,链表(linked list)这种数据结构既熟悉又陌生,熟悉是因为它确实是非常基础的数据结构,陌生的原因是我们在业务开发中用到它的几率的确不大. 在很多情况下,我们用数组就能很好的完成工作,而且不会产生太多的差异,那么链表存在的意义是什么?链表相比于数组有什么优势或者不足吗? ## 什么是链表 链表是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer). 从本质上来讲,链表与数组的确有相似之处,他们的相同点是都是线性数据结构,这与树和图不同,而它们的不同之处在于数组是一块连续的内存,而链表可以不是连续内存,链表的节点与节点之间通过指针来联系.  当然,链表也有不同的形态,主要分为三种:单向链表、双向链表、循环链表. ## 单向链表 单向链表的节点通常由两个部分构成,一个是节点储存的值`val`,另一个就是节点的指针`next`.  链表与数组类似,也可以进行查找、插入、删除、读取等操作,但是由于链表与数组的特性不同,导致不同操作的复杂度也不同. ### 查找性能 单向链表的查找操作通常是这样的: 1. 从头节点进入,开始比对节点的值,如果不同则通过指针进入下一个节点 2. 重复上面的动作,直到找到相同的值,或者节点的指针指向null 链表的查找性能与数组一样,都是时间复杂度为O(n). ### 插入删除性能 链表与数组最大的不同就在于删除、插入的性能优势,由于链表是非连续的内存,所以不用像数组一样在插入、删除操作的时候需要进行大面积的成员位移,比如在a、b节点之间插入一个新节点c,链表只需要: 1. a断开指向b的指针,将指针指向c...
本文于2019年首发于掘金 --- 数组几乎可以是所有软件工程师最常用到的数据结构,正是因为如此,很多开发者对其不够重视. 而面试中经常有这样一类问题: 「100万个成员的数组取第一个和最后一个有性能差距吗?为什么?」 除此之外,我们在平时的业务开发中会经常出现数组一把梭的情况,大多数情况下我们都会用数组的形式进行操作,而有读源码习惯的开发者可能会发现,在一些底层库中,我们可能平时用数组的地方,底层库却选择了另外的数据结构,这又是为什么? 希望大家带着以上的问题我们进行讨论. ## 什么是数组 数组是计算机科学中最基本的数据结构了,绝大多数编程语言都内置了这种数据结构,也是开发者最常见的数据结构. 数组(英语:Array),是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储. > 当然,在一些动态语言中例如Python的列表或者JavaScript的数组都可能是非连续性的内存,也可以存储不同类型的元素. 比如我们有如下一个数组: ```java arr = [1, 2, 3, 4, 5] ``` 其在内存中的表现应该是这样的:  我们可以看到,这个数组在内存中是以**连续线性**的形式储存的,这个连续线性的储存形式既有其优势又有其劣势,只有我们搞清楚优劣才能在以后的开发中更好地使用数组. ## 数组的特性 一个数据结构通常都有「插入、查找、删除、读取」这四种基本的操作,我们会逐一分析这些操作带来的性能差异....
本文于2019年首发于掘金 --- 很多时候虽然我们了解了TypeScript相关的基础知识,但是这不足以保证我们在实际项目中可以灵活运用,比如现在绝大部分前端开发者的项目都是依赖于框架的,因此我们需要来讲一下React与TypeScript应该如何结合运用。 如果你仅仅了解了一下TypeScript的基础知识就上手框架会碰到非常多的坑(比如笔者自己),如果你是React开发者一定要看过本文之后再进行实践。 ## 快速启动TypeScript版react 使用TypeScript编写react代码,除了需要`typescript`这个库之外,还至少需要额外的两个库: ```bash yarn add -D @types/{react,react-dom} ``` 可能有人好奇`@types`开头的这种库是什么? 由于非常多的JavaScript库并没有提供自己关于TypeScript的声明文件,导致TypeScript的使用者无法享受这种库带来的类型,因此社区中就出现了一个项目[DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped),他定义了目前市面上绝大多数的JavaScript库的声明,当人们下载JavaScript库相关的`@types`声明时,就可以享受此库相关的类型定义了。 当然,为了方便我们选择直接用TypeScript官方提供的react启动模板。 ```bash create-react-app react-ts-app --scripts-version=react-scripts-ts ``` ## 无状态组件 我们用初始化好了上述模板之后就需要进行正式编写代码了。 无状态组件是一种非常常见的react组件,主要用于展示UI,初始的模板中就有一个logo图,我们就可以把它封装成一个`Logo`组件。 在JavaScript中我们往往是这样封装组件的: ```jsx import * as...
本文于2019年首发于掘金 --- 2019年下半年即将到来,上半年狂风骤雨般的裁员浪潮让每一位从业者背脊发凉,在经历了五六年黄金发展期之后,前端开发这个行业似乎也进入了转折点。 我一边听开发者在网络上抱怨工作难找,前端开发早已经饱和了,又在另一边听大厂的朋友们抱怨,招了很久的人,四处出击却填不满HC,前端人才市场就是这么充满了矛盾与反常。 其实仔细想想,出现上述的情况很容易理解,实际上前端开发单纯从数量上已经饱和了,所以大量的初级前端工程师找不到活干,但是从另一方面,高级前端工程师依然是凤毛麟角,高级岗的HC永远是不饱和的。 前不久民工叔发的动态:  目前前端人员的分布是金字塔形的,而且是底部比较长的金字塔形状:  所以进阶是大部分前端开发必须要面对的事情,现在已经不是能写几个页面就能找到工作的时代了,只有往上进阶才能保持职业竞争力,否则我们谁都不能保证下次裁员潮来临的时候,我们会不会成为沙滩上裸泳的人。 ## 我对前端技术的思考方式 前端社区是非常活跃的社区,几乎每过一段时间都会有新的技术或者新的开发方式变成了热点,因此前端开发者才会有了『学不动了』的梗,以及毕竟丢人的Deno留言事件。 以我自己为例,因为想自己开发一个APP,所以面临技术选型,也面临将来要投入大量时间选择学习的技术,摆在我面前的有三个选项: * Flutter跨平台技术 * RN跨平台技术(WEEX除了阿里生态外,很少用的) * 原生技术 到底选择哪一个技术既能满足开发APP的需求,又值得投入时间进行学习呢? 如果你去知乎或者其他技术类的社区去问,绝大多数的回答是Flutter(虽然从回答来看很多答主似乎都没用过Flutter),Flutter作为正式发布才刚刚半年的新技术已经席卷了整个大前端圈子,成为了当之无愧的第一热点,真是佩服谷歌的布道能力。  关于Flutter的事情我思考了很久,也用它快速开发了一个demo,它有很吸引人的地方: * 声明式UI这跟react很像,比Android 那种UI编程方式先进太多(笔者很早之前写过一个Android...
本文于2019年首发于掘金 --- ## 前言 我们在学习 React 的过程中经常会碰到一个概念,那就是数据的不可变性(immutable),不可变数据是函数式编程里的重要概念,因为可变数据在提供方便的时候会带了很多棘手的副作用,那么我们应该如何处理这些棘手的问题,如何实现不可变数据呢? ## 1.可变数据的副作用 我们应该都知道的基本知识,在JavaScript中分为原始类型和引用类型. > JavaScript原始类型:Undefined、Null、Boolean、Number、String、Symbol > JavaScript引用类型:Object 同时引用类型在使用过程中经常会产生副作用. ```js const person = {player: {name: 'Messi'}}; const person1 = person; console.log(person, person1); //[ {...
本文于2019年首发于掘金 --- ## 前言 虽然前端开发作为 GUI 开发的一种,但是存在其特殊性,前端的特殊性就在于“动态”二字,传统 GUI 开发,不管是桌面应用还是移动端应用都是需要预先下载的,只有先下载应用程序才会在本地操作系统运行,而前端不同,它是“动态增量”式的,我们的前端应用往往是实时加载执行的,并不需要预先下载,这就造成了一个问题,前端开发中往往最影响性能的不是什么计算或者渲染,而是加载速度,加载速度会直接影响用户体验和网站留存。 [《Designing for Performance》](https://link.juejin.im/?target=http%3A%2F%2Fshop.oreilly.com%2Fproduct%2F0636920033578.do)的作者 [Lara Swanson](https://link.juejin.im/?target=http%3A%2F%2Fradar.oreilly.com%2Flswanson)在2014年写过一篇文章[《Web性能即用户体验》](https://link.juejin.im/?target=https%3A%2F%2Fwww.forbes.com%2Fforbes%2Fwelcome%2F%3FtoURL%3Dhttps%3A%2F%2Fwww.forbes.com%2Fsites%2Foreillymedia%2F2014%2F01%2F16%2Fweb-performance-is-user-experience%2F%26refURL%3D%26referrer%3D%23194909aa5a52),她在文中提到“网站页面的快速加载,能够建立用户对网站的信任,增加回访率,大部分的用户其实都期待页面能够在2秒内加载完成,而当超过3秒以后,[就会有接近40%的用户离开你的网站](https://link.juejin.im/?target=http%3A%2F%2Fwww.mcrinc.com%2FDocuments%2FNewsletters%2F201110_why_web_performance_matters.pdf)”。 值得一提的是,GUI 开发依然有一个共同的特殊之处,那就是 **体验性能** ,体验性能并不指在绝对性能上的性能优化,而是回归用户体验这个根本目的,因为在 GUI 开发的领域,绝大多数情况下追求绝对意义上的性能是没有意义的. 比如一个动画本来就已经有 60 帧了,你通过一个吊炸天的算法优化到了 120 帧,这对于你的 KPI 毫无用处,因为这个优化本身没有意义,因为除了少数特异功能的异人,没有人能分得清 60 帧和 120...
本文2018年首发于掘金 --- ## 前言 **双向绑定**其实已经是一个老掉牙的问题了,只要涉及到MVVM框架就不得不谈的知识点,但它毕竟是Vue的三要素之一. **Vue三要素** * 响应式: 例如如何监听数据变化,其中的实现方法就是我们提到的双向绑定 * 模板引擎: 如何解析模板 * 渲染: Vue如何将监听到的数据变化和解析后的HTML进行渲染 可以实现双向绑定的方法有很多,KnockoutJS基于观察者模式的双向绑定,Ember基于数据模型的双向绑定,Angular基于脏检查的双向绑定,本篇文章我们重点讲面试中常见的基于**数据劫持**的双向绑定。 常见的基于数据劫持的双向绑定有两种实现,一个是目前Vue在用的`Object.defineProperty`,另一个是ES2015中新增的`Proxy`,而Vue的作者宣称将在Vue3.0版本后加入`Proxy`从而代替`Object.defineProperty`,通过本文你也可以知道为什么Vue未来会选择`Proxy`。 > 严格来讲Proxy应该被称为『代理』而非『劫持』,不过由于作用有很多相似之处,我们在下文中就不再做区分,统一叫『劫持』。 我们可以通过下图清楚看到以上两种方法在**双向绑定**体系中的关系.  > 基于数据劫持的当然还有已经凉透的`Object.observe`方法,已被废弃。 > **提前声明:** 我们没有对传入的参数进行及时判断而规避错误,仅仅对核心方法进行了实现. --- ## 文章目录 1....