落魄前端,整理给自己的前端知识体系复习大纲(下篇)

前言

首先,感谢一些同行们对上篇的肯定。

其次,文章标题为"大纲",只是笔者,整理给自己的一个复习大纲。

也许内容并不深入,因为文章的标题与定义就是大纲,并没指望一篇文章,可以教会提到的对应的知识点。无论哪个知识点,一个原型链最基础的东西,都可进行深挖,大神都可以扯上几万字,也未必能让所有人看懂,培训机构上万的学费,也未必敢说一句包你懂,何况笔者只是一个免费的大纲汇总呢?本文仅是大纲而已。大家哪个知识点不熟悉,应该学会自己查漏补缺,自己学习着去深入。

也许错别字,也许知识点有误,因为时间紧迫,精力有限,能力也有限,多多包涵,也欢迎您的指出,大家一起进步。

下篇,不像上篇,很多都是一个开放性的答案,也因个人时间原因,故只提供一个简介,或者第三方链接。

大纲

本章一共有两篇:

上篇主要为html,css,js,es6,浏览器等基础知识。

下篇主要为手写api,网络编程基础,设计模式基础,源码指引,框架复习指引等。

其中,该文为下篇,上篇链接为:juejin.im/post/686771…

三.巩固前端基建

本章重点,提供的知识点的归类,以及重点。具体的知识点不做多余的介绍。(如果对知识点不熟悉,建议重点突击补充一下。)

在职前端开发,如果你也想学习前端开发技术,可以加入我组建的前端学习交流裙:851 231 348

也可以关注我的微信公众号:【前端留学生】自己根据多年来的开发经验总结录制的

一套web前端精讲视频和学习方法,以及一些前端学习手册,前端面试题,端开发工具,

PDF文档书籍教程,无偿分享给大家。需要的话都可以自行来获取下载。

1

2

3

4

5

1)加深巩固篇

1.前端去重的方法有哪些?

看过一篇文章,里边有十二种,可以参考:segmentfault.com/a/119000001…

但是内容感觉很多重复,以及有点为重复而重复。笔者简单提及一下自己脑袋里可行的去重方法(关键字思维,代码太多了暂不提供):

1.利用Set,自带数组去重功能。也是ES6最实用的方法

2.利用Map,

3.for for splice/del

4.indexOf

5.sort

6.includes

7.hasOwnProperty

8.filte

9.递归

2.前端异步的方案有哪些?

1)Promise(可看上篇的解释)

2)generator(可看上篇的解释)

3)async/await

4)事件发布/监听模式(可看后续的设计模式,属于发布订阅模式,代表作EventBus)

async 和 await 相比直接使用 Promise 来说,优势在于处理 then 的调用链,能够更清晰准确的写出代码。缺点在于滥用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。

3.前端网络请求有哪些?

ajax, fetch, axios。

一句简单的语句来概括的话,ajax因为不支持promise给淘汰,从而有了fetch,然后fetch缺陷多,不支持对异常捕捉,不支持监听进度条,cookies不友好等等。所以,axios当今浪潮。

有兴趣了解,推荐:juejin.im/post/684490…

4.前端定时器有哪些?

异步编程当然少不了定时器了,常见的定时器函数有 setTimeout、setInterval、requestAnimationFrame。我们先来讲讲最常用的setTimeout,很多人认为 setTimeout 是延时多久,那就应该是多久后执行。

其实这个观点是错误的,因为 JS 是单线程执行的,如果前面的代码影响了性能,就会导致 setTimeout 不会按期执行。当然了,我们可以通过代码去修正 setTimeout,从而使定时器相对准确

首先 requestAnimationFrame 自带函数节流功能,基本可以保证在 16.6 毫秒内只执行一次(不掉帧的情况下),并且该函数的延时效果是精确的,没有其他定时器时间不准的问题,当然你也可以通过该函数来实现 setTimeout。

5.前端创建对象有哪几种方式?

该知识点只做汇总提示,不做具体分析。请各自查询资料查漏补缺。

1)var obj = new Object();

2)var obj = { name: ‘小明’ }

3)工厂模式

function createObj(name){

var o = new Object();

o.name = name;

o.fun = function(){

}

return o;

}

1

2

3

4

5

6

7

4)构造函数

