前端复习1

1,063 阅读47分钟

数据结构

散列表 hashMap

hashmap查找的时间复杂度是1
hashmap中key是关键字 是通过哈希函数映射找到地址 然后地址中存放着value。
像map,对象,数组,这种key:value结构都是类似hashmap,性质一样的。
数组通过索引查找一个元素的时间复杂度是1,通过顺序查找遍历时的时间复杂度是O(n),二分法查找的时间复杂度是log以2为底n的对数,通过哈希查找的时间复杂度是1

计算机基础

线程的私有资源: 线程ID,寄存器组的值,线程的堆栈
任何语言经过编译之后将内存分为以下几个区域
(1)栈(stack):由编译器进行管理,自动分配和释放,存放函数调用过程中的各种参数、局部变量、返回值以及函数返回地址。操作方式类似数据结构中的栈。
(2)堆(heap):用于程序动态申请分配和释放空间。C语言中的malloc和free,C++中的new和delete均是在堆中进行的。正常情况下,程序员申请的空间在使用结束后应该释放,若程序员没有释放空间,则程序结束时系统自动回收。注意:这里的“堆”并不是数据结构中的“堆”。
(3)全局(静态)存储区:分为DATA段和BSS段。DATA段(全局初始化区)存放初始化的全局变量和静态变量;BSS段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。
(4)文字常量区:存放常量字符串。程序结束后由系统释放。
(5)程序代码区:存放程序的二进制代码。

寄存器和内存有什么区别

寄存器是CPU的主要组成部分,用来暂时存放参与运算的数据和运算结果。寄存器拥有非常高的读写速度,所以在寄存器之间的数据传送非常快。
CPU理解为是寄存器的集合体,程序计数器,累加寄存器,标志寄存器,指令寄存器和栈寄存器只有一个,其他的寄存器一般会有多个。
计算机中所有程序的运行都是在内存中进行的,用于暂时存放CPU中的运算数据,和与外部存储器交换的数据。只要计算机在运行中,操作系统就会把需要运算的数据从内存调到CPU中进行运算,当运算完成后CPU再将结果传送出来,

进程与线程的区别

根本区别: 进程是资源分配的最小单位,线程是程序执行的最小单位
地址空间: 进程有自己独立的地址空间,线程基本上不拥有系统资源,只拥有一点在运行中必不可少的资源,(如线程ID,一组寄存器例如程序计数器和栈)但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
切换开销
blog.csdn.net/L1376333836…
CPU 上下文指的就是 CPU 寄存器的一些设置,
进程切换时要切页表,页表就可以将虚拟地址转换为物理内存地址,进程切换包含了CPU加载上下文+CPU执行+CPU保存上下文
线程共享了进程的上下文执行环境,
线程切换只需要保存线程的上下文(相关寄存器状态和栈的信息)就好了
通信方面
进程间通信方式:
进程之间交换数据要靠内核,在内核中开辟一块缓冲区,进程1把数据从用户空间复制到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信
(1) 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程的血缘关系通常指父子进程关系。
(2)有名管道:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。
(3)信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段
(4)消息队列(message queue):消息队列是由消息组成的链表,存放在内核中 并由消息队列标识符标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(5)信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某一事件已经发生。
(6)共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,共享内存是最快的IPC方式, (7)套接字(socket):套接口也是一种进程间的通信机制,与其他通信机制不同的是它可以用于不同及其间的进程通信。
线程间通信方式:
线程间的通信一般采用四种方式:全局变量方式、消息传递方式、参数传递方式和线程同步法

  • 全局变量法:线程间可以通过直接读写同一进程中的数据段,如全局变量来进行通信。

  • 消息传递方式:每一个线程都拥有自己的消息队列,线程之间利用消息来传递信息

  • 参数传递方式:主线程创建子线程并让其子线程为其完成特定的任务,主线程在创建子线程时,可以通过传给线程函数的参数和其通信。

  • 线程同步:线程间通信的主要目的是用于线程同步,所以线程没有像进程通信中用于数据交换的通信机制。

  1. 锁机制
    *互斥锁(独占锁):每个对象都对应于一个可称为互斥锁的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象
    *读写锁(共享锁)允许多个线程同时读共享数据,而对写操作是互斥的。
    *条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用
  2. 信号量机制:包括无名线程信号量与有名线程信号量
  3. 信号机制:类似于进程间的信号处理。

锁的好处:确保了共享数据资源只能有一个线程从头到尾完整地执行能解决多线程资源竞争问题。 就比如线程A现在用资源a,上锁,独占锁,其他线程只能等线程A执行完释放资源
锁的坏处:阻止了多线程并发执行,包含锁的某段代码实际上只能单线程执行,效率就打打地下降了

死锁: 若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿意先解锁,互相干等着,程序无法进行下去。
解决死锁问题:

  1. 避免多次锁定。尽量避免同一个线程对多个 Lock 进行锁定。例如主线程要对 A、B 两个对象的 Lock 进行锁定,副线程也要对 A、B 两个对象的 Lock 进行锁定,这就埋下了导致死锁的隐患。
  2. 具有相同的加锁顺序。如果多个线程需要对多个 Lock 进行锁定,则应该保证它们以相同的顺序请求加锁。比如上面的死锁程序,主线程先对 A 对象的 Lock 加锁,再对 B 对象的 Lock 加锁;而副线程则先对 B 对象的 Lock 加锁,再对 A 对象的 Lock 加锁。这种加锁顺序很容易形成嵌套锁定,进而导致死锁。如果让主线程、副线程按照相同的顺序加锁,就可以避免这个问题。
  3. 使用定时锁。程序在调用 acquire() 方法加锁时可指定 timeout 参数,该参数指定超过 timeout 秒后会自动释放对 Lock 的锁定,这样就可以解开死锁了。
  4. 死锁检测。死锁检测是一种依靠算法机制来实现的死锁预防机制,它主要是针对那些不可能实现按序加锁,也不能使用定时锁的场景的。

TCP如何保证可靠性传输

  • 校验和
  • 序列号和确认应答:TCP传输时为每个字节的数据都进行了编号称为序列号。服务端收到后会发送ACK报文,ack确认序列号
  • 超时重传:发送方在发送完数据后等待一个时间,时间到达没有接收到ACK报文,那么对刚才发送的数据进行重新发送
  • 连接管理:三次握手、四次挥手
  • 流量控制:解决发送方和接收方速度不同而导致的数据丢失问题,流量控制用滑动窗口的形式解决问题。接收端将自己可以接受的缓冲区大小放入TCP首部的“窗口大小”字段,通过ACK通知发送端。
    • 滑动窗口:TCP连接中有发送方和接收方,发送方会维护一个发送窗口,接收方会维护一个接收窗口。发送窗口包括已经发送,还没有收到应答的数据和可以发送但未发送的数据,发送端根据接收端的应答和网络拥塞确定发送窗口大小。
  • 拥塞控制:拥塞控制是为了解决过多的数据注入到网络,导致网络奔溃,超过负荷,拥塞控制的用的是拥塞窗口解决问题的

TCP UDP 最大报文是1460 和1472

在应用层,你的Data最大长度为1472。当我们的UDP包中的数据多于MTU(1472)时,发送方的IP层需要分片fragmentation进行传输,而在接收方IP层则需要进行数据报重组,由于UDP是不可靠的传输协议,如果分片丢失导致重组失败,将导致UDP数据包被丢弃。

