this的指向
- 对于直接调用的函数来说,不管函数在哪被调用,this一定是window
- 对于对象引用函数来说,谁调用了它,this就指向谁
- 对于new的方法来说,this被永远绑定在对应的方法上,不会被任何方式改变
- 箭头函数是没有this的,箭头函数中的this只取决包裹箭头函数的第一个普通函数的this。另外对箭头函数使用bind这类函数无效
- 对于改变上下文的API,对于这些函数来说,this取决于第一个参数,如果第一个参数为空,那么就是window
- 如果发现多个同时出现,可根据优先级来决定this最终指向哪里
- new的方式优先级最高,其次是bind这些函数,然后就是对象引用函数(obj.foo()),最后就是直接调用函数。
同时,箭头函数的this一旦被绑定,就不会在被任何方式所改变。
JS 分为哪两大类型?都有什么各自的特点?你该如何判断正确的类型?
JS分为原始类型与引用类型
- 原始类型:undefined,null,string,boolean,number,Symbol
- 引用类型:Object、Array、Function
- 原始类型存储的是值,是没有函数可以调用的
- number类型0.1+ 0.2 != 0.3 原因是JS会截取到我们浮点数的一部分,导致从二进制转换出来的数并不是0.1
- string类型是不可变的,无论在string上调用哪种方法,都不会有变化
- typeof判断原始类型 除了null的时候会返回object之外,其余的正常
- instanceof判断对象类型 除了判断函数,会返回function之外,其余的都能返回正常
- 所以有一个更加好的:Object.prototype.toString.call()
存储区别
基本数据类型存储在栈中
引用类型的对象存储于堆中
当我们把变量赋值给一个变量时,解析器首先要确认的就是这个值是基本类型值还是引用类型值
简单类型赋值,是生成相同的值,两个对象对应不同的地址
复杂类型赋值,是将保存对象的内存地址赋值给另一个变量。也就是两个变量指向堆内存中同一个对象
本地存储
区别:
- 存储大小:cookie数据大小不能超过4k,sessionStorage和localStorage虽然也有存储大小的限制,
但比cookie大得多,可以达到5M或更大
- 有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage数据在当前浏览器窗口
关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
- 数据与服务器之间的交互方式,cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端;
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
应用场景:
标记用户与跟踪用户行为的情况,推荐使用cookie
适合长期保存在本地的数据(令牌),推荐使用localStorage
敏感账号一次性登录,推荐使用sessionStorage
闭包
当函数可以记住并且访问所在的词法作用域时,就产生了闭包,即使函数在当前词法作用域外
使用场景
创建私有变量
延长变量的生命周期
一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文
被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的
原型:
- prototype:
- 是函数才会有的属性
- 函数的prototype属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型
- 原型
每一个javaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,
每一个对象都会从原型‘继承’属性(原型也是一个对象)
- __proto__
每一个javaScript对象(null除外)都具有的一个属性,叫__proto__,这个属性会指向该对象的原型
- constructor
每个原型都有一个constructor属性指向关联的构造函数
- 原型链
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的
原型,一直找到最顶层为止(null表示‘没有对象’,既该处不应该有值)
- 注意:
1、当读取person.constructor时,其实person中并没有constructor属性,当不能读取到constructor属性时,会从peroson的原型
也就是Person.prototype中读取,正好原型中有该属性,所以:person.construcotr === Person.prototype.constructor
2、其次是__proto__,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于Person.prototype中,实际上它是来自于
Object.prototype,与其说是一个属性,不如说是一个getter/setter,当使用obj.__proto__时,
可以理解成返回了Object.getPrototypeOf(obj)
bind、call 和 apply 各自区别
- call,apply,bind这三个方法是继承Function.prototype中的,属于实例方法;都是改变this指向的方法
- 普通对象,函数,数组都继承了Function.prototype对象中的三个方法,所以这三个方法可以在对象,数组,函数中使用
- 总结一下call,apply,bind方法:
a:第一个参数都是指定函数内部中this的指向(函数执行时所在的作用域),然后根据指定的作用域,调用该函数。
b:都可以在函数调用时传递参数。call,bind方法需要直接传入,而apply方法需要以数组的形式传入。
c:call,apply方法是在调用之后立即执行函数,而bind方法没有立即执行,需要将函数再执行一遍。有点闭包的味道。
d:改变this对象的指向问题不仅有call,apply,bind方法,也可以使用that变量来固定this的指向。
循环
foreach:遍历数组中的每一项,没有返回值,对原数组没有影响,不支持IE
map:有返回值,可以return出来,对原数组没有影响,只是相当于把原数组克隆一份,把克隆的这一份的数组中的对应项改变了
filter:不会改变原数组,返回新数组,不需要retrun,会直接返回满足条件的数据出来
every:判断是否都满足,全部满足才返回true,只要有一个不满足就返回false
some:判断是否有一个满足,满足一个就返回true,全部不满足才返回false
reduce:累加器,数组中每个值从左到右开始缩减,最终为一个值。接收四个参数:上一次的值,当前的值,当前值的索引,数组
find:返回满足条件的第一条数据,如果都不满足则返回undefined
事件冒泡
从一个具体的元素开始,然后逐级向上传播,从里到外执行事件
阻止事件冒泡:event.stopPropagation()
事件捕获
- 从外到里捕获事件并执行;可以自己选择绑定事件时采用事件捕获还是事件冒泡,方法就是绑定事件时通过addEventListener函数,
- 它有三个参数,第三个参数若是true,则表示采用事件捕获,若是false,则表示采用事件冒泡。
- 不是所有的事件都能冒泡,例如:blur、focus、load、unload
宏任务与微任务
微任务
一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
常见的微任务有:
Promise.then
MutaionObserver
Object.observe(已废弃;Proxy 对象替代)
process.nextTick(Node.js)
宏任务
宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
常见的宏任务有:
script (可以理解为外层同步代码)
setTimeout/setInterval
UI rendering/UI事件
postMessage、MessageChannel
setImmediate、I/O(Node.js)
执行机制是:
执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完
跨域
由于浏览器的同源策略,不同域名、不同端口、不同协议都会构成跨域
同源策略就是浏览器为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的JS进行交互。对于浏览器而言只要域名、
协议、端口其中一个不同就会引发同源策略,从而限制他们之间如下的交互行为:
注意:
1、如果是协议和端口造成的跨域问题“前台”是无能为力的;
2、在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
- 解决跨域问题的方法:
1.跨域资源共享(CORS)
2、通过jsonp跨域
3.通过修改document.domain来跨子域
4.使用window.name来进行跨域
5.使用HTML5的window.postMessage方法跨域
6.通过WebSocket进行跨域
7.图像ping(单向)
8.Nginx代理
http协议(超文本传输协议)
是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
由请求方法、URL、协议版本组成
作用:规定了应用进程间通信的准则
特点:
1、传输效率高
无连接:交换HTTP报文前,不需要建立HTTP连接
无状态:数据传输过程中,不保存任何历史和状态信息
传输格式简单:请求时,只需要传输请求方法和路径
2、传输可靠性高
用TCP作为传输层协议
3、兼容性好
支持B/S、C/S模式
4、灵活性高
HTTP允许传输任意类型的数据对象
OPTIONS
返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性
HEAD
向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。
GET
向特定的资源发出请求。它本质就是发送一个请求来取得服务器上的某一资源。资源通过一组HTTP头和呈现数据(如HTML文本,或者图片或者视频等)返回给客户端。GET请求中,永远不会包含呈现数据。
POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 Loadrunner中对应POST请求函数:web_submit_data,web_submit_form
PUT
向指定资源位置上传其最新内容
DELETE
请求服务器删除Request-URL所标识的资源
TRACE
回显服务器收到的请求,主要用于测试或诊断
CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
get 和 post区别
区别:
get请求无消息体,只能携带少量数据
post请求有消息体,可以携带大量数据
携带数据的方式:
get请求将数据放在url地址中
post请求将数据放在消息体中
GET请求请提交的数据放置在HTTP请求协议头中,而POST提交的数据则放在实体数据中;
GET方式提交的数据最多只能有1024字节,而POST则没有此限制。
常见状态码:
200 OK,表示从客户端发来的请求在服务器端被正确处理
204 No content,表示请求成功,但响应报文不含实体的主体部分
206 Partial Content,进行范围请求
3XX(重定向)
301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
302 found,临时性重定向,表示资源临时被分配了新的 URL
303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源
304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
4XX (客户端错误)
400 bad request,请求报文存在语法错误
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
403 forbidden,表示对请求资源的访问被服务器拒绝
404 not found,表示在服务器上没有找到请求的资源
5XX (服务器错误)
500 internal sever error,表示服务器端在执行请求时发生了错误
501 Not Implemented,表示服务器不支持当前请求所需要的某个功能
503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求
垃圾回收机制
不定期的间歇的寻找到不在使用的变量,并释放掉他们所指的内存,防止内存泄漏
通常两种方式:标记清除,引用计数
标记清除:就是函数执行的时候对声明变量做一个标记,当函数执行完毕后在做一个标记,并对该变量进行删除,回收他们所
占用的内存空间
引用计数:常常会引起内存泄漏;低版本的IE使用这种方式;机制就是跟踪一个值的引用次数,当声明的变量被赋值
给引用类型的时候引用值加1,当这个变量指向其他一个时该值减一,当引用值等于0 的时候,说明没有方法在访问
这个值了,这个就被视为回收的对象。每过一段时间垃圾回收的时候就将其回收
引用计数方法可能导致循环利用,类似死锁,导致内存泄漏
常见内存泄漏的原因
1、全局变量引起的内存泄漏
2、闭包引起的内存泄漏
3、dom清空或删除时,事件未清理导致的内存泄漏
4、循环引用带来的内存泄漏
浏览器的缓存机制
浏览器第一次向服务器发起请求后拿到请求结果,会根据响应报文中的http头的缓存标识,决定是否缓存结果,
是的话就将请求结果和缓存标识存入浏览器缓存中
就像浏览器每次发起请求,都会限制浏览器缓存中查找该请求的结果以及缓存标识
浏览器每次拿到返回的结果都会将该结果和缓存标识存入浏览器缓存中
强缓存就是向浏览器缓存查找该请求结果,并根据该结构的缓存规则来决定是否使用该缓存结果的过程
控制强缓存的字段有Expires和Cache-Control,后者优先级比前者高
协商缓存就是强缓存失败后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否
使用缓存的过程。控制协商缓存的字段分别由:Last-Modified/if-Modified-Since和Etag/If-None-Match
后者优先级比前者高。协商缓存生效,返回304;协商缓存失效,返回200和请求结果
输入 URL 到页面渲染的整个流程
1、输入url地址
2、浏览器进行DNS查询,查找域名对应的IP地址
3、建立TCP连接,浏览器向web服务器发送http请求
4、服务器处理请求,并返回状态码和html文件
5、浏览器判断状态码,如果是200就继续解析,如果是400或500就会报错,如果 300 的话会进行重定向发送
另一个请求
6、浏览器开始显示HTML。当浏览器获得一个html文件时,会“自上而下”加载,并在加载过程中进行解析渲染。
7、浏览器发送请求获取嵌入在HTML中的资源
三次握手
起初,两端都为closed(关闭)状态。在通信开始前,双方都会创建TCB。服务器创建完TCB后便进入listen状态,
此时开始等待客户端发送数据
第一次握手:
客户端想服务端发送连接请求报文段。该报文段中包含自身的数据通讯初始序号。请求发送后,客户端
便进入STN-SENT(发送)状态
第二次握手:
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯
初始序号,发送完成后便进入syn-received(接收)状态
第三次握手:
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文。客户端发完这个报文段后便进入
established(已确定)状态,服务端收到这个应答后也进入established(已确定)状态,此时连接建立成功
四次挥手
TCP是全双工的,在断开连接时两端都需要发送fin和ack
第一次挥手:
若客户端认为数据发送完成,则它需要向服务端发送连接释放请求
第二次挥手:
服务端收到连接释放请求后,会告诉应用层要释放TCP链接。然后会发送ACK包,并进入close_wait(关闭-等待)
状态,此时表明客户端到服务端的连接已经释放,不再接收客户端的数据了。但是因为TCP连接是双向的,所以
服务端仍旧可以发送数据给客户端
第三次挥手:
服务端如果此时还没有发完的数据会继续发送,完毕后会向客户端发送连接释放请求,然后客户端便进入
last-ack(最后确认)状态
PS:通过延迟确认的技术(通常有时间限制,否则双方会误认需要重传),可以将第二次合第三次握手
合并,延迟ACK包的发送
第四次挥手
客户端收到释放请求后,向服务端发送确认应答,此时客户端进入time-wait(时间等待)状态。该状态会持
续2MSL(最大生存期,指报文段在网络中生存的时间,超时就会被抛弃)时间,若该时间段内没有服务端的
重发请求的话,就进入closed(关闭)状态。当服务端收到确认应答后,也进入closed(关闭)状态
为什么客户端进入time-wait状态,等待2MSL时间后才进入closed状态?
为了保证服务端收到客户端的确认应答。若客户端发完确认应答后直接进入closed状态,如果确认应答
因为网络问题一直没有达到,那么会造成服务端不能正常关闭
ARQ协议
是超时重传机制。通过确认和超时机制保证了数据的正确送达,ARQ协议包含停止等待ARQ和连续ARQ两种协议
UDP与TCP的区别
UDP和TCP是传输层的两个协议
首先UDP是不需要和TCP一样在发送数据前进行三次握手建立链接的,想发数据就可以开始发送了;
并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作
具体来说:
在发送端,应用层将数据传递给传输层的UDP协议,UDP只会给数据增加一个UDP头标识下是UDP协议,
然后就传递给网络层了
在接收端,网络层将数据传递给传输层,UDP只去除IP报文头就传递给应用层,不会任何拼接操作
因为是无连接,通信都不需要建立连接,这种情况非常不可靠。
并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了;
在网络不好的情况下可能会导致丢包。
优点的话在某些实时性要求高的场景(比如电话会议,直播)就需要使用UDP而不是TCP
UDP的头部开销小,只有八字节,相比TCP的至少二十字节要少得多,在传输数据报文时是很高效的