function TestObj(name){

this.name = name;

}

1

2

3

5)原型创建

function TestObj(){}

Person.prototype.name = '小明';

};

1

2

3

6)构造函数 + 原型创建

7)class写法

6.前端的继承方式有哪些?

1.原型链继承

本质是重写了对象。

缺点:

1)对象实例共享所有继承的属性和方法

2)不能传递参数

2.构造函数继承

在子类构造函数的内部调用超类型构造函数。使用apply()和call() 方法

缺点:

1)函数复用性不高 ,每个实例都是重新实例化构造函数,不存在共享属性

2)只能继承实例上的属性,原型上的方法不可见

3.组合继承

本质:原型链 + 构造函数

Parent.call(this) new Parent()避免了上述的缺点,常用。

优点:可传参,不会与父类引用属性共享

缺点:继承父类函数的时候调用了父类构造函数,导致子类的原型上多了不需要的父类属性,存在内存上的浪费。

4.原型式继承

实现本质:object()函数对传入其中的对象执行了一次浅复制

5.寄生式继承

借用构造函数来继承属性,通过原型链的混成形式来继承方法

6.寄生组合

高效率只调用了一次构造函数,集寄生式继承和组合继承的优点于一身,是实现基于类型继承的最有效方式。

就是将父类的原型赋值给了子类,并且将构造函数设置为子类,这样既解决了无用的父类属性问题

Parent.call + Object.create()

详细可参考:juejin.im/post/684490…

7.前端代码的复用有哪几种方式?

该知识点只做汇总提示,不做具体分析。请各自查询资料查漏补缺。

1)函数封装

2)继承

3)复制extend

4)混入mixin

5)借用apply/call

2)手写api

此部分,废话不多说,直接给对应的代码!如果还有其他重要手写代码,留言笔者会考虑补充。

有源码不理解的朋友们,可自行查询资料,或留意关注笔者的解说: juejin.im/post/686940…

1.new

function createThis( proto ){

var obj = new Object;

obj.__proto__ = proto.prototype;

let [ constructor, ...args] = [ ...arguments ];

let result = constructor.apply( obj, args );

return typeof result === 'object' ? result : obj;

}

1

2

3

4

5

6

7

8

2.apply/call/bind

Function.prototype.wzApply = function (context) {

const thisContext = context ? context : windows;

thisContext.fn = this;

var result = null;

if (arguments[1]) {

result = thisContext.fn(...arguments[1]);

} else {

result = thisContext.fn();

}

delete thisContext.fn;

return result;

}

Function.prototype.wzCall = function (context) {

const thisContext = context ? context : windows;

thisContext.fn = this;

var result = null;

var args = [...arguments].slice(1)

if (args) {

result = thisContext.fn(...args);

} else {

result = thisContext.fn();

}

delete thisContext.fn;

return result;

}

Function.prototype.wzBind = function (context) {

var _this = this;

var arg = [...arguments].slice(1);

return function F(){

if( this instanceof F ){

return new _this(arg.concat(...arguments));

}

return _this.apply( context, arg.concat(...arguments) );

}

}

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

26

27

28

29

30

31

32

33

34

35

36

37

38

3.instanceOf