TCP和UDP的区别:

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的,
4、UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
5、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
6、TCP首部开销20字节;UDP的首部开销小,只有8个字节
7、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

七层网络模型

三次握手、四次挥手

  • 三次握手

第三次握手是为了向服务端传递一个信息就是我客户端可以正常接收服务端发来的连接请求报文。
SYN是连接请求报文 seq连接请求序列号
ACK是响应报文 ack是响应序列号

  • 四次挥手

为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为三次握手的时候,服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。但是关闭连接时,服务端收到FIN报文后,服务端因为有数据在传输,所以先发送ACK应答报文。等数据传输完毕后再发送FIN+AC。
为什么客户端要等待2MSL
1、客户端要保证客户端发送的ACK应答被服务端正常接收了,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
2、防止“已失效的连接请求报文段”出现在本连接中。客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。

http协议

http是超文本传输协议,是应用层协议,由请求和响应构成,定义了web浏览器与web服务器请求和应答的标准,是建立在TCP之上的无状态协议

请求方法

http1.0只有GET、Head、POST

  • GET :请求指定页面信息,并返回实体主体
  • HEAD:类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
  • POST:向指定资源提交数据进行处理(例如提交表单)
  • PUT:从客户端向服务端传送的数据取代指定的文档的内容
  • DELECTE:请求服务器删除指定的文档的内容
  • CONNECT:预留给能够将连接改为管道方式的代理服务器
  • OPTIONS:允许客户端查看服务器的性能
  • TRACE:回显服务器收到的请求,主要用于测试或诊断
  • PATCH:对PUT方法的补充,用来对已知资源进行局部更新

get和post的区别

getpost
GET请求会被浏览器主动cachePOST不会,除非手动设置
请求参数会被完整保留在浏览器历史记录post的参数不会保留
GET在浏览器回退时是无害的POST会再次提交请求
对参数的数据类型,GET只接受ASCII字符而POST没有限制
GET参数通过URL传递POST放在Request body中
url长度限制了传递参数的长度无限制
url编码多种编码方式
用于信息获取向服务器传递数据
一个TCP数据包,浏览器把header data一并发送两个TCP数据包,先发送header,响应100后发送data
在以下情况中,请使用 POST 请求:
  1. 无法使用缓存文件(更新服务器上的文件或数据库)
  2. 向服务器发送大量数据(POST 没有数据量限制)
  3. 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

请求头和响应头

  • 请求
    请求行 (请求方法,url, http版本)
    请求头
    Accept:浏览器能够处理的数据格式
    Accept-Charset:浏览器能够显示的字符集
    Accept-Encoding:浏览器能够处理的压缩编码
    Accept-Language:浏览器当前设置的语言
    accept系列请求头相当于内容协商机制 content-Type:说明了报文体内对象的媒体类型(text,imge,application/xml/json/x-www-form-urlencoded) Connection:keep-alive/closed 浏览器与服务器之间连接的类型
    Cookie:当前页面设置的任何Cookie
    Host:发出请求的页面所在的域,由服务器名+域名组成
    Referer:发出请求的页面的URL
    User-Agent:用来描述客户端浏览器相关信息,可以用来区分PC端页面和移动端页面
    If-none-match:其实就是上回返回的资源的Etag标识符
    If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(某个页面缓存时间)
    空行
    请求体

  • 响应
    响应行(http版本,状态码,状态码描述短语)
    响应头Date:表示消息发送的时间
    Location: www.it315.org/index.jsp(控… Server:apache tomcat(服务器的类型)
    Content-Encoding: gzip(服务器发送的压缩编码方式)
    Content-Length: 80(服务器发送显示的字节码长度)
    Content-Language: zh-cn(服务器发送内容的语言和国家名)
    Content-Type: image/jpeg; charset=UTF-8(服务器发送内容的类型和编码类型)
    Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务器最后一次修改的时间)
    Refresh: 1;url=www.it315.org(控制浏览器1秒钟后转发URL所指向的页面) Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务器发送Cookie相关的信息)
    Expires: -1(服务器控制浏览器不要缓存网页,默认是缓存)
    Cache-Control: no-cache(服务器控制浏览器不要缓存网页)
    Pragma: no-cache(服务器控制浏览器不要缓存网页)
    Connection: close/Keep-Alive(HTTP请求的版本的特点)
    Etag:资源的标识符
    (空行)
    响应体

状态码

100 Continue 继续,一般在发送post请求时,发送了http header之后服务端将返回此信息,表示确认,之后发送具体参数信息
101 切换协议,
200 OK 正常返回信息
201 Created 请求成功并且服务器创建了新的资源
202 Accepted 服务器已接受请求,但尚未处理
203 非授权信息,传回来一个副本
206 服务器成功处理了部分get请求,http的断点续传 301 Moved Permanently 请求的网页已永久移动到新位置
302 Found 临时性重定向,如果客户端发出非GET、HEAD请求后,收到服务端的302状态码,那么就不能自动的向新URI发送重复请求,除非得到用户的确认(例如post请求需要用户确认后再次发送post请求)。但是,很多浏览器都把302当作303处理了,都会自动把POST请求变为GET请求(不用用户确认)。
303 指示客户端可以自动用GET方法重定向请求location中的url,无需用户确认。
304 Not Modified 自从上次请求后,请求的网页未修改过
307 临时重定向,HTTP1.1文档中307状态码则相当于HTTP1.0文档中的302状态码,当客户端的POST请求收到服务端307状态码响应时,需要跟用户询问是否应该在新URI上发起POST方法,也就是说,307是不会把POST转为GET的。
303和307的存在,归根结底是由于POST方法的非幂等属性引起的
400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求
401 Unauthorized 请求未授权,需要认证
403 Forbidden 被服务器拒绝了,禁止访问
404 Not Found 找不到与URL相匹配的资源
405 客户端请求的方法被禁止了 406:后台的返回结果前台无法解析。 500 Internal Server Error 最常见的服务器端错误
503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)

301重定向 当浏览器接收到服务端301时,会将original-url和redirect-url1存储在浏览器缓存中,当再次请求original-url时,浏览器会从本地缓存中读取redirect_url1直接进行跳转,不再请求服务端。
在浏览器未清理缓存或缓存未失效的情况下,即使服务端将重定向地址修改为redirect-url2,浏览器依然会跳转到redirect_url1。
新的永久性的URI应当在响应的Location头中返回。除非这是一个HEAD请求(响应的实体中应当包含指向新的URI的超链接及简短说明)
如果这不是一个GET或者HEAD请求,因此浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
302重定向 浏览器请求一个url,服务器响应状态码是302的时候,浏览器会再次对新的临时的url发起请求
临时URI应该由响应头部中的 Location 字段给出。
只有当服务器发出 Cache-Control或Expires头字段进行指示,此响应才能被缓存,否则不能被缓存。
如果在除 GET 或 HEAD 两种请求方法之外的请求时,接收到302状态码,客户端不得自动重定向请求,除非用户可以确认;否则可能会更改发出请求的条件。

浏览器输入url到页面展示的全部过程

