# 知识整理
对自己的前端知识进行一个梳理
# JavaScript
# 数据类型
# 7种简单的数据类型
- Undefined
- Null
- Boolean
- Number
- String
- Symbol
- BigInt (ES10 草案)
# 1种复杂数据类型
- Object(Function 是 Object 的子类,即继承于 Object)
# 判断数据类型
Object.prototype.toString.call()可以鉴别所有的类型 结果为[object ,object ],[object Undefined]
instanceof
instanceof
的内部机制是通过判断对象的原型链中是不是能找到类型的prototype
。使用
instanceof
判断一个对象是否为数组,instanceof
会判断这个对象的原型链上是否会找到对应的Array
的原型,找到返回true
,否则返回false
。但
instanceof
只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 truetypeof
只对基本类型有用。但不包括null(因为js的所有对象在底层都是二进制的,js把前三位为0的表示为object,null全为0)
- 对于基本类型,除 null 以外,均可以返回正确的结果。
- 对于引用类型,除 function 以外,一律返回 object 类型。
- 对于 null ,返回 object 类型。
- 对于 function 返回 function 类型。
基本类型存放在栈中。对象数据类型存放在堆中。
对于赋值
操作,原始类型的数据直接完整地复制变量值,对象数据类型的数据则是复制引用地址。
# 深拷贝|浅拷贝
当变量复制引用类型值的时候,同样和基本类型值一样会将变量的值复制到新变量上,不同的是对于变量的值,它是一个指针,指向存储在堆内存中的对象(JS规定放在堆内存中的对象无法直接访问,必须要访问这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值,所以引用类型的值是按引用访问)
浅拷贝
Object.assign
ES6中拷贝对象的方法,接受的第一个参数是拷贝的目标,剩下的参数是拷贝的源对象(可以是多个)
拓展运算符
Array.prototype.slice
Array.prototype.concat
深拷贝
JSON.parse(JSON.stringify)
如果obj里面有时间对象,时间将只是字符串的形式。而不是时间对象;
如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
递归
递归地狱回调可以通过return的方法解决
# undefined与null的区别
undefined
是 Undefined
类型的值,表示未定义。任何变量在赋值前都是 Undefined
类型,值为 undefined
。由于undefined
只是全局作用域下的一个属性(变量),并非关键字。undefined
属性的属性特性 ,而在函数作用域内是可以随意改写 undefined
的。这也是建议使用 void 0
来表示 undefined
的来源
Null
类型也只有一个值,就是 null
,它的语义表示空值,与 undefined
不同,null
是 JavaScript
关键字,所以在任何代码中,你都可以放心用 null
关键字来获取 null
值。
# 隐式转换
涉及最多的两个操作符+ ==
- * / 这些运算符只会针对number类型,故转换的结果只能是转换成number类型
隐式转换中主要涉及到三种转换:
1、将值转为原始值,ToPrimitive()。
2、将值转为数字,ToNumber()。
3、将值转为字符串,ToString()。
# 原型-原型链
构造函数
可以通过
new
来 新建一个对象 的函数。原型对象
一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个
JavaScript
对象中都包含一个__proto__
(非标准)的属性指向它爹(该对象的原型),可obj.__proto__
进行访问实例
通过构造函数和
new
创建出来的对象,便是实例。 实例通过__proto__
指向原型,通过constructor
指向构造函数
实例.__proto__ === 原型
原型.constructor === 构造函数
构造函数.prototype === 原型
原型链
原型链是由原型对象组成,每个对象都有 __proto__
属性,指向了创建该对象的构造函数的原型,__proto__
将对象连接起来组成了原型链。是一个用来实现继承和共享属性的有限的对象链。
属性查找机制: 当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象Object.prototype
,如还是没找到,则输出undefined
;
属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用: b.prototype.x = 2
;但是这样会造成所有继承于该对象的实例的属性发生改变。
# 作用域和闭包
# 执行机制
# THIS
调用位置—— 调用位置就是函数在代码中被调用的位置
最重要的是要分析调用栈(就是为了到达当前执行位置所调用的所有函数)。我们关心的 调用位置就在当前正在执行的函数的前一个调用中
function baz(){
//当前的调用栈是baz
//因此调用位置是全局作用域
console.log('baz')
bar() //bar的调用位置
}
function bar(){bar
//当前的调用栈是baz -> bar
//因此调用位置是baz
console.log('bar')
foo() //foo的调用位置
}
function foo(){
//当前的调用栈是baz -> bar -> foo
//因此调用位置是bar
console.log('foo')
}
baz() //baz的调用位置
绑定规则
1、默认绑定
function foo(){
console.log(this.a)
}
var a = 2
foo() //2
那么我们怎么知道这里应用了默认绑定呢?可以通过分析调用位置来看看 foo() 是如何调 用的。在代码中, foo() 是直接使用不带任何修饰的函数引用进行调用的,因此只能使用 默认绑定,无法应用其他规则。
2、隐式绑定
function foo(){
console.log(this.a)
}
var obj = {
a:2,
foo:foo
}
obj.foo() //2
调用位置会使用 obj 上下文来引用函数,因此你可以说函数被调用时 obj 对象“拥 有”或者“包含”它。当 foo() 被调用时,它的落脚点确实指向 obj 对象。当函数引 用有上下文对象时, 隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。因为调 用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的
3、显式绑定
function foo(){
console.log(this.a)
}
var obj = {
a:2
}
foo.call(obj) //2
4、new绑定
使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
- 创建(或者说构造)一个全新的对象。
- 这个新对象会被执行 [[ 原型 ]] 连接。
- 这个新对象会绑定到函数调用的 this。
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
优先级
默认绑定最低的
显示绑定大于隐式绑定
new绑定大于隐式绑定
- 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。 var bar = new foo()
- 函数是否通过 call、 apply(显式绑定)或者硬绑定调用?如果是的话, this 绑定的是 指定的对象。 var bar = foo.call(obj2)
- 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话, this 绑定的是那个上 下文对象。 var bar = obj1.foo()
- 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到 全局对象。 var bar = foo()
# let / const / var
let,const用于声明变量,用来替代老语法的var关键字,与var不同的是,let/const会创建一个块级作用域(通俗讲就是一个花括号内是一个新的作用域)
let
不存在变量提升,如果在还未声明是使用会报错ReferenceError
const
const声明变量的时候必须赋值,否则会报错,同样使用const声明的变量被修改了也会报错
const声明变量不能改变,如果声明的是一个引用类型,则不能改变它的内存地址
# 深入数组
# 计算机网络
# 应用层
应用层规定了向用户提供应用服务时通信的协议,如:
TCP/IP 协议族内预存了各类通用的应用服务协议。比如,FTP(File Transfer Protocol,文件传输协议)和DNS(Domain Name System,域名系统)服务就是其中的两类以及HTTP协议。
# 传输层
传输层对接上层应用层,提供处于网络连接中两台计算机之间的数据传输所使用的协议。
在传输层有两个性质不同的协议:TCP(Transmission Control Protocol,传输控制协议)和UDP(User Data Protocol,用户数据报协议)。
TCP协议是全双工的,即发送数据和接收数据是同步进行的,就好像我们打电话一样,说话的同时也能听见。TCP协议在建立和断开连接时有三次握手和四次挥手,因此在传输的过程中更稳定可靠但同时就没UDP那么高效了。
UDP协议是面向无连接的,也就是说在正式传递数据之前不需要先建立连接。UDP 协议不保证有序且不丢失的传递到对端,也就是说不够稳定,但也正因如此,UDP协议比TCP更加高效和轻便。
# 网络层
网络层规定了数据通过怎样的传输路线到达对方计算机传送给对方(IP协议等)。
与对方计算机之间通过多台计算机或网络设备进行传输时,网络层所起的所用就是在众多的选项内选择一条传输路线。就跟携程提供的回家路线图作用一样。
# 数据链路层
用来处理连接网络的硬件部分,包括控制操作系统、硬件的设备驱动、NIC(Network Interface Card,网络适配器,即网卡),及光纤等物理可见部分(还包括连接器等一切传输媒介)。硬件上的范畴均在链路层的作用范围之内。
# 物理层
光猫等设备
# 状态码
HTTP状态码表示客户端HTTP请求的返回结果、标识服务器处理是否正常、表明请求出现的错误等。
2XX | 成功(这系列表明请求被正常处理了) |
---|---|
200 | OK,表示从客户端发来的请求在服务器端被正确处理 |
204 | No content,表示请求成功,但响应报文不含实体的主体部分 |
206 | Partial Content,进行范围请求成功 |
3XX | 重定向(表明浏览器要执行特殊处理) |
---|---|
301 | moved permanently,永久性重定向,表示资源已被分配了新的 URL |
302 | found,临时性重定向,表示资源临时被分配了新的 URL |
303 | see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源(对于301/302/303响应,几乎所有浏览器都会删除报文主体并自动用GET重新请求) |
304 | not modified,表示服务器允许访问资源,但请求未满足条件的情况(与重定向无关) |
307 | temporary redirect,临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求 |
4XX | 客户端错误 |
---|---|
400 | bad request,请求报文存在语法错误 |
401 | unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息 |
403 | forbidden,表示对请求资源的访问被服务器拒绝,可在实体主体部分返回原因描述 |
404 | not found,表示在服务器上没有找到请求的资源 |
5XX | 服务器错误 |
---|---|
500 | internal sever error,表示服务器端在执行请求时发生了错误 |
501 | Not Implemented,表示服务器不支持当前请求所需要的某个功能 |
503 | service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求 |
# 首部字段
下面是请求首部和响应首部中的字段名称和作用:
请求首部 | 作用(请求报文专用) |
---|---|
Accept | 能正确接收的媒体类型:application/json text/plain |
Accept-Charset | 能正确接收的字符集: unicode-1-1 |
Accept-Encoding | 能正确接收的编码格式列表:gzip deflate |
Accept-Language | 能正确接收的语言列表:zh-cn,zh;1=0.9,en,1=0.8 |
Authorization | 客户端认证信息:Bearer dSdSdFFlsfdjasd123 ,一般存token用 |
Cookie | 发送给服务器的Cookie信息 |
Expect | 期待服务端的指定行为 |
From | 请求方邮箱地址 |
Host | 服务器的域名,用于区分单台服务器多个域名的虚拟主机,是HTTP/1.1唯一必须包含的字段。 |
If-Match | 两端资源标记比较,只有判断条件为真服务端才会接受请求:If-Mach: "123456 ,和服务端文件标记比较 |
If-Modified-Since | 本地资源未修改返回 304(比较时间) |
If-None-Match | 本地资源未修改返回 304(比较标记) |
User-Agent | 客户端信息 |
Max-Forwards | 限制可被代理及网关转发的次数 |
Proxy-Authorization | 向代理服务器发送验证信息 |
Range | 请求某个内容的一部分,配合If-Range 使用 |
Referer | 请求发起页面的原始URI |
TE | 传输编码方式 |
响应首部 | 作用(响应报文专用) |
---|---|
Accept-Ranges | 告知客户端服务器是否可接受范围请求,是bytes ,否none |
Age | 资源在代理缓存中存在的时间 |
ETag | 资源标识,资源发生变化时标识也会发生改变 |
Location | 客户端重定向到某个 URL |
Proxy-Authenticate | 向代理服务器发送验证信息 |
Server | 服务器名字:Apache Nginx |
WWW-Authenticate | 获取资源需要的认证方案 |
Set-Cookie | 需要存在客户端的信息,一般用于识别用户身份 |
实体首部 | 作用(补充请求报文或响应报文相关信息) |
---|---|
Allow | 资源的正确请求方式:GET HEAD POST |
Content-Encoding | 内容的编码格式:gzip deflate |
Content-Language | 内容使用的语言:zh-CN |
Content-Length | request body 长度(即实体主体的大小): |
Content-Location | 返回数据的备用地址 |
Content-MD5 | Base64加密格式的内容 MD5检验值 |
Content-Range | 响应主体的内容范围 |
Content-Type | 内容的媒体类型(如'application/json;charset=UTF-8'则会发送预检请求) |
Expires | 内容的过期时间 |
Last_modified | 内容的最后修改时间 |
# 浏览器缓存
缓存对于前端性能优化来说是个很重要的点,良好的缓存策略可以降低资源的重复加载提高网页的整体加载速度。
- 通常浏览器缓存策略分为两种:强缓存和协商缓存。
强缓存
实现强缓存可以通过两种响应头实现:
Expires
和Cache-Control
。强缓存表示在缓存期间不需要请求,state code
为200
Expires: Wed, 22 Oct 2018 08:41:00 GMT
Expires
是HTTP / 1.0
的产物,表示资源会在Wed
,22 Oct 2018 08:41:00 GMT
后过期,需要再次请求。并且Expires
受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
Cache-control: max-age=30
Cache-Control
出现于HTTP / 1.1
,优先级高于Expires
。该属性表示资源会在30
秒后过期,需要再次请求。
协商缓存
- 如果缓存过期了,我们就可以使用协商缓存来解决问题。协商缓存需要请求,如果缓存有效会返回
304
。 - 协商缓存需要客户端和服务端共同实现,和强缓存一样,也有两种实现方式
Last-Modified 和 If-Modified-Since
Last-Modified
表示本地文件最后修改日期,If-Modified-Since
会将Last-Modified
的值发送给服务器,询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。- 但是如果在本地打开缓存文件,就会造成
Last-Modified
被修改,所以在HTTP / 1.1
出现了ETag
ETag 和 If-None-Match
ETag
类似于文件指纹,If-None-Match
会将当前ETag
发送给服务器,询问该资源ETag
是否变动,有变动的话就将新的资源发送回来。并且ETag
优先级比Last-Modified
高
选择合适的缓存策略
对于大部分的场景都可以使用强缓存配合协商缓存解决,但是在一些特殊的地方可能需要选择特殊的缓存策略
- 对于某些不需要缓存的资源,可以使用
Cache-control: no-store
,表示该资源不需要缓存 - 对于频繁变动的资源,可以使用
Cache-Control: no-cache
并配合ETag
使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。 - 对于代码文件来说,通常使用
Cache-Control: max-age=31536000
并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件