function _instanceof(A, B) {

var O = B.prototype;// 取B的显示原型

A = A.__proto__;// 取A的隐式原型

while (true) {

//Object.prototype.__proto__ === null

if (A === null)

return false;

if (O === A)

return true;

A = A.__proto__;

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

4.获取url参数

function getQuery( params ){

var query = window.location.search.substring(1);

var vars = query.split("&");

for (var i=0;i<vars.length;i++) {

var pair = vars[i].split("=");

if(pair[0] == params ){return pair[1];}

}

return(false);

}

1

2

3

4

5

6

7

8

9

10

5.模拟深拷贝

简版看笔者代码,如需要深入建议:www.kancloud.cn/ljw78947894…

function deepClone(initalObj, finalObj) {

var obj = finalObj || {};

for (var i in initalObj) {

var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况

if(prop === obj) {

continue;

}

if (typeof prop === 'object') {

obj[i] = (prop.constructor === Array) ? [] : {};

arguments.callee(prop, obj[i]);

} else {

obj[i] = prop;

}

}

return obj;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

6.防抖与节流

const debounce = (cb, wait = 500, immediate = true) => {

let timer = 0;

let context = null;

let param = null;

const later = () => setTimeout(() => {

timer = null;

if (!immediate) {

cb.apply(context, param);

context = null;

param = null;

}

}, wait);

return function (...args) {

if (!timer) {

timer = later();

if (immediate) {

cb.apply(this, args);

} else {

context = this;

param = args;

}

} else {

clearTimeout(timer);

time = later();

}

}

}

const throttle= (func, delay=500 ){

var timer = 0;

var startTime = Date.now();

return function( ...args ){

var context = this;

var currentTime = Date.now();//当前时间

var diffTime = currentTime - startTime; //时间差

clearTimeout(timer);

if( diffTime > delay){

func.apply( context, args);

startTime = Date.now();

}else{

timer = setTimeout( function(){

throttle( func, delay);

});

}

}

}

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

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

7.手写迭代器next

function createIterator(items) {

var i = 0;

return {

next: function() {

var done = (i >= items.length);

var value = !done ? items[i++] : undefined;

return {

done: done,

value: value

};

}

};

}

var iterator = createIterator([1, 2, 3]);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

8.手写Object.freeze

function tFreeze(obj){

if(obj instanceof Object){

Object.seal(obj); // 封闭对象

for(let key in obj){

if(obj.hasOwnProperty(key)){

Object.defineProperty(obj,key,{

writable:false

})

myFreeze(obj[key]); //遍历

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

3)框架源码理解

源码是很多企业的考试重点,看不懂源码没关系,但是要明白源码大概是什么,大概的原理又是什么。此章节内容相对较多,笔者就不单独在本文解析。

笔者自身也处于探索或学习状态。如果你2到5年工作经验,想学习一下源码,可以参考一下笔者过去写的文章,那也是笔者的复习思路。

列的知识点,都是重点之重点。

如果你有一定的基础,或以及看过源码,或觉得网上还有更好的帖子,可以另从他处学习,不喜勿喷。

(笔者也是学习中写下的源码,有不足或者理解错误的地方,多多包涵与讨论)

1.vue源码

笔者mini版草文:juejin.im/post/684790…

2.react源码

笔者mini版草文:juejin.im/post/685457…

3.wepback源码

笔者mini版草文:juejin.im/post/685457…

4.vuex源码

笔者mini版草文:juejin.im/post/685705…

5.vue route源码

笔者mini版草文:juejin.im/post/686010…

6.diff源码

笔者mini版草文:juejin.im/post/686881…

7.promise源码

笔者mini版草文: juejin.im/post/686920…

8.react体系

react fiber,,react redux, react Hook等,笔者来不及学习或汇总,提供曾看到不错的文章:

React Fiber: juejin.im/post/685952…

React Hook:juejin.im/post/686774…

React redux: juejin.im/post/684490…

4)工具拓展篇

1.babel

概念部分拷贝:juejin.im/post/684490…

Babel是一个工具链,主要用于将ECMAScript 2015+版本代码向后兼容 Javascript 语法,以便可以运行到旧版本浏览器或其他环境中。

Babel 的三个主要处理步骤分别是: 解析(parse),转换(transform),生成(generate)。

解析

将代码解析成抽象语法树(AST),每个js引擎(比如Chrome浏览器中的V8引擎)都有自己的AST解析器,而Babel是通过Babylon实现的。在解析过程中有两个阶段:词法分析和语法分析,词法分析阶段把字符串形式的代码转换为令牌(tokens)流,令牌类似于AST中节点;而语法分析阶段则会把一个令牌流转换成 AST的形式,同时这个阶段会把令牌中的信息转换成AST的表述结构。

转换

在这个阶段,Babel接受得到AST并通过babel-traverse对其进行深度优先遍历,在此过程中对节点进行添加、更新及移除操作。这部分也是Babel插件介入工作的部分。

生成

将经过转换的AST通过babel-generator再转换成js代码,过程就是深度优先遍历整个AST,然后构建可以表示转换后代码的字符串。

babel编译原理

● babylon 将 ES6/ES7 代码解析成 AST

● babel-traverse 对 AST 进行遍历转译,得到新的 AST

● 新 AST 通过 babel-generator 转换成 ES5

babel/babel-polyfill

babel-polyfill:ES6的转码。IE的兼容

2.nignx

非专业人员,不过前端人员还是必要掌握一下前端如何部署。

简单的普及一下nignx,Nginx可见简单理解成,所开发高性能的 Web和 反向代理 服务器。

明白nigix如何实现正向代理,如何实现反向代理,如何完成负载均衡。本文不做重点介绍,有兴趣请移步:juejin.im/post/684490…

3.csr与ss

SSR(Server Side Rendering) :传统的渲染方式,由服务端把渲染的完整的页面吐给客户端。这样减少了一次客户端到服务端的一次http请求,加快相应速度,一般用于首屏的性能优化。

CSR(Client Side Rendering):是一种目前流行的渲染方式,它依赖的是运行在客户端的JS,用户首次发送请求只能得到小部分的指引性HTML代码。第二次请求将会请求更多包含HTML字符串的JS文件。

SSR优点:

1)有利于SEO的优化

2)首屏快

缺陷:

1)性能全都依赖于服务器

2)只能做静态,交互效果还是得用CSR,前端界面开发可操作性不高

3)开发条件受限,生命周期等。