1.输入url
2.浏览器的应用层DNS解析,获得IP地址
3.根据IP+端口,浏览器发起http请求
4.请求到达传输层,tcp协议通过三次握手为传输报文提供安全可靠的字节流服务。通过对大块数据的分割成一个个报文段的方式传输。
5.建立连接后,网络层将http的请求数据包进行路由分发
6.数据链路层将比特封装成数据帧并传递,请求阶段完成
7.接收方收到请求之后,进行请求文件资源的寻找并响应报文
8.浏览器收到http响应
9.关闭TCP连接(四次挥手)
10.浏览器解析html->DOM树,处理css->层叠样式表模型,两者合并为渲染树
11.布局(计算每个节点的位置,包含的元素)+绘制到浏览器

DNS解析

1、查找浏览器缓存->操作系统缓存->本地域名服务器(递归查询)
2、若本地域名服务器没有查询到,则跳转到根域名服务器(保存着顶级域名服务器地址)
3、根域名服务器返回本地域名服务器顶级域名服务器地址
4、本地域名服务器向顶级域名服务器请求
5、顶级域名服务器查找该域名对应的域名服务器地址 。
6、域名服务器查找对应的IP地址,返回给本地域名服务器,本地域名服务器进行缓存
7、本地域名服务器将IP发送给用户

解决http协议无状态的三种方法

  • cookie
    客户端第一次请求,服务端通过set-cookie响应头设置cookie,客户端存储cookie(key/value在硬盘上),下次请求的时候带上
  • session
    Session是通过服务器来保持状态的。在服务器端程序运行的过程中创建的,在创建了Session的同时,服务器会为该Session生成唯一的Session id,在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;而这个Session id在随后的请求中被用来查找已经创建的Session;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session.
    客户端:session id 存储在cookie里,session id:session id值
    服务端:session id值 :session(哈希表)
  • token
    token是服务端生成的一串字符串,作为客户端请求时的令牌,第一次登录时,服务端生成Token,并将它返回到客户端,客户端以后请求的时候带上Token前来请求数据即可。
    token生成
    1.将荷载payload,以及Header信息进行Base64加密,形成payload密文,header密文。
    2.将形成的密文用句号链接起来,用服务端秘钥进行HS256加密,生成签名.
    3.将前面的两个密文后面用句号链接签名形成最终的token返回给客户端
    tokenu验证
    (1)服务端解析第一部分(header密文),用Base64解密,可以知道用了什么算法进行签名,此处解析发现是HS256。
    (2)服务端使用原来的秘钥与密文(header密文+"."+payload密文)同样进行HS256运算,然后用生成的签名与token携带的签名进行对比,若一致说明token合法,不一致说明原文被修改。
    (3)判断是否过期,客户端通过用Base64解密第二部分(payload密文),可以知道荷载中授权时间,以及有效期。通过这个与当前时间对比发现token是否过期。
cookietokenSession
功能存储验证存储
存储位置存储在客户端存储在客户端(http的authorization头,localstorage,sessionstorage,cookie),不影响服务器性能,需要额外的时间开销存储在服务端,时间上快一些
有效期Expires属性解密payload密文SESSINID在客户端cookie的有效期为-1,永久有效。session在服务器的默认有效时间是30分钟
特点简单轻量,数量有限可扩展性好,多平台跨域只支持验证过的服务器
安全SSL加密,XSS(设置HttpOnly),CSRFCSRF用token验证

https

https就是将http协议放到ssl/tsl层加密后,在IP层组成数据包去传输,保证数据安全
http://www.阮一峰播客图解SSL协议l
第一步,客户端给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
第二步,服务端确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
第三步,客户端确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,(此处是非对称加密)发给服务端。
第四步,服务端使用自己的私钥,获取客户端发来的随机数(即Premaster secret)。
第五步,客户端和服务端根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(此处是对称加密),用来加密接下来的整个对话过程。

第三步,客户端内置了根证书来验证服务端数字证书的签名,并用公钥进行加密随机数,要求服务端用私钥来解密

*对称加密:DES IDEA
*非对称加密:RSA DSA

  • 加密用到了哪些加密算法

  • 对称加密和非对称加密的区别
    非对称加密公钥和私钥使用不同密钥加密解密,对称加密使用相同的密钥加密解密
    非对称加密复杂,适合数据量小的数据,对称加密相对简单,适合数据量大的数据
    非对称安全,对称没有非对称安全

http1.0、http1.1 http2

  • HTTP 1.0
    HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。

  • HTTP 1.1
    HTTP1.1支持长连接和请求的流水线处理,Connection请求头的值为Keep-Alive时
    HTTP1.1增加host字段
    HTTP/1.1加入了一个新的状态码100(Continue)

  • HTTP2
    多路复用: 即多个请求都通过一个TCP连接并发地完成,对端可以通过帧中的标识知道属于哪个请求,通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
    服务端推送: 服务端能够主动把资源推送给客户端
    新的二进制格式:HTTP/2采用二进制格式传输数据,二进制格式具有更好的解析性和拓展性
    header压缩: 使用了 HPACK 压缩格式对传输的 header进行编码,减少了传输数据的大小。并在两端维护了索引表,用于记录出现过的 header ,后面在传输过程中就可以传输已经记录过的 header 的键名,对端收到数据后就可以通过键名找到对应的值。

浏览器

浏览器缓存

  • http缓存
    浏览器有个缓存数据库进行http缓存
    强缓存优先级:Pragma>Cache-Control>expires。
    Cache-control(http强缓存中的一个值)的取值有以下几种:
    private: 默认为private,客户端可以缓存
    public: 客户端和代理服务器都可缓存
    max-age=xxx: 缓存的内容将在 xxx 秒后失效, max-age<=0 时 向server 发送http 请求确认 ,该资源是否有修改 。有的话 返回200 ,无的话 返回304。
    no-cache: 需要使用对比缓存来验证缓存数据
    no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多越好,so...基本上和它说886)
    If-None-Match:(上一次响应返回的Etag标识)。
    服务器收到If-None-Match 则与被请求资源的唯一标识进行比对,
    不同,说明资源又被改动过,则响应整片资源内容,返回状态码200;
    相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
    if-modified-since(上一次返回的last-modified)
    if-modified-since的值是上一次响应返回的last-modified的值,客户端先从缓存数据库中读取if-modified-since发送到服务器,服务器进行验证对比,要是相同,就是说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache; 要是不同,说明资源又被改动过,则响应整片资源内容,返回状态码200; 如果两者都有,就必须同时验证,并且两者都满足才会返回304 www.cnblogs.com/chenqf/p/63…

