display:none和visibility:hidden都可以实现元素在视窗的不可见,
display:none不会保留元素的位置,结构发生了改变,所以触发了回流和重绘;
visibility:hidden会保留元素的位置,结构没有发生改变,所以只是触发了重绘。
new的过程主要完成了以下操作
完成以上步骤,我们可以自己模拟一个new
通过new创建的对象和通过字面量创建的对象本质上是一样的,字面量内部也是使用new来完成的。但是通过字面量的方式比较简单,也不用调用构造函数,性能较好,所以推荐使用字面量的方式。
首先,call,apply,bind都是用于改变this指向的
它们的区别主要有两点,call和apply是立即调用的,bind是返回一个新函数;
另一个区别就是传递参数的不同。call传递参数时,从第二个参数开始依次进行传递;apply传递参数时,第二个参数是一个数组,数组里面的每一项依次是向函数传递的参数;bind可以在使用时直接传递参数,也可以在 新函数调用时传递参数。
函数的返回结果是一个内部函数,并且被外部变量引用,如果内部函数引用了外部函数中定义的变量,就形成了闭包。闭包可以在内部函数访问到外部函数作用域,使用闭包可以将函数中的变量存储在内存之中,保护变量不会被污染,但是使用闭包有可能会导致内存泄漏,不能滥用。
闭包的应用场景:
TypeScript是一种面向对象的编程语言。它是JavaScript的超集。
typescript可以约束我们的编码习惯,还能起到注释的作用。比如当我们看到一函数后我们立马就能知道这个函数的用法,需要传什么值,返回值是什么类型一目了然,对大型项目的维护性有很大的提升。
post请求的发送:
当客户端需要请求一个服务端资源的时候,会率先检查浏览器中是否有缓存,这时的检查其实就是在判断是否有强缓存。
强缓存可以通过设置两种 HTTP Header 实现:Expires和 Cache-Control。
1. Expires
Expires是服务端返回的响应头,设置的是一个具体到年月日时分秒的时间,如果客户端此次发送请求的时间在Expires之前,则会直接触发缓存,不再去发起请求。
1. Cache-Control
Cache-Control同样是服务端返回的一个响应头,实际开发中常设置其中的max-age。设置的是相对时间,单位为秒。如果客户端此次发送请求的时间在max-age之内,则会直接触发缓存,不再去发起请求。
协商缓存
协商缓存就是客户端在没有匹配到强缓存的前提下,向服务端发起了请求,而服务端则会使用两种方式来判断。
1. Last Modified 与 If-Modified-Since
服务端在上一次响应客户端响应时,会返回一个Lase Modified的响应头,对应的值是一个该文件最后一次修改时间。
当客户端再一次请求该资源时,浏览器会自动为请求添加If-Modified-Since请求头,且该请求头携带上一次Last-Modified的值。
服务端接收到If-Modified-Since请求头后,会和服务端所储存的该资源最后修改时间作对比,如果没有任何变化,服务端会响应304,客户端就会直接从缓存获取数据。
1. Etag与If-None-Match
Etag是服务端根据请求资源的内容所生成的特殊标识,服务端下次发起对该资源的请求时,请求头会携带If-None-Match字段,该字段携带着上次服务端返回的Etag的值.
服务端接收到If-None-Match之后,会和该资源的标识进行对比,如果相同则认为资源未发生变化,响应304,客户端自动使用资源缓存。
对于 == 来说,如果对比双方的类型不一样,就会进行类型转换 ,===:用来检测两个操作数是否严格相等,不会进行类型转换
Typescript 是 JavaScript 的超集,可以被编译成 JavaScript 代码。
用 JavaScript 编写的合法代码,在 TypeScript 中依然有效。
Typescript 是纯面向对象的编程语言,包含类和接口的概念。
程序员可以用它来编写面向对象的服务端或客户端程序,并将它们编译成 JavaScript 代码。
TypeScript 引入了很多面向对象程序设计的特征,包括:
主要不同点如下:
答案:
返回结果是false。
分析:
首先,相等运算符在比较不同的数据类型之前会强制转换。
在转换不同的数据类型时,相等运算符遵循下列基本规则:
那么,‘true’==true,根据规则1,就转换为’true’==1,再根据规则2,将字符串’true’转换为数值,转换为数值会调用Number()函数,Number()函数转换规则如下:
如果是Boolean值,true和false将分别被转换为1和0;
如果是数字值,只是简单的传入和返回;
如果是null值,返回0;
如果是undefined,返回NaN;
如果是字符串,遵循下列规则:
(1)如果字符串只包含数字(包括前面带加号或负号的情况),则将其转换为十进制数值,即'1'会变成1,'111'会变成111,'01234'会变成1234,这里的前面的0会被省略;
(2)如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样,如果前面有0,如02.1,也会忽略前面的0);
(3)如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整数值;
(4)如果字符串是空的(不包含任何字符),则将其转换为0;
(5)如果字符串中包含除上述格式之外的字符,则将其转换为NaN。
那么,按照规则5(5),'true’会被转换为NaN,最后就变为对NaN==1进行判断求值,又有NaN与任何值都不相等,包括NaN本身,所以最终的结果为false。
整个判断流程为:‘true’ == true --> ‘true’ == 1 --> NaN == 1 --> false。
Promise为什么可以实现链式调用?
promise 的 then/catch 方法执行后会也返回一个 promise。
链式调用的执行顺序?
关于执行顺序,这里有两个结论:
1、当执行 then 方法时,如果前面的 promise 已经是 resolved 状态,则直接将回调放入微任务队列中;
2、当一个 promise 被 resolve 时,会遍历之前通过 then 给这个 promise 注册的所有回调,将它们依次放入微任务队列中。
关于结论1:
执行then方法是同步的,而then中的回调是异步的,同步代码执行时,会先将then中的回调先放入微任务队列,等同步任务执行完毕后,再依次取出执行,同时,在同步执行then方法时,会进行判断:
1、如果前面的 promise 已经是 resolved 状态,则会立即将回调推入微任务队列(但是执行回调还是要等到所有同步任务都结束后);
2、如果前面的 promise 是 pending 状态则会将回调存储在 promise 的内部(promse内部的一个数组中),一直等到 promise 被 resolve 才将回调推入微任务队列。
关于结论2:
对于会遍历之前通过 then 给这个 promise 注册的所有回调这句话的理解,来考虑一种情景,假设实例化一个promise,该promise被延迟resolve(比如将resolve的调用放入setTimeout函数中,设置延迟时间为3秒),但因为then方法是同步的,那么,在这个promise被resolve之前,可能已经通过then方法注册了几个回调函数,那么这几个回调函数不会被执行,也不会被放入到微任务队列中,它们会被这个promise内部储存起来,等到这个promise被resolve后,才会对之前储存的这几个回调函数进行遍历依次推入微任务队列(这里先存入的回调函数就先推入微任务队列),此时如果没有同步任务就会逐个取出再执行。
这里需要注意的点:
1、对于普通的 promise 来说,当执行完 resolve 函数时,promise 状态就为 resolved;
2、对于 then 方法返回的 promise 它是没有 resolve 函数的,取而代之只要 then 中回调函数代码执行完毕,这个 then 返回的 promise 就算被 resolve。
(原文参考链接:https://mp.weixin.qq.com/s/VfP9_8kUx6hyrII7LVae6g)
介绍:
装饰器(Decorator)是一种与类(class)相关的语法,用来注释或修改类和类方法。装饰器是一种函数,写成@ + 函数名,它可以放在类和类方法的定义前面。装饰器函数的参数就是被修饰的类和类方法本身。如果觉得一个参数不够用,可以在装饰器外面在封装一层函数,该函数再返回一个函数,用来接收类和类方法。
在react中,装饰器可以用来装饰函数组件吗?
答案:
不能。
分析:
装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码。也就是说,装饰器本质就是编译时执行的函数。
react函数组件本身是个函数,函数是存在函数提升的。在代码编译阶段,函数被定义,装饰器开始执行,但由于函数提升,函数体还没有任何内容,所以装饰器也就起不到他应有的装饰作用(也就是增强或者扩展函数功能)。(感觉这段之前的描述不太准确,故作修改。— 20.09.02改)
首先前端后端正式进入联调的时候我们需要使用后端给我们提供的真实接口地址进行测试,所以这个时候在我们的项目中将之前的假的接口地址给替换成真实的接口, 所以在一开始的时候我们需要把接口的配置放在一个配置文件之中,这样方便我们好调试,你也可以使用本地配置host的方式来达到真实环境下的不同域名请求的接口的调试,在这个过程中可能出现后端的接口不能满足前端之前编写的代码的数据格式,这个时候你可以根据具体情况前端进行处理或者让后端帮你在改一下接口的数据格式,也难免不了数据缺少这样的情况,也有可能是产生真实情况下域名产生跨域问题,这个时候你需要使用具体的方案去解决这个问题,比如jsonp跨域,服务器代理,后端cros处理。联调成功之后呢我们需要对代码提审然后进行上线了。
将代码交给你自的组长或者leader由他们进行上线,一般上线需要运维工程师的参与。但是上线可能会出现一系列的问题,比如测试环境中代码正常运行,一旦上线之后用户使用时,出现了bug,我们如何处理,这个时候我们需要代码回滚,但这个时候代码回滚又会出现前后端接口不一致的问题,怎么去解决。两个思路如果bug轻微我们可以暂时已提示的方式告诉用户请重试这样的话,然后我们需要对代码重新进行review和排除bug。如果bug问题较为严重,我们需要对该模块的直接暂停功能,代码进行回滚,重新审查一遍,修复bug。后端公司内部人员使用的项目可以不需要考虑这么多,等待bug修复完成之后然后把补丁打上去就行了。一般在公司会有专门的团队出一套关于bug紧急修复的方案,为了应对上线的项目出现bug的问题。
TypeScript 是 JavaScript 的一个超集
https://my.oschina.net/u/3991187/blog/4415774
原因:js 的加载、解析和执行会阻塞页面的渲染过程,因此我们希望 js 脚本能够尽可能的延迟加载,提高页面的渲染速度。
我了解到的几种方式是:
1.箭头函数是匿名函数,不能作为构造函数,不能使用new
2.箭头函数不绑定arguments,取而代之用rest参数...解决
3.箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值
4.箭头函数不能改变this指向
5.箭头函数没有原型属性
6.箭头函数不能当做Generator函数,不能使用yield关键字
用正确的标签做正确的事情。
html语义化让页面的内容结构化,结构更清晰,便于对浏览器,搜索引擎解析;即使在没有css样式的情况下,也以一种文档格式显示,并且是容易阅读的;搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO;使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。
尽可能少的使用无语义的标签div和span在语义不明显时,既可以使用div或者时,尽量用p,因为p在默认情况下有上下间距,对兼容特殊终端有利。
不要使用纯样式的标签,如:b,font,u等,改用css设置。
表单域要用fieldset标签包起来,并用legend标签说明标签的用途。
每个input标签对应的文本框都需要使用label标签,并且通过为input设置id属性,在label标签中设置for=someID来说明文本和相对应的input关联起来
1. 减少 HTTP 请求数量
在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。
1. 控制资源文件加载优先级
浏览器在加载HTML内容时,是将HTML内容从上至下依次解析,解析到link或者script标签就会加载href或者src对应链接内容,为了第一时间展示页面给用户,就需要将CSS提前加载,不要受 JS 加载影响。一般情况下都是CSS在头部,JS在底部。
1. 利用浏览器缓存
浏览器缓存是将网络资源存储在本地,等待下次该资源,直请求该资源时,如果资源已经存在就不需要到服务器重新请求接在本地读取该资源。
1. 减少重排(Reflow)
基本原理:重排是DOM的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的visibility属性,这也是Reflow低效的原因。如果Reflow的过于频繁,CPU使用率就会急剧上升。
1. 减少 DOM 操作
它们之间的主要区别可以用这样一句话来概括:src用于替代这个元素,而href用于建立这个标签与外部资源之间的关系。
href (Hypertext Reference) 超文本引用href这个属性指定web资源的位置,从而定义当前元素(如锚点a)或当前文档(如链接)与目标锚点或目标资源之间的联系。
例如当我们写:
浏览器知道这是个样式表文件,html的解析和渲染不会暂停,css文件的加载是同时进行的,这不同于在style标签里面的内置样式,用@import添加的样式是在页面载入之后再加载,这可能会导致页面因重新渲染而闪烁。所以我们建议使用link而不是@import。
src (Source)源这个属性是将资源嵌入到当前文档中元素所在的位置。例如当我们写:
当浏览器解析到这句代码时,页面的加载和解析都会暂停直到浏览器拿到并执行完这个js文件。这就像是把js文件里的内容全部注入到这个script标签中,类似于img,img标签是一个空标签,它的内容就是由src这个属性定义,浏览器会暂停加载直到这个图片加载完成。这也是为什么要将js文件的加载放在body最后的原因(在前面)。
一、 概念的理解
webstorage本地存储
提供一种在cookie之外存储会话数据的路径
提供一种存储大量可以跨会话存在的数据的机制
HTML5的WebStorage提供了两种API:localStorage(本地存储)和sessionStorage(会话存储)
不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标 签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的
localStorage和sessionStorage的存储数据大小一般都是:5MB
localStorage和sessionStorage都保存在客户端,不与服务器进行交互通信
localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
localStorage:window.localStorage;;sessionStorage:window.sessionStorage;
localStoragese:常用于长期登录(+判断用户是否已登录),适合长期保存在本地的数据,而sessionStorage:敏感账号一次性登录
存储空间更大:cookie为4KB,而WebStorage是5MB
节省网络流量:WebStorage不会传送到服务器,存储在本地的数据可以直接获取,也不会像cookie一样美词请求都会传送到服务器,所以减少了客户端和服务器端的交互,节省了网络流量
对于那种只需要在用户浏览一组页面期间保存而关闭浏览器后就可以丢弃的数据,sessionStorage会非常方便
快速显示:有的数据存储在WebStorage上,再加上浏览器本身的缓存。获取数据时可以从本地获取会比从服务器端获取快得多,所以速度更快
安全性:WebStorage不会随着HTTP header发送到服务器端,所以安全性相对于cookie来说比较高一些,不会担心截获,但是仍然存在伪造问题
WebStorage提供了一些方法,数据操作比cookie方便
setItem (key, value) —— 保存数据,以键值对的方式储存信息。
getItem (key) —— 获取数据,将键值传入,即可获取到对应的value值。
removeItem (key) —— 删除单个数据,根据键值移除对应的信息。
clear () —— 删除所有的数据
key (index) —— 获取某个索引的key
cookie
名称:name(不区分大小写,但最好认为它是区分的)
值:value(通过URL编码:encodeURIComponent)
域
路径
失效时间:一般默认是浏览器关闭失效,可以自己设置失效时间
安全标志:设置安全标志后只有SSL连接的时候才发送到服务器
通过良好的编程,控制保存在cookie中的session对象的大小
通过加密和安全传输技术,减少cookie被破解的可能性
只有在cookie中存放不敏感的数据,即使被盗取也不会有很大的损失
控制cookie的生命期,使之不会永远有效。这样的话偷盗者很可能拿到的就 是一个过期的cookie
cookie的长度和数量的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉
安全性问题。如果cookie被人拦掉了,那个人就可以获取到所有session信息。加密的话也不起什么作用
有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务端保存一个计数器。若吧计数器保存在客户端,则起不到什么作用
sessionStorage
localStorage
图示说明:
注意:时刻注意XSS注入的风险,因为可以在控制台直接访问它们,所以不要存入敏感数据
二、区别的比较
本地储存localStorage与cookie的区别
sessionStorage和localStorage不会把数据发给服务器,仅在本地保存
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
sessionStorage:仅在当前浏览器窗口关闭前有效
localStorage 始终有效,长期保存
存储大小也不同,cookie数据不能超过4k,sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
sessionStorage不在不同的浏览器窗口中共享
localStorage在所有同源窗口中都是共享的
cookie也是在所有同源窗口中都是共享的
WebStorage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便
cookie、session和localStorage的区别
cookie和session的区别
web Storage和cookie的区别
sessionStorage、localStorage、cookie都是在浏览器端存储的数据,其中sessionStorage的概念很特别,引入了一个“浏览器窗口”的概念,sessionStorage是在同源的同窗口中,始终存在的数据,也就是说只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一个页面,数据仍然存在,关闭窗口后,sessionStorage就会被销毁,同时“独立”打开的不同窗口,即使是同一页面,sessionStorage对象也是不同的
减少网络流量:一旦数据保存在本地之后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要的来回传递
快速显示数据:性能好,从本地读数据比通过网络从服务器上获得数据快得多,本地数据可以及时获得,再加上网页本身也可以有缓存,因此整个页面和数据都在本地的话,可以立即显示
临时存储:很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用sessionStorage非常方便
浏览器本地存储与服务器端存储的区别
sessionStorage、localStorage和cookie的区别
sessionStorage与页面js数据对象的区别
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
一、 通过jsonp跨域
通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。
1.)原生实现:
一、回调函数(callback)
是啥:一个函数a被当做另一个函数b的参数,在b的函数体内去执行a
function b(callback){
callback();
}
function a(){}
b(a)
优点:能让a函数的逻辑在适当的位置才被执行
缺点:代码逻辑不清,不利于代码的阅读和维护,各个部分之间高度耦合
优化: 变成异步回调
function b(callback){
setTime(()=>{
callback();
},1000)
}
function a(){}
b(a)
二、事件监听
是啥: 当某个事件被触发时,才执行绑定在这个事件上的函数
document.on('click',fn)
优点:不同的事件能绑定不同的函数,利于后期代码模块化
缺点:同个事件只能绑定一个函数。并且整个代码都采用事件驱动,执行逻辑不是很清楚
优化: attachEvent和addEvenListener方法 (可以添加许多事件,添加的事件不会覆盖已存在的事件 )
document.addEvenListener("click",fn,false);
三、发布/订阅(观察者模式)
是啥:观察者模式类似一个外卖平台派单的过程,系统通过平台发布一个单子,外卖员一直刷着平台的消息并接收到一条单子,整个过程是一次消息的发布和订阅。
优点 :整个消息的发布和订阅都能比较清晰的被看到,代码逻辑易懂。
缺点 :发布者和订阅者如果各自对应多个时,并且各自有关联,容易造成循环调用。即使没有关联,也容易造成通知的耗时加长。
四、promise对象(模式)
是啥:JavaScript 中,所有代码都是单线程的,也就是同步执行的。而 Promise 就为异步编程提供了一种解决方案。
//一、Promise 对象是由关键字 new 及其构造函数来创建的。
const promise = new Promise((resolve, reject) => {
if (success) {
resolve(value); //成功的消息
} else {
reject(error); //失败的消息
}
});
//二、then方法处理成功和失败的回调
promise.then(function(value) {
// success
}, function(error) {
// failure
});
五、async await
是啥:async是“异步”的意思,async用于声明一个函数是异步的。await意思是“等待”,用来等待async 所声明的异步函数的执行结果,并且await只能在async函数中使用。
async function sync() {
const result= await new Promise(resolve => {
setTimeout(() => {
resolve("async await result");
}, 1000);
});
console.log(result);
}
sync()
1. const和let
let: 声明在代码块有用的变量
特点:
Set(数组去重)
特点:
Map(使用实例的set,get,delete方法增,查,删,也可以在new 时接受一个数组)
特点:
1. 状态不受外界影响(有三种状态:padding, fulfilled,redected)
2. 一旦状态改变就不会再变。
11. class
12. Module(一种将程序拆分成一个个小模块的支持,或者说是可以将一个个小模块加入到程序中去)
在ES6的module之前,比较流行的模块加载方案有:CommonJS和AMD,前者用于服务器(node),后者用于浏览器。
区别:
1. CommondJS和AMD是运行时加载的。
2. module是编译时加载的。
3. CommondJS输出的是值的复制,而ES6输出的是值的引用
ES6模板默认使用严格模式
- 变里必须声明后再使用
- 函数的参数不能有同名属性
- 不能使用width
- 禁止this指向全局对象
13. Generator与async、await
Generator是ES6提供的一种异步编程解决方案。使异步写法更像同步
Async await是ES2017的标准,是generator的一个语法糖。
服务端渲染:在早期的时候,由于页面比较简单,前后端分离还没有做的比较完善,所以当时一般页面渲染还是在服务端完成html文件的拼装,然后浏览器接收到这个文件,就可以直接解析展示。
如今前端页面的复杂性提高,前端已经不再仅仅是普通的页面展示了,现在前端页面功能更加完善,也更加复杂。同时伴随着ajax的兴起,使得现在越来越崇尚前后端分离的开发方式。后端不再提供完整的html页面,而是提供一些API使得前端可以获取需要的json数据,然后前端拿到数据后在前端完成html页面的拼装,然后展示在浏览器上,这就是客户端渲染。
优点
缺点
1.不利于前后端分离,开发效率低。使用服务器端渲染,则无法进行分工合作,则对于前端复杂度高的项目,不利于项目高效开发。另外,如果是服务器端渲染,则前端一般就是写一个静态html文件,然后后端再修改为模板,这样是非常低效的,并且还常常需要前后端共同完成修改的动作; 或者是前端直接完成html模板,然后交由后端。另外,如果后端改了模板,前端还需要根据改动的模板再调节css,这样使得前后端联调的时间增加。
2.占用服务器端资源。即服务器端完成html模板的解析,如果请求较多,会对服务器造成一定的访问压力。而如果使用前端渲染,就是把这些解析的压力分摊了前端,而这里确实完全交给了一个服务器
Es6 module和commonjs的区别
前者建立模块依赖关系是在运行时,后者是在编译时
在模块导入方面,CommonJS导入的是值拷贝,ES6 Module导入的是只读的变量映射
ES6 Module通过其静态特性可以进行编译过程中的优化,并且具备处理循环依赖的能力
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。
- 闭包的用途
function myInstanceof(left, right) {
let prototype = right.prototype
left = left.__proto__
while (true) {
if (left === null || left === undefined)
return false
if (prototype === left)
return true
left = left.__proto__
}
}
思路
1. 触发条件
1. 三次握手
三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP窗口大小信息
浅拷贝
当一个对象拷贝另一个对象的数据的时候,只要一个对象的数据发生改变另一个对象的数据也会发生改变
因为浅拷贝拷贝的是引用的地址,(所以必须在对象是多层才能拷贝,单层拷贝的是数值,多层说明里面套着对象,所以拷贝的是地址。)
实现方式:
1. Object.assign() 作用:将第二个参数及以后的参数合并到第一个对象里。
```javascript
var obj = {a:{name:"kaiqin",age:19}};
var obj1 = Object.assign({},obj);
obj1.a.name="wang"
console.log(obj1) // { a: { name: 'wang', age: 19 } }
console.log(obj) // { a: { name: 'wang', age: 19 } }
布尔值 如果填true的情况下是深拷贝 什么也不写就是浅拷贝
目标对象
…后面所有的对象 都是需要合并的对象
var obj = {a:{name:“kaiqin”,age:19}};
var obj1 = {b:{name:“wang”,age:19}};
var obj2 = $.extend({},obj,obj1)
obj2.a.name=“zhang”;
console.log(obj2) // a: {name: “zhang”, age: 19} b: {name: “wang”, age: 19}
console.log(obj) // a: {name: “zhang”, age: 19}
深拷贝
当一个对象拷贝另一个对象的数据的时候,其中一个对象的数据发生变化不会影响另一个对象的数据
因为深考贝拷贝的是对象的数据而不是地址
实现方式
对象是单层的情况下 Object.assign()
var obj = {a:1,b:2,c:3}
var obj1 = Object.assign({},obj);
obj1.a = 30;
console.log(obj1,obj)
$.extend()
var obj = {a:{name:“kaiqin”,age:19}};
var obj1 = {b:{name:“wang”,age:19}};
var obj2 = $.extend(true,{},obj,obj1);
obj2.a.name=“zhang”;
console.log(obj2)
console.log(obj)
JSON.parse、JSON.stringfiy 不能拷贝函数,但用在拷贝数据库数据时,不影响。因为数据库没有函数。所以推荐使用
其原理是:先将对象转换为字符串、再转换成对象,此时地址一定发生了变化,所以可以实现浅拷贝。
var obj1 = {b:{name:“wang”,age:19}};
var obj2 = JSON.parse(JSON.stringify(obj1)); //此时地址发生了改变。
obj2.b.name = “kaiqin”;
console.log(obj1,obj2)
递归
什么是promise与async、await
promise,简单来说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作的结果),是一个异步解决的方案。
基本语法:
let p = new Promise((resolve,reject) => {
//...
resolve('success')
});
p.then(result => {
console.log(result);//success
});
三个状态:pending(执行中)、success(成功)、rejected(失败)
错误捕获:Promise.prototype.catch用于指定Promise状态变为rejected时的回调函数,可以认为是.then的简写形势,返回值跟.then一样
let p = new Promise((resolve,reject) => {
reject('error');
});
p.catch(result => {
console.log(result);
})
编写一个简单的promise
const fn = function (resolve, reject) {
console.log("Promise execution!");
let date = new Date();
let time = date.getTime();
console.log(time);
if (time % 2 == 0) {
resolve("She loves me!");
} else {
reject("She doesn't love me!");
}
};
const defer = new Promise(fn);
defer.then(
function (value) {
console.log("resolve: " + value);
},
function (reason) {
console.log("reject: " + reason);
}
);
async、await
简洁:异步编程的最高境界就是不关心它是否是异步。async、await很好的解决了这一点,将异步强行转换为同步处理。async/await与promise不存在谁代替谁的说法,因为async/await是寄生于Promise,Generater的语法糖。
用法
async用于申明一个function是异步的,而await可以认为是async wait的简写,等待一个异步方法执行完成。
规则:
写法
async function demo() {
let result01 = await sleep(100);
//上一个await执行之后才会执行下一句
let result02 = await sleep(result01 + 100);
let result03 = await sleep(result02 + 100);
// console.log(result03);
return result03;
}
demo().then(result => {
console.log(result);
});
错误捕获
如果是reject状态,可以用try-catch捕捉
let p = new Promise((resolve,reject) => {
setTimeout(() => {
reject('error');
},1000);
});
async function demo(params) {
try {
let result = await p;
}catch(e) {
console.log(e);
}
}
demo();
区别
1 promise是ES6,async/await是ES7
2 async/await相对于promise来讲,写法更加优雅
3 reject状态:
1)promise错误可以通过catch来捕捉,建议尾部捕获错误,
2)async/await既可以用.then又可以用try-catch捕捉
一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回
37.node的优缺点以及适用场景
优点:
因为 Node 是基于事件驱动和无阻塞I/O的,所以非常适合处理并发请求,因此构建在Node 上的代理服务器相比其他技术实现(如Ruby)的服务器表现要好得多
与 Node 代理服务器交互的客户端代码是由 javascript语言编写的,因此客户端和服务器端技术统一
缺点:
##38.webpack 是怎么处理 vue 格式的文件的?
关于HTTP的缓存机制来说,这些缓存策略都会体现在HTTP的头部信息的字段上,这些策略会根据是否需要重新向服务器发起请求可以分为强缓存和协商缓存两大类。
实现的方法:
arr.flat(Infinity) 底层原理:通过foreach遍历和递归的方式进行一层一层的遍历
arr.toString.split(“,”)
reduce和递归来实现
foreach遍历和递归
回流和重绘
HTML5 能够本地存储数据,在之前都是使用 cookies 。HTML5 提供了两种本地存储方案: localStorage 用于持久化的本地存储,数据永远不会过期,关闭浏览器也不会丢失。 sessionStorage 同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储
使用箭头函数应注意什么?
用了箭头函数,this就不是指向window,而是父级(指向是可变的)
不能够使用arguments对象
不能用作构造函数,所以不能使用new命令,否则会报错
不可以使用yield命令,因此箭头函数不能用作 Generator 函数
请介绍一下Node事件循环的流程
在进程启动时,Node便会创建一个类似于while(true)的循环,每执行一次循环体的过程我们称为Tick。每个Tick的过程就是查看是否有事件待处理。如果有就取出事件及其相关的回调函数。然后进入下一个循环,如果不再有事件处理,就退出进程。
map和forEach都是对数组的遍历,但是他们是有区别的,forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。
例如,在react经常需要使用数据进行渲染元素的时候,那么这时候,我们就需要使用map了,返回一个新的元素的数组进行渲染。而forEach就是不需要返回新的数据,需要在原数组的每一项上修改的时候,我们经常会用到。
提供网页加载速度的方式?(优化)
减少http的请求
使用服务端渲染
懒加载图片
添加Expires请求头,缓存http访问的组件,下次访问的时候减少不必要的http请求,提高加载速度。
使用CDN,减小服务器负担
启用GZIP压缩,压缩必要资源,从而给用户发送最小的HTML文件和CSS/JS等资源
localstorage sessionstorage和cookie的区别
基本概念
区别
存储大小
cookie:一般不超过4K(因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识)
sessionStorage:5M或者更大
localStorage:5M或者更大
数据有效期
cookie:一般由服务器生成,可以设置失效时间;若没有设置时间,关闭浏览器cookie失效,若设置了时间,cookie就会存放在硬盘里,过期才失效
sessionStorage:仅在当前浏览器窗口关闭之前有效,关闭页面或者浏览器会被清除
localStorage:永久有效,窗口或者浏览器关闭也会一直保存,除非手动永久清除,因此用作持久数据
作用域
cookie:在所有同源窗口中都是共享的
sessionStorage:在同一个浏览器窗口是共享的(不同浏览器、同一个页面也是不共享的)
localStorage:在所有同源窗口中都是共享的
通信
cookie:十种携带在同源的http请求中,即使不需要,故cookie在浏览器和服务器之间来回传递;如果使用cookie保存过多数据会造成性能问题
sessionStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信;不会自动把数据发送给服务器,仅在本地保存
localStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信;不会自动把数据发送给服务器,仅在本地保存
易用性
cookie:需要自己进行封装,原生的cookie接口不够友好
sessionStorage:原生接口可以接受,可以封装来对Object和Array有更好的支持
localStorage:原生接口可以接受,可以封装来对Object和Array有更好的支持
应用场景
cookie:判断用户是否登录过网站,以便实现下次自动登录或记住密码;保存事件信息等
sessionStorage:敏感账号一次性登录;单页面用的较多(sessionStorage 可以保证打开页面时 sessionStorage 的数据为空)
localStorage:常用于长期登录(判断用户是否已登录),适合长期保存在本地的数据
什么是内存泄漏
内存泄露是指:内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
React中解决方式
componentWillUnmount(){
this.setState = (state,callback)=>{
return;
};
}
作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
全局作用域、函数作用域、块状作用域、动态作用域。
对象 类型
global/window 全局作用域
function 函数作用域(局部作用域)
{} 块状作用域
this 动态作用域
变量在函数或者代码块{ }外定义,即为全局作用域。不过,在函数或者代码块{ }内未定义的变量也是拥有全局作用域的(不推荐)。
var carName = "Volvo";
//此处可以调用carName变量
function myFunction(){
//函数内可调用carName变量
}
上述代码中变量carName就是在函数外定义的,它是拥有全局作用域的。这个变量可以在任意地方被读取或者修改,当然如果变量在函数内没有声明(没有使用 var 关键字),该变量依然为全局变量。
//此处可以调用carName变量
function myFunction(){
carName = "Volvo";
//函数内可调用carName变量
}
以上实例中 carName 在函数内,但是拥有全局作用域,它将作为 global 或者 window 的属性存在。
在函数内部或代码块中没有定义的变量实际上是作为 window/global 的属性存在,而不是全局变量。换句话说没有使用 var 定义的变量虽然拥有全局作用域,但是它是可以被 delete 的,而全局变量不可以。
在函数内部定义的变量,就是局部作用域。函数作用域内,对外是封闭的,从外层的作用域无法直接访问函数内部的作用域!
function bar(){
var testValue = 'inner';
}
console.log(testValue) //报错:ReferenceError:testValue is not defined
如果想读取函数内的变量,必须借助 return 或者闭包。
function bar(value){
var testValue = 'inner';
return testValue+value;
}
console.log(bar('fun')) //"innerfun"
这是借助return的方式,下面是闭包的方式:
function bar(value){
var testValue = 'inner';
var result = testValue+value;
function innser(){
return result
};
return innser();
}
console.log(bar('fun')) //"innerfun"
通俗的讲,return 是函数对外交流的出口,而 return 可以返回的是函数,根据作用域的规则,函数内部的子函数是可以获取函数作用域内的变量的。
说到这其实大家会想到嵌套函数的作用域问题,如果 inner 函数再嵌套函数呢?这就涉及到另一个概念:作用域链。
仔细观察上图,其实不难理解作用域链是什么,因为你可以按照原型链那样去理解。任何一个作用域链都是一个堆栈,首先先把全局作用域压入栈底,再按照函数的嵌套关系一次压入堆栈。在执行的时候就按照这个作用域链寻找变量。
在其他编程语言中,块状作用域是很熟悉的概念,但是在JavaScript中不被支持,就像上述知识一样,除了全局作用域就是函数作用域,一直没有自己的块状作用域。在 ES6 中已经改变了这个现象,块状作用域得到普及。关于什么是块,只要认识
if(true){
let a = 1
console.log(a)
}
在这个代码中,if 后 { } 就是“块”,这个里面的变量就是拥有这个块状作用域,按照规则,{ }之外是无法访问这个变量的。ES6中的let。
在 JavaScript 中很多同学对 this 的指向时而清楚时而模糊,其实结合作用域会对 this 有一个清晰的理解。不妨先来看下这段代码:
window.a = 3
function test () {
console.log(this.a)
}
test.bind({ a : 2 })() //2
test() //3
在这里bind已经把作用域的范围进行了修改指向了{ a:2},而 this 指向的是当前作用域对象,是不是可以清楚的理解了呢?
接下来我们再思考另一个问题:作用域是在代码编写的时候就已经决定了呢,还是在代码执行的过程中才决定的?
var carName = "Volvo";
//此处可调用 carName 变量
function myFunction(){
//函数内可调用 carName 变量
}
在看看这段代码,写代码的时候就知道 carName 就是全局作用域,函数内部的用 var 定义的变量就是函数作用域。这个也就是专业术语:词法作用域。
通俗的讲变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。
相反,只能在执行阶段才能决定变量的作用域,那就是动态作用域。
看看下面的代码是遵循了动态作用域还是静态作用域呢?
function foo(){
console.log(a) //2 (不是3!)
}
function bar(){
var a=3;
foo();
}
var a=2;
bar()
为什么会这样?
如果按照动态作用域分析:当 foo() 不能为 a 解析出一个变量引用时,它不会沿着嵌套的作用域链向上走一层,而是沿着调用栈向上走,以找到 foo() 是 从何处 被调用的。因为 foo() 是从 bar() 中被调用的,它就会在 bar() 的作用域中检查变量,并且在这里找到持有值 3 的 a。
如果按照静态作用域分析:foo执行的时候没有找到 a 这个变量,它会按照代码书写的顺序往上找,也就是 foo 定义的外层,就找到了 var a=2 ,而不是 foo 调用的 bar 内找。
所以结果就是 2。
从这个示例可以看出 JavaScript 默认采用词法(静态)作用域,如果要开启动态作用域请借助 bind、with、eval 等。