反之,CSR 不利于SEO,首屏慢,但是交互效果好。

4.web Worke

想了解的朋友们移步:juejin.im/post/684490…

四.编程相关

这里为"编程相关",而不是"前端相关",因为这是无论哪个客户端的开发人员都必须掌握的基础。废话不多说,本文列举以前端挂钩的知识点。

1)设计模式篇

设计模式更是一种思维。设计模式一共23种,分创建型,结构,行为型。本文举几个,前端用到的几个设计模式,且是简单的描述一下。

如果对全面想要了解,可参考笔者曾经写过的一篇文章:juejin.im/post/684490…

此外,"徐小夕"这篇也是不错的。juejin.im/post/684490…

1.单例模式

一个极有可能重复出现的“实例”, 如果重复创建,是否消耗性能?如果借助第一次的实例,后续只是对该实例的重复使用,这样就达到了我们节省性能的目的。

可能服务端的朋友,知道什么是数据库链接池,这就是一个单例的经典模式,数据库连接池,与每次创建数据库连接,效率值将差异巨大。这就是单例模式的魅力。

我们前端的实践中,也经常可以借鉴这个思维。例如,登录弹出框,取消重新弹出时,再显示原来的弹出框,而不是重新创建。

var myLogin = function( fn ){

var result;

return function(){

return result || ( result = '<div>我是登陆框</div>' );

}

}

1

2

3

4

5

6

7

2.工厂模式

这里严格来说有两类设计模式,一个叫简单工厂,一个抽象工厂。

简单工厂模式叫做静态工厂方法模式,是由一个工厂对象决定创建出哪一种产品类的实例。例如富士康同时需要生产华为,苹果等手机,我们可用一个工厂的模型,生产人只要输入型号,就可以产出对应的手机。

抽象工厂,多一个抽象对象。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。 如上栗子,如果还需要手机颜色,内存大小,共同来确定一步手机,这就是抽象工厂。

抽象工厂,还需要使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性。

3.策略模式

简单点的理解,就是针对不同的状态,给出不同的算法或者结果。定义好策略组,根据不同的状态定义不同的策略。我们前端的实例,比如我们的form验证。

他的优点:

1、算法可以自由切换。

2、避免使用多重条件判断。

3、扩展性良好。

缺点:

1、策略类会增多。

2、所有策略类都需要对外暴露。

4.责任链模式

用来处理相关事务责任的一条执行链。例如前端JS 中的事件冒泡,一层一层往上传递。

优点:

1、降低耦合度。它将请求的发送者和接收者解耦。

2、简化了对象。使得对象不需要知道链的结构。

3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

4、增加新的请求处理类很方便。

缺点:

不能保证请求一定被接收;代码调试时不太方便,可能会造成循环调用;

5.观察者模式(Vue必懂)

观察者模式(Vue双向绑定原理了解一下): 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。

发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

发布订阅模式属于广义上的观察者模式。经过时间的沉淀,慢慢独立于观察者模式,成为另外一种不同的设计模式。

这篇写得挺好的:blog.csdn.net/hf872914334…

Vue双向绑定的思维的设计模式,Vue玩家必须深入一下。

7.装饰器模式(React必懂)

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。