ETag 比较的是响应内容的特征值,而Last-Modified 比较的是响应内容的修改时间。这两个是相辅相成的,并不是说有了ETag就不该有Last-Modified,有Last-Modified就不该有ETag。同时传入服务器时,服务器可以根据自己的缓存机制的需要,选择ETag或者是Last-Modified来做缓存判断的依据,甚至可以两个同时参考。

  • websql
    websql这种方式只有较新的chrome浏览器支持,并以一个独立规范形式出现,主要有以下特点:
    它是将数据以数据库的形式存储在客户端,根据需求去读取;
    Web Sql 更方便于检索,允许sql语句查询; 让浏览器实现小型数据库存储功能;

  • indexDB IndexedDB 是一个为了能够在客户端存储可观数量的结构化数据,并且在这些数据上使用索引进行高性能检索的 API。虽然 DOM 存储 对于存储少量数据是非常有用的,但是它对大量结构化数据的存储就显得力不从心了。IndexedDB 则提供了这样的一个解决方案。

  • application cache application cahce是将大部分图片资源、js、css等静态资源放在manifest文件配置中。当页面打开时通过manifest文件来读取本地文件或是请求服务器文件。

  • cacheStorage CacheStorage是在ServiceWorker的规范中定义的。CacheStorage 可以保存每个serverWorker申明的cache对象

  • cookie

  • Cookies是由服务器端生成,发送给浏览器,浏览器会将Cookies的key/value保存到硬盘的某个目录下的文本文件内, Cookies一般存在用户本地终端上,通常经过加密处理

  • localstorage
    1.存储的内容大概20mb
    2.不同浏览器不能共享数据。但是在同一个浏览器的不同窗口中可以共享数据
    3.永久生效,它的数据是存储在硬盘上,并不会随着页面或者浏览器的关闭而清除。必须手动清除
    4.localStorage最好用于性能优化,不能保证数据的实时性(服务端的数据可能会更新);

  • sessionstorage
    1.存储数据到本地。存储的容量5mb左右。
    2.这个数据本质是存储在当前页面的内存中-意味着其它页面和浏览器无法获取数据
    3.它的生命周期为关闭当前页面,关闭页面,数据会自动清除 www.codeceo.com/article/9-b…

浏览器优化

1、减小页面大小(针对html文件)

  • 去除不必要的空格、回车、注释。
  • 将内联的 css 和 js 移到外部文件
  • 页面压缩工具对页面进行压缩,比如:webpack集成的UglifyJS插件,react框架的代码分割(import、React.lazy()、)

2、减少文件数量 减少页面上引用的文件数量可以减少HTTP连接数。 许多JavaScript、CSS 文件可以合并最好合并成一个js 或者 css。
3、减少域名查询 DNS查询和解析域名也是消耗时间的,所以要减少对第三方JavaScript、CSS、图片等资源的引用,不同域名的使用越少越好。
4、缓存重用数据。对重复使用的数据进行缓存。
5、页面元素加载顺序 (js文件会阻塞DOM树,放在最下面或者异步加载) 6、指定图像和table的大小,确定布局。那么它就可以马上显示页面而不要重新做一些布局安排的工作。
7、图片的懒加载

js的垃圾回收机制

  • 标记清除
    这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境变量所占用的内存,只要执行流进入相应的环境,就可能用到他们。当变量离开环境时,就标记为离开环境。 垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

  • 引用计数法
    引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是 1。如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量(例如下面例子中的数组arr就是包含了对e1,e2的引用)又取得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾收集器下次再运行时,它就会释放那些引用次数为零的值所占用的内存。 引用计数保存在哪里 www.jianshu.com/p/5ba70e1f6… 引用技术怎么去做管理 使用散列表来管理引用计数
    用引用计数法会存在内存泄露(内存泄露是指一块被分配的内存既不能使用,又不能回收)

浏览器兼容问题

html

  • ul标签内外边距问题
    ul标签在IE6\IE7中,有个默认的外边距,但是在IE8以上及其他浏览器中有个默认的内边距。解决方法:统一设置ul的内外边距为0

  • IE9以下浏览器不支持HTML5标签
    解决办法:
    1、通过JS的document.creatElement()和style配合使用
    2、通过引用包的形式解决兼容问题

样式兼容

1.不同的浏览器样式存在差异,通过通配符选择器,全局重置样式

 { margin: 0; padding: 0; }

2.IE6双边距问题:IE6在浮动后,又有横向的margin,此时,该元素的外边距是其值的2倍
解决办法:display:block;
IE6下两个float之间会有个3px的bug 解决办法:给右边的元素也设置float:left;
IE6下没有min-width的概念,其默认的width就是min-width
IE6下图片下有空隙产生解决办法:img为display:block
3.当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度
解决方案:超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度
4.有些浏览器图片默认有间距,设置通配符也不管用
解决方案:使用float为img布局,float布局没有间隙
5.IE9以下浏览器不能使用opacity
解决方案:

opacity0.5filter:alfha(opacity=50);
filter:progid:DXlmageTransform.Microsoft.Alfha(style=0,opacity=50);

不同浏览器的内核、前缀

交互兼容性(js)

1.const问题
Firefox下,可以使用const关键字来定义常量;IE下,只能使用var关键字来定义常量。
2.ajax略有不同
IE:ActiveXObject
其他:xmlHttpReuest

浏览器添加事件解绑事件阻止DOM默认行为阻止事件冒泡事件流
一般情况对象.on事件名字=事件处理函数对象.on事件名字=null
google、firfoxaddEventListener("click",命名函数f1,false)默认fase,冒泡removeEventListener("click",命名函数f1,false)e.preventDefault()e.stopPropagation();或者 return false默认是捕获支持捕获和冒泡
IE8attachEvent("onclick",命名函数f1)detachEvent("onclick",f1)window.event.returnValue=falsewindow.event.cancleBubble=true仅冒泡

浏览器Hack

V8引擎

V8是google开发的JavaScript引擎, 它是开源的

V8引擎怎么编译JS代码

当 V8 编译JavaScript 代码时,解析器(parser)将生成一个抽象语法树。语法树是 JavaScript 代码的句法结构的树形表示形式。解释器 Ignition 根据语法树生成字节码。TurboFan 是 V8 的优化编译器将字节码(Bytecode)生成优化的机器代码(Machine Code)

V8引擎为啥这么快?

优化JIT(即时编译): 相较于C++/Java这类编译型语言,JS一边解释一边执行,效率低。V8对这个过程进行了优化:如果一段代码被执行多次,那么V8会把这段代码转化为机器码缓存下来,下次运行时直接使用机器码。
内联(Inlining): 内联特性是一切优化的基础,对于良好的性能至关重要,所谓的内联就是如果某一个函数内部调用其它的函数,编译器直接会将函数中的执行内容,替换函数方法
内嵌缓存(Inline caching) 内嵌缓存就是将初次查找的隐藏类和偏移值保存起来,
隐藏类(Hidden class): 对于JavaScript这种动态语言,变量在运行时可以随时由不同类型的对象赋值,并且对象本身可以随时添加删除成员。访问对象属性需要的信息完全由运行时决定。为了实现按照索引的方式访问成员,V8“悄悄地”给运行中的对象分了类,在这个过程中产生了一种V8内部的数据结构,即隐藏类。隐藏类本身是一个对象。 每次向对象添加新的属性时,旧的隐藏类会通过路径转换切换到新的隐藏类。由于转换的重要性,因此引擎允许以相同的方式创建对象来共享隐藏类。

如何迎合编译器的嗜好编写更优化的代码呢?

对象属性的顺序:始终以相同的顺序实例化对象属性, 以便可以共享隐藏类和随后优化的代码.
避免动态属性: 在实例化后向对象添加属性将强制隐藏类更改, 使用在构造函数中分配对象的所有属性来代替.
方法: 重复执行相同方法的代码将比只执行一次的代码(由于内联缓存)运行得快.
数组:避免键不是增量数字的稀疏数组. 稀疏数组是一个哈希表. 这种阵列中的元素访问消耗较高. 另外, 尽量避免预分配大型数组, 最好按需分配, 自动增加. 最后, 不要删除数组中的元素, 它使键稀疏. cloud.tencent.com/developer/a…

网络安全

同源策略

同源是指协议,域名,端口相同,同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性。用于隔离潜在恶意文件的重要安全机制

  • 受同源策略限制的有:
    cookie localstorage indexDB无法读取
    js和DOM对象
    Ajax请求

  • 不受同源策略限制的有:
    资源跳转:a链接,重定向,表单提交
    资源嵌入:link img script标签
    脚本请求:js发起的ajax请求、dom和js对象的跨域操作

  • 历史上表单一直可以发出跨域请求。AJAX的跨域设计就是,只要表单可以发,AJAX 就可以直接发。但是form表单没有跨域问题,AJAX存在跨域问题,这是因为form表单提交之后不会有任何数据返回,不会去读取任何数据,所以认为是无害的,而AJAX用于异步刷新,会返回数据进行交互

  • 同源策略本质是一个域内的js在未经允许的情况下,不得读取其他源的数据,但浏览器并不阻止向其他源发送请求

跨域方法

  • jsonp
    利用script标签不受同源策略的特点,动态创建script标签,引入js文件,把script标签的src属性,指向一个数据接口的地址,jsonp是需要服务器端的页面进行相应的配合的。服务端通过url模块解析url,得到回调函数,拼接一个回调函数的调用的字符串,将客户端需要的数据传入回调函数,通过res end将这个字符串返回

  • CORS
    www.ruanyifeng.com/blog/2016/0…
    简单请求方法:post get head
    简单请求头:accept accept--language content-language last-event-id content-type(application/x-www-form-urlencoded、multipart/form-data、text/plain) 浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

GET /cors HTTP/1.1          ------------请求行  
Origin: http://api.bob.com  --------本次请求来自哪个源  
Host: api.alice.com 

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true    //跨域请求是否允许携带cookie
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

非简单请求,就自动发出一个"预检"请求

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

允许请求时的响应

HTTP/1.1 200 OK        
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com ---必须的
Access-Control-Allow-Methods: GET, POST, PUT    ---必须
Access-Control-Allow-Headers: X-Custom-Header   ---看请求是否设置了headers

一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

如果服务器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获

  • window.name window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。 a.html页面中使用一个隐藏的iframe来充当一个中间人角色,由iframe通过window.name去获取data.html的数据,然后a.html再去得到iframe获取到的数据。

  • window.postMessage 先指定接收消息的window对象 需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。 www.cnblogs.com/2050/p/3191…

Ajax

Ajax是一种创建交互式网页应用浏览器端开发技术。
Ajax的原理就是通过创建xhr异步调用对象去服务器获取数据,通过js来操作DOM局部更新页面

open方法第三个参数默认true异步,fase(同步)
 var xhr = new XMLHttpRequest()
    xhr.open('GET', './time.php')
    xhr.send()
    xhr.onreadystatechange = function () {
      // 这个事件并不是只在响应时触发,XHR 状态改变就触发
      if (this.readyState !== 4) return
      
      console.log(this.responseText)
    }

readyState 属性 状态 有5个可取值: 0 = 未初始化,1 = 启动, 2 = 发送,3 = 接收,4 = 完成
Ajax 的优点

  1. 局部刷新
  2. 通过异步模式,不阻塞用户,从而提升了用户体验。
  3. AJAX不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
  4. AJAX引擎在客户端运行,承担了一部分本来由服务器承担的工作,从而减少了大用户量下的服务器负载。

Ajax 的缺点

  1. Ajax 不支持浏览器 back 按钮
  2. 安全问题,使用GET请求的话Ajax 暴露了与服务器交互的细节
  3. 对搜索引擎的支持比较弱
  4. 破坏了程序的异常机制
  5. 不容易调试

网站攻击

  • XSS(Cross Site Scripting),跨站脚本攻击
    存储型:即攻击被存储在服务端,常见的是在评论区插入攻击脚本,如果脚本被储存到服务端,那么所有看见对应评论的用户都会受到攻击。
    反射型:攻击者将脚本混在URL里,服务端接收到URL将恶意代码当做参数取出并拼接在HTML里返回,浏览器解析此HTML后即执行恶意代码
    DOM型:将攻击脚本写在URL中,诱导用户点击该URL,如果URL被解析,那么攻击脚本就会被运行。和前两者的差别主要在于DOM型攻击不经过服务端
    防御措施:
    (1) 输入过滤。如输入的数据是否符合预期格式,比如日期格式,Email格式,电话号码
    移除上传的DOM属性,如onerror等 移除用户上传的style节点、script节点、iframe节点等
    对用户输入数据 ' " & < > 空格进行HTML Entity编码
    (2) 输出编码 可以使用系统的安全函数来进行编码 在PHP中,有htmlentities()和htmlspecialchars()两个函数可以满足安全要求。 JavaScript的编码方式可以使用JavascriptEncode。
    (3) 安全编码。开发需尽量避免Web客户端文档重写、重定向或其他敏感操作,同时要避免使用客户端数据,这些操作需尽量在服务器端使用动态页面来实现。
    (4) HttpOnly Web应用程序在设置cookie时,将其属性设为HttpOnly, 就可以避免该网页的cookie被客户端恶意JavaScript窃取,保护用户cookie信息。
    (5)WAF(Web Application Firewall),Web应用防火墙,主要的功能是防范诸如网页木马、XSS以及CSRF等常见的Web漏洞攻击。由第三方公司开发,在企业环境中深受欢迎。
    (6) CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击。 www.cnblogs.com/meituantech… blog.csdn.net/u011781521/…

  • CSRF(Cross Site Request Forgery),即跨站请求伪造
    CSRF攻击的原理:

  1. 登陆受信任的网站A,在本地生成cookie
  2. 在不登出A的情况下,在A网站点击由攻击者构建的一条恶意链接跳转到B网站,然后携带着的用户cookie信息去访问B网站

防范的原理很简单,即使在客户端使用cookie存储token,cookie仅仅是一个存储机制,而不是认证。所以不能单单验证cookie信息来确认身份和合法性就可以防范了。目前的防范思路主要有两种:
1.验证请求来源,通过请求头的Referer或者Origin字段来判断来源。
2.生成随机的token,在请求的时候带上,在服务端验证token。 www.jianshu.com/p/958e6757b…

  • SQL注入攻击
    攻击者在提交表单的时候,在表单上面填写相关的sql语句,而系统把这些字段当成普通的变量发送给服务器端进行sql查询,由攻击者填写的sql会拼接在系统的sql语句上,从而进行数据库的某些操作。
    【防御】
    1、表单过滤,验证表单提交的合法性,对一些特殊字符进行转义处理
    2、数据库权限最小化
    3、查询语句使用数据库提供的参数化查询接口,不要直接拼接SQL
    4、防止SQL注入最好的方法是使用预编译语句

js

作用域 作用域链

函数作用域,块级作用域,全局作用域,定义了数据可被访问的区域
作用域链:当代码在执行的过程中,会创建变量对象(变量对象即表示变量的对象)的作用域链,保证对执行环境中有权访问到的变量对象和函数进行有序访问,作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

函数调用的时候,才会创建函数这个局部环境的变量对象,作为函数执行环境的作用域链的前端
作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

执行环境