有点类似我们的相框与相片的关系。

优点:装饰类和被装饰类可以独立发展,不会相互耦合。

缺点: 多层装饰比较会显得复杂。

React高阶组件的思维,React玩家必须深入一下。

2)网络协议篇

本人列举几个重点的点。建议直接tiantianUp的文章,写得比较适合观众(不像写得比较适合自己,自己看的都是写个要点去联想)。

本节内容参考:

1.巩固你的HTTP知识体系:juejin.im/post/685728…

2.前端必备的HTTP基础知识:www.jianshu.com/p/20bd68e95…

3.12期前端冲刺必备指南: juejin.im/post/684490…

1.http特点

优点

1.简单快速

每个资源得到URI是固定的,想访问某个资源,只需要输入这个资源对应的URI就可以了。

(URL(Uniform Resource Location)统一资源定位符,URI(Uniform Resource Identifier)统一资源标识符。URL是URI的子集,URL就是用定位的方式实现的URI。)

2.灵活

每个HTTP头部有个Content-Type,一个HTTP协议通过设置不同的Content-Type值,可以完成不同类型的资源的传输。

3.无连接

限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

4.无状态

HTTP协议对于事务处理没有记忆能力。知乎一句简单回单很好:就是第二次来你无法识别它曾经来过。(人生若只如初见)

但是,在通过增加cookie和session机制的前提下,现在的网络请求其实是有状态的。

缺点

1.无状态,有时候,需要保存信息,比如像购物系统,需要保留下顾客信息等等,另外一方面,有时候,无状态也会减少网络开销,比如类似直播行业这样子等,这个还是分场景来说。

2.明文传输,即协议里的报文(主要指的是头部)不使用二进制数据,而是文本形式。这让HTTP的报文信息暴露给了外界,给攻击者带来了便利。

3.队头阻塞,当http开启长连接时,共用一个TCP连接,当某个请求时间过长时,其他的请求只能处于阻塞状态,这就是队头阻塞问题。

2.https

HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。

HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。

HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。

3.http1.1

缓存处理

带宽优化

异常码的完善,新增了24个错误状态响应码,

Host头处理

长连接

4.http2.0

header压缩

新的二进制格式

多路复用

服务端推送

5.http缓存

参考上篇,浏览器缓存部分。

6.常见状态码

「1xx」: 代表请求已被接受,需要继续处理。

「2xx」: 表示成功状态。

「3xx」: 重定向状态。

「4xx」: 客户端错误。

「5xx」: 服务器端错误。

7.DNS解析

浏览器缓存 —>> 本地hosts文件 —>> 本地DNS解析器 —>>本地DNS服务器 —>> 其他域名服务器请求。

8.三次握手

第一次握手:建立连接时,客户端发送syn包(seq=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

9.四次挥手

1、客户端发送断开TCP连接请求的报文,其中报文中包含seq序列号,是由发送端随机生成的,并且还将报文中的FIN字段置为1,表示需要断开TCP连接。(FIN=1,seq=x,x由客户端随机生成)

2、服务端会回复客户端发送的TCP断开请求报文,其包含seq序列号,是由回复端随机生成的,而且会产生ACK字段,ACK字段数值是在客户端发过来的seq序列号基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP断开请求已经得到验证。(FIN=1,ACK=x+1,seq=y,y由服务端随机生成)

3、服务端在回复完客户端的TCP断开请求后,不会马上进行TCP连接的断开,服务端会先确保断开前,所有传输到A的数据是否已经传输完毕,一旦确认传输数据完毕,就会将回复报文的FIN字段置1,并且产生随机seq序列号。(FIN=1,ACK=x+1,seq=z,z由服务端随机生成)

4、客户端收到服务端的TCP断开请求后,会回复服务端的断开请求,包含随机生成的seq字段和ACK字段,ACK字段会在服务端的TCP断开请求的seq基础上加1,从而完成服务端请求的验证回复。(FIN=1,ACK=z+1,seq=h,h为客户端随机生成)

五.前端框架(复习指引)

该章节,本计划列出所有知识点。后续发现有很多好文,再加上笔者时间不足,

避免本文没了下文,笔者做一个简单的指引。(该章节后续有时间,会单独出文章,时间暂不确定,有兴趣就期待吧)