js代码解析执行时所处的环境,执行环境定义了变量或函数有权访问的数据,每个执行环境都有一个与之关联的变量对象(variableobject),环境中定义的所有变量和函数都保存在这个对象中。
执行上下文是指代码执行前的准备,包括变量对象、局部变量对象、作用域链
栈顶的执行上下文处于执行中,其它需要排队
全局上下文只有一个处于栈底,页面关闭时出栈
函数执行上下文可存在多个,但应避免递归时堆栈溢出
函数调用时就会创建新的上下文,即使调用自身,也会创建不同的执行上下文

变量提升

函数字面量式的声明和变量提升的结果是一样的,只会把函数名提升,函数整体不提升
函数声明式会将整个函数提升到作用域最前边
函数声明的优先级高于变量声明的优先级

function f() { console.log('I am outside!'); }
(function () {
  if(false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  console.log( f ); //undefined
}());
if里面的函数声明式函数会定义一个全局变量 函数名 = undefined
if 条件句中的 function 会被编译成 函数表达式, 声明会被提升到当前作用域的最顶部, 但是赋值会被留在原地
function f() { console.log('I am outside!'); }
        (function () {

            if (true) {
                // 重复声明一次函数f
                function f() { console.log('I am inside!'); }
            }

            f(); // I am inside!
        }());

function f() { console.log('I am outside!'); }
        (function () {
            f(); // I am outside!
        }());

//函数声明式
 function bar () {} 
//函数字面量式 
 var foo = function () {}

闭包

闭包函数:声明在一个函数中的函数,叫做闭包函数。
闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
使用场景(1)闭包可以缓存数据,如果想要缓存数据,就把数据放在外层函数和内层函数中间 (2)es5没有块级作用域,可以用闭包和立即执行函数模拟

执行过程中,JS引擎会将父函数的上下文从执行栈中移除。但是内部函数会将外部函数的局部活动对象添加到自己的作用域链中。内部匿名函数的作用域链在引用外部包含函数的活动对象。当内部函数执行完毕,JS引擎才会将内部函数的上下文及外部函数的活动对象一并从执行栈中移除。也就是说,即使外部函数执行完毕了,它的活动对象还是不会被销毁。造成内存泄漏!

通过用let替换var ,解决for循环返回一个闭包函数共享一个全局变量i的问题
let声明的变量定义了块级作用域,每次i循环的时候,会创建for循环的活动对象,保存不同的i值,闭包被执行的时候,查找到每个闭包所在的块级作用域中的i

原型链

原型链是一种关系,实例对象和原型对象之间的关系,通过原型(proto)联系, 实例对象的原型_proto_指向的是构造函数中的原型prototype,此时,Person.prototype实例原型又是另一个构造函数Object的实例对象,里面有个_proto_属性指向Object.prototype。原型链顶端null。 Object.prototype.proto === null

new操作符

1.先创建了一个新的空对象
2.然后让这个空对象的__proto__指向构造函数的原型prototype
3.调用构造函数,并将对象作为构造函数的this传进去,如果return 返回的是对象的话就直接返回 return 的内容,没有的话就返回新建的这个对象

function _new(F,...args){
    var instance = {}
    instance._proto_ =F.prototype
    var res = F.call(instance,...args)
    return res instanceof Object ? res : instance
}

继承

www.cnblogs.com/ranyonsue/p…

  • 原型链继承---继承了父类所有的属性和方法,这些继承而来的属性和方法会放到子类的原型中

  • 构造函数继承---在子类型构造函数的内部调用父类型构造函数。只实现了对实例属性和实例方法的继承。无法实现函数复用

  • 组合继承---使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。会调用两次构造函数,效率低

  • 原型式继承---父类对象会被共享。实际上,每次创建新的实例时就会创建父类的副本,子类对象修改某些属性后,父类的同名属性也就被修改了 ECMAScript 5 通过新增 Object.create()方法代表了原型式继承。

function object(o){
function F(){}
F.prototype = o;
return new F();
}
  • 寄生式继承---创建一个仅用于封装继承过程的函数, 使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一点与构造函数模式类似。
function createAnother(original){ 
 var clone = object(original); //通过调用函数创建一个新对象
 clone.sayHi = function(){ //以某种方式来增强这个对象
 alert("hi"); 
 }; 
 return clone; //返回这个对象
}
  • 寄生组合式继承---避免了在 SubType. prototype 上面创建多余的属性。与此同时,原型链还能保持不变; 所谓寄生组合式继承,即通过借用构造函数来继承实例属性和实例方法,通过原型链的混成形式来继承原型方法和原型属性。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
function inheritPrototype(subType, superType){ 
 var prototype = object(superType.prototype); //创建对象
 prototype.constructor = subType; //增强对象
 subType.prototype = prototype; //指定对象
}


function SubType(name, age){ 
 SuperType.call(this, name); 
 this.age = age; 
}

深拷贝与浅拷贝

  • 深拷贝,改变拷贝对象的属性值,原对象不受影响
function extend(obj1,obj2){
    for(var key in obj1){
      var item = obj1[key]
        if(item instanceof Array){
            var obj2[key] = []
            extend(item,obj2[key])
        }
        if(item instaceof Object){
            var obj2[key] = {}
            extend(item,obj2[key])
        }else{
            obj2[key] = item
        }
    }
}
function deepClone(obj1){
		var _obj=JSON.stringify(obj)
		var obj2=JSON.parse(_obj)
		return obj2
	}
热门的函数库lodash,也有提供_.cloneDeep用来做深拷贝;
var _ = require('lodash');
var obj2 = _.cloneDeep(obj1);
jquery 提供一个$.extend可以用来做深拷贝
var $ = require('jquery');
var obj2 = $.extend(true, {}, obj1);
  • 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
Object.assign()实现浅拷贝及一层的深拷贝
var obj2 = Object.assign({}, obj1);
Object,creat(obj1)实现浅拷贝以及深拷贝一层
var obj2 = Object.create(obj1);
  • slice 和concat 对于内部含有嵌套数组,slice和concat实现的是浅拷贝以及一层深拷贝

for-in for-of

  1. for-in是ES5标准,遍历的是key,不需要迭代器接口;for-of是ES6标准,遍历的是value,本质上就是调用迭代器接口产生的遍历器
  2. for...in循环有几个缺点。 数组的键名是数字,但是for...in循环遍历的key是字符串格式。
    for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。遍历对象通常用for-in来遍历对象的键名.
    某些情况下,for...in循环会以任意顺序遍历键名。
  3. for..of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合.for-of遍历得到的是value。所以通常用for(var value of arr)遍历数组。如果是普通对象,可以通过for(var value of obj.value())遍历。对象提供key(),value(),entries()方法将遍历元素返回一个数组

事件

浏览器添加事件解绑事件阻止DOM默认行为阻止事件冒泡事件流
一般情况对象.on事件名字=事件处理函数对象.on事件名字=null
google、firfoxaddEventListener("click",命名函数f1,false)默认fase,冒泡removeEventListener("click",命名函数f1,false)e.preventDefault()e.stopPropagation();或者 return false默认是捕获支持捕获和冒泡
IE8attachEvent("onclick",命名函数f1)detachEvent("onclick",f1)window.event.returnValue=falsewindow.event.cancleBubble=true仅冒泡

事件冒泡、捕获、代理

  • 冒泡 :多个元素嵌套,有层次关系,这些标签都注册了相同的事件,如果里面的元素的事件触发了,外面的元素的该事件自动的触发了。
<div id="div1">我是div1
   <div id="div2">我是div2
     <div id="div3">我是div3
       <div id="div4">我是div4</div>
      </div>
  </div>
</div>

冒泡顺序有里到外,点击4,执行顺序4,3,2,1,
捕获,点击4,执行顺序,1,2,3,4
w3c规定了,任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段。

  • 事件代理
    即是把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务。从触发某事件的元素开始,递归地向上级元素传播事件。事件代理的原理是DOM元素的事件冒泡
    优点:1.可以大量节省内存占用,减少事件注册。比如ul上代理所有li的click事件就很不错。
    2.可以实现当新增子对象时,无需再对其进行事件绑定,对于动态内容部分尤为合适

事件循环

所有同步任务都在主线程上执行,形成一个执行栈,遇到异步任务后,就放到任务队列中。事件循环是先执行宏任务,遇到异步任务后判断其是宏任务还是微任务,如果是宏任务,会创建另一个宏任务放在宏任务队列,是微任务,则添加到微任务队列,当前宏任务的同步任务执行完毕后会清空执行栈,检查微任务队列中是否有微任务,然后执行任务队列中该宏任务产生的微任务,微任务执行完毕后,再进行下一轮宏任务的循环。

(macro)task主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)

microtask主要包含:process.nextTick(Node.js 环境),Promise.then、MutaionObserver

事件队列

js是单线程的,所有同步任务都在主线程上执行,形成一个执行栈,主线程之外,还存在一个任务队列,只要异步任务有了结果,就在任务队列中放置一个事件,一旦执行栈中的同步任务执行完毕,就会执行任务队列中的事件,主线程重复的执行这个过程。

判断数据类型

  1. typeof可以判断 number boole string undefined symbol function Object
  2. instanceof 用于判断一个变量是否属于某个对象的实例。原理是判断这个变量(a)的原型链上有没有某个对象(Array,Object)的原型
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
 var O = R.prototype;
 L = L.__proto__;
 while (true) { 
   if (L === null) 
     return false; 
   if (O === L)  // 这里重点:当 O 严格等于 L 时,返回 true 
     return true; 
   L = L.__proto__; 
 } 
}
  1. 实例对象也有constructor属性指向它的构造函数。因为原型上有这个属性呀
    a.constructor === Array
  2. 基于Object.prototype.isPrototypeOf 。 isPrototypeOf() 方法用于测试一个对象(a)是否存在于另一个对象(Array)的原型链上 Array.prototype.isPrototypeOf(a)
  3. 基于getPrototypeOf Object.getPrototypeOf(a) === Array.prototype
  4. Object.prototype.toString.call(a) === '[object Array]'
  5. ES6新增Array.isArray() 用于确定传递的值是否是一个 Array。

bind call apply()

bind()调用后返回的是一个绑定函数,不是一个普通函数,这个绑定函数已经被定义好哪个函数来调用、this的指向以及传入的参数,所以调用绑定函数重新传参,或者再次使用bind(),apply(),call()方法都不会影响绑定函数的结果。

function myBind(that,...args){
    var funcThis = this
    return function (..._args){
        var finArg =args.concat(_args)
        funcThis.apply(that,finArg)
    }
}

apply要求传入的参数是数组

function myApply(context){
   if(typeof this !== "function"){
       throw new TypeError('error')
   }
   var context = context || window
   var context.fn = this
   var result
   if(arguments[1]){
       result = context.fn(arguments[1])
   }else{
       result = context.fn()
   }
   delete context.fn()
   return result
}
Function.prototype.myCall(context){
   if(typeof this !== 'function'){
       throw new TypeError('error')F
   }
   let context = context || window
   let context.fn = this
   let result
   if(arguments.length>1){
       result = context.fn(arguments.slice(1))
   }else{
       result = context.fn()
   }
   delete context.fn()
   return result
}

防抖和节流

防抖:回调函数只执行一次,期间若有事件触发,则重新计时,在给定时间过后只会被调用一次

function debounce(){
    let timeout
    return function(){
        const args = arguments
        const context = this
        if(timeout){
            clearTimeout(timeout)
        }
        if(immediate){
            var callNow = !timeout
            timeout = setTimeout(function(){
                timeout = null
            },wait)
            if(callNow){
             fn.call(context,args)
            }
        }else{
            timeout = setTimout(function(){
                fn.call(context,args)
                timeout = null
            },wait)
        }
    }
}

节流:不管事件触发多频繁,在规定的时间内函数只调用一次

function throttle(){
let timeout
return function(){
    const args = arguments
    const context = this
    if(!timeout){
        timeout = setTimeout(function(){
            fn.call(context,args)
            timeout = null
        },wait)
    }
}



function throttle(){
let timeout
return function(){
    const args = arguments
    const context = this
    if(!timeout){
         fn.call(context,args)
        timeout = setTimeout(function(){
            timeout = null
        },wait)
    }
}

}

编程范式

面向对象编程

  • 封装 将类的使用和实现分开,只保留部分接口,
  • 继承 子类自动继承其父级类中的属性和方法,并可以添加新的属性和方法或者对部分属性和方法进行重写。继承增加了代码的可重用性。
  • 多态 多个子类中虽然都具有同一个方法,但是这些子类实例化的对象调用这些相同的方法后却可以获得完全不同的结果,多态性增强了软件的灵活性

函数式编程

函数式编程起源是一门叫做范畴论的数学分支,什么是范畴呢,范畴就是满足某种变形关系的所有对象,所以总结范畴的数学模型就是(1)所有对象是集合(2)变形关系是函数
函数式编程要求是纯函数,纯函数的概念很简单就是两点:

  • 无状态: 函数的的运行结果不依赖全局变量,this 指针,IO 操作等。相同的输入,总是相同的输出,完全不依赖外部状态的变化

  • 数据不变: 不修改全局变量,不修改入参。 所有的数据都是不可变的,这意味着如果你想修改一个对象,那你应该创建一个新的对象用来修改,而不是修改已有的对象。

函数式编程的特点

  1. 函数是一等公民,主要就是操作函数
  2. 声明式编程,声明需要做什么,而不是怎么去做
  3. 惰性执行,只在需要的时候执行
  4. 没有副作用,函数没有其他副要功能,函数中最常见的副作用就是随意操纵外部变量

异步编程

设计模式

单例模式即一个类只能构造出唯一实例,单例模式的意义在于共享、唯一
工厂模式即对创建对象逻辑的封装
观察者模式概念很简单:观察者监听被观察者的变化,被观察者发生改变时,通知所有的观察者。观察者模式被广泛用于监听事件的实现
装饰器模式,可以理解为对类的一个包装,动态地拓展类的功能
适配器模式,将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作
代理模式,为一个对象找一个替代对象,以便对原对象进行访问。

css

盒子模型

margin->boder->padding->content
content-box 为标准盒(W3C)模型 你设置的width属性值仅仅是内容的宽度. border-box 为IE盒模型 你设置的width属性值就是盒子的最终的宽度,包含了border和padding和内容。
box-sizing: border-box | content-box

弹性盒子由弹性容器(Flex container)和弹性子元素(Flex item)组成。
弹性容器通过设置 display 属性的值为 flex 或 inline-flex将其定义为弹性容器。 弹性容器内包含了一个或多个弹性子元素

布局

垂直水平居中

  • margin负值法
 body{
            position: relative;
        }
  div{           
            position: absolute;
            left: 50%;
            top: 50%;
            /*使用transform实现元素的居中  百分比是参照元素本身的宽高*/
            /*transform: translate(-50%,-50%);*/
            /*或者下面这样*/
            margin-top: -100px;
            margin-left: -100px;
        }
  • 自适应法
#outer{
            position: relative;
        }
#inner{ 
            margin: auto;
            position: absolute;
            top: 0;left: 0;right: 0;bottom: 0;
        }
  • flex布局法
#outer{
		display: flex;
		align-items: center;
		justify-content:center;
		
	}
	
  • table居中法
 #outer{
            display: table-cell; 
            vertical-align: middle;
        }

两栏布局

  • 使用浮动—float:左侧固定宽高,设置浮动,右侧设置margin-left: 左侧宽度;或者overflow: hidden; 右侧设置具体高度数值或者全局html, body设置100%高度,右侧可以使用百分比,宽度自适应
  • 使用双float+calc()函数:左侧固定宽高,两侧均设置浮动,右侧设置高度,宽度使用calc()函数:width: calc(100% - 左侧宽度);
  • 使用绝对定位—absolute:左侧设置绝对定位,left: 0; top: 0; 右侧设置margin-left: 左侧宽度; 以及自身高度(百分比不起作用),宽度自适应
  • table布局:父元素设置display: table; width: 100%;,左右两侧均设置display: table-cell;,左侧设置固定宽高,右侧设置高度,宽度自适应(注意:左右两侧高度始终跟随着高度最大值保持一致)
  • flex布局:父元素设置display: flex;,左侧设置flex: 0 0 200px;及自身高度,右侧flex: 1;及自身高度

三栏布局

  • 双飞翼布局
 <body>
    <div class="main"><div class="main-inner">中心区</div></div>
    <div class="left">left</div>
    <div class="right">right</div>
  </body>
  
   <style>
      .left,
      .right,
      .main {
        min-height: 200px;
      }
      .left {
        width: 200px;
        background-color: thistle;
      }
      .main {
        background: #999;
      }
      .right {
        width: 300px;
        background-color: violet;
      }
      /* 双飞翼布局重点 */
      .main,
      .right ,
      .left{
        float: left;
      }
      .main {
        width: 100%;
      }
      .main-inner {
        margin-left: 200px;
        margin-right: 300px;
      }
      .left {
        margin-left: -100%;//向左移动一屏的宽度
      }
      .right {
        margin-left: -300px;//left移动后,此时右边界是main,向左移动300px
      }
    </style>
  • 圣杯布局
  • float布局:左侧设置float: left;,右侧设置float: right;,中间部分设置margin-left:左侧宽度;,以及margin-right: 右侧宽度;
  • absolute布局:左中右均设置绝对定位,左侧设置left:0;,右侧设置right:0;,中间部分设置left: 左侧宽度; right: 右侧宽度;
  • table布局:父元素设置display: table; width: 100%;,左中右均设置display: table-cell;,左右两侧设置宽高,中间部分自适应宽度(高度随其中最大值,三者高度保持一致)
  • flex布局:父元素设置display: flex;,左右两侧设置宽高,中间部分设置flex:1;自适应宽度(注意flex布局中若没有设置高度会跟随其他部分的高度)
  • gird布局:父元素设置display: grid;,通过grid-template-rows设置网格高度,通过grid-template-columns设置左中右宽度,中间部分auto自适应宽度
<body>
    <div class="container">
      <div class="main">main</div>
      <div class="left">left</div>
      <div class="right">right</div>
    </div>
  </body>
  
<style type="text/css">
      /*基本样式*/
      .left, .right, .main {
        min-height: 300px;
      }
      .left {
        width: 200px;
        background-color:thistle;
      }
      .main {
        background-color: #999;
      }
      .right {
        width: 300px;
        background-color: violet;
      }
      /* 圣杯布局关键代码 */
      .left, .main, .right {
        float: left;
        position: relative;
      }
      .main {
        width: 100%;
      }
      .container {
        padding-left: 200px;
        padding-right: 300px;
      }
      .left {
        margin-left: -100%;
        left: -200px;
      }
      .right {
        margin-left: -300px;//margin-left会让right块向左移动300px,移动到上方
        right: -300px;
      }
    </style>

flex

flex:1这个知道什么意思吗?
flex 是 flex-grow、flex-shrink、flex-basis的缩写,flex 的默认值是 0 1 auto。 当 flex 取值为 none,则计算值为 0 0 auto

当 flex 取值为 auto,则计算值为 1 1 auto

当 flex 取值为一个非负数字,则该数字为 flex-grow 值,flex-shrink 取 1,flex-basis 取 0%
www.ruanyifeng.com/blog/2015/0…

BFC

www.cnblogs.com/chakson/p/4… 块级格式化上下文,它是一个独立的渲染区域,规定了内部的盒子如何布局,盒子里面的子元素的样式不会影响到外面的元素。
BFC布局规则:
1、内部的box会在垂直方向,一个接一个地放置
2、Box垂直方向的距离有margin决定,属于同一个 BFC中的两个相邻的块级盒在垂直方向(和布局方向有关系)的 margin 会发生折叠。
3、每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)即使存在浮动也是如此
4、BFC的区域不会与float元素重叠
5、BFC就是页面上一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此
6、计算BFC的高度时,浮动元素也参与计算
形成BFC的条件:
1、根元素 2、float属性不为none 3、position为absolute或fixed 4、display为inline-block 5、overflow不为visible

浮动

浮动元素脱离文档流,不占据空间。浮动元素碰到包含它的边框或者浮动元素的边框停留。
高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷)
清除浮动的方法:
1.在浮动的子元素后面添加空标签 clear:both (在包含块里面添加了一个div,该div不与其他浮动元素左右边界重合,所以会到最下面,拉长了包含块也就是父元素的高度) 缺点:添加无意义的标签
2.给父元素添加高度 缺点:不灵活
3.给父元素添加overflow:auto/hidden (形成了BFC,计算BFC的高度时,浮动元素也参与计算)
4.父容器上加伪元素

.clearfix::aftercontent:“ ”;
display:block
clear:both
}
.clearfix{zoom:1}兼容ie6

5、以浮制浮,给父级元素也添加浮动属性缺点:浮动多了容易出现问题。

样式

伪类/伪元素

伪类是针对文档中已有的元素
元素可以定义伪类样式,例如

 a:link {color: #FF0000} /* 点击之前,未访问的链接 */
 a:visited {color: #00FF00} /* 已访问的链接 */ 
 a:hover {color: #FF00FF} /* 鼠标移动到链接上 */ 
 a:focus {color: #000000} /*使用Tab键把聚焦落在链接上*/
 a:active {color: #0000FF} /* 选定的链接 */

class也可以定义伪类

a.red:visited {color:#FF0000;}
<a class="red" href="css-syntax.html">CSS 语法</a>

伪元素是创建了新的元素

权重

!important>内联样式>id选择器>(类选择器|属性选择器|伪类选择器)>标签选择器>*

动画

写在最后,感谢我的大学同学张晗的倾情补充、检查,文章好多引用了一些博客上的内容,如有侵权,联系处理