前端经典面试题汇总 sort(面试题)执行的机制(两数比较,小的排在大的前边)a – b < 0 ,那么 a会排列在b之前a – b = 0,a 和 b 的位置不变 备注:ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都遵守a – b > 0,a 会 排列在 b 之后 sort(computerFunccion) 中的 computerFunction(a,b) 参数的值 及其混乱!!!(在不同的服务器上有不同的结果 :chrome、火狐、IE)快速掌握return a – b 升序return b – a 降序 三栏布局(面试题) 实现三栏布局的几种方法 (两边宽度固定 中间宽度自适应 ) vue 和 react 的区别(面试题) 数据是不是可变的react 整体是函数式的思想,把组件设计成纯组件,状态和逻辑通过参数传入,所以在react中,是单向数据流,推崇结合 immutable 来实现数据不可变vue 的思想式响应式的,也就是基于是数据可变的,通过对每一个属性建立 Watcher 来监听,当属性变化的时候,响应式的更新对应的虚拟domreact 的优化需要手动优化 vue 是自动的,当vue的state特别多的时候,Watcher 也会很多,会导致卡顿,所以大型状态特别多的应用一般用 react,更加可控vue 是把 html css js 组合到一起,用各自的处理方式,vue 有单文件组件,可以把 html css js 写到一个文件中,html 提供了模板引擎来处理 说一下http和https(面试题) http和https的基本概念 http:超文本传输协议 ,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器段请求和应答的标准(TCP),用于从 WWW 服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少https:是以安全为目的的 HTTP 通道,简单讲是 HTTP 的安全版,即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSLhttps 协议的主要作用是:建立一个信息安全通道,来确保数据的传输,确保网站的真实性 http 和 https 的区别 http 传输的数据都是未加密的,也就是明文的,网景公司设置了 SSL 协议来对 http 协议传输的数据进行加密处理,简单来说 https 协议是由 http 和 SSL 协议构建的可进行加密传输和身份认证的网络协议,比http协议的安全性更高https 协议需要 ca 证书, 费用较高http 是超文本传输协议,信息是明文传输,https 则是具有安全性的 ssl 加密传输协议使用不同的连接方式,端口也不同,一般而言, http 协议的端口为 80 ,https 的端口为 443http 的连接很简单,是无状态的,https 协议是由 ssl + http 协议构建的可进行加密传输、身份认证的网络协议,比http协议安全 (3)https 的工作原理 客户端在使用 HTTPS 方式于 Web 服务器通信时有以下几个步骤 客户端使用 https url 访问服务器,则要求 web 服务器建立 ssl 连接web 服务器接收到客户端的请求之后,会将网站的证书(证书中包含了公钥),返回给客户端客户端和 web 服务器端开始协商 SSL 链接的安全等级,也就是加密等级客户端浏览器通过双方协商一致的安全等级,建立共话密钥,然后通过网站的公钥来加密会话密钥,并传送给网站web 服务器通过自己的私钥解密出会话密钥web 服务器通过会话密钥加密与客户端之间的通信 (4)https 的优点 使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器HTTPS 协议是由 SSL + HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 http 协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性HTTPS 是现行框架下最安全的解决方案,虽然不是绝对安全,但他大幅增加了中间人攻击的成本谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用 HTTPS 加密的网站在搜索结果中的排名会更高” (5)https的缺点 https 握手阶段比较费时,会是页面加载时间延长50%,增加 10% ~ 20% 的耗电。https 缓存不如 http 高效,会增加数据开销SSL 证书也需要钱,功能越强大的证书费用越高SSL 证书需要绑定 IP , 布恩你那个在同一个 ip 上绑定多个域名,ipv4 资源支持不了这种消耗 三次握手,一句话概括(面试题) 客户端和服务器都叫直到给自的手法,因此需要三次握手简化三次握手
从图片中可以得到三次握手可以简化为:c发起请求连接 s 确认,也发起连接 c 确认 我看再看看每次我收的作用:第一次握手:s 只确认自己可以接受c发送的报文段第二次握手:c 可以确认 s 收到了自己发送的报文段,并且可以确认 自己可以接受 s 发送的报文段第三次握手: s 可以确认 c 收到了自己发送的报文段 TCP和UDP的区别(面试题) tcp 是面向连接的,udp 是无连接的 即发送数据前不需要建立连接tcp 提供可靠的服务,也就是说,通过 tcp 连接传送的数据,无差错、不丢失、不重复,且按序到达;udp尽最大努力交付,即不保证可靠交付。并且因为 tcp 可靠 面向连接,不会丢失数据因此适合大数量的交换tcp 是面向字节流,udp面向报文,并且网络出现拥塞不会使得发送速率低(因此会出现丢包,对实现的应用比如 IP电话和视频会议等tcp只能是一对一的,udp支持一对一,一对多tcp得首部较大为20字节,而udp只有8字节tcp是面向连接的可靠性传输,而udp是不可靠的 http请求的方式,head方式(面试题) head:类似于get 请求 , 只不过返回的响应中没有具体得内容,用户报头 options:允许客户端查看服务器的性能,比如说服务器支持的请求方式等等 一个图片 url 访问后直接下载怎样实现(面试题) 请求的返回头里面,用于浏览器解析的重要的参数就是 oss 的 api 文档里面的返回 http 头,决定用户下载行为的参数 css选择器优先级顺序(面试题) ! important // 在属性后面加上这条样式,会覆盖掉页面上任何定义的素样式行内样式,在style属性里系的样式id选择器class选择器标签选择器通配符选择器*浏览器自定义的属性和继承 css position(面试题) absolute: 生成绝对定位的素,相对于 static 定位以外的第一个父素进行定位,素的位置通过“left”、“right”、“top”、“bottom”属性进行规定fixed:生成绝对定位素,相对于浏览器窗口进行定位,素的位置通过“left”、“right”、“top”、“bottom”属性进行规定relative:生成相对定位素,相对于其正常位置进行定位,left: 20; 会向素的 LEFT 的位置添加 20 像素static:默认值 ,没有定位,素出现在正常的流中,(忽略 “left”、“right”、“top”、“bottom” 或者 z-index 声明)inherit:规定 应该从父级素继承 position 属性的值 vue组件修饰符(面试题) 全局组件和局部组件全局组件(定义在 vue 对象外面,在挂在了 vue 对象上的 html 标签中,都可以使用一定要先定义组件 在进行 vue 的挂载模板中必须有一个跟标签,否则没有效果取名问腿:如果使用 驼峰命名法:myTag局部组件(定义在vue 对象中,只能在挂载的html标签中使用全局组件和局部组件的区别全局组件:可以作用于全局的挂在对象局部组件:只能作用于挂载的当前对象 vue时间修饰符(面试题) vue提倡的是在方法中只有对数据的处理,所以提供了时间修饰符用于DOM的事件处理,常用的时间修饰符有以下几个.stop:组织冒泡(通俗讲就是阻止事件向上级DOM素传递).prevent:阻止默认事件的发生默认事件指对dom的操作会因此自动执行的动作,比如超链接的时候会进行页面的跳转,表单按钮会重新加载页面等 使用 ”prevent“ 修饰符可以阻止这些事件的发生.capture:捕获冒泡,即有冒泡发生时,有该修饰符的 dom 素会先执行,如果有多个,从外到内依次执行,然后再按自然顺序执行出发的事件.self:将事件绑定到自身,只有自身才能出发,通常用于避免冒泡事件的影响.once:设置之间只能触发一次,比如按钮的等.passive:该修饰符大概意思用于对DOM的默认事件进行性能优化 从浏览器输入url到显示页面发生了什么(面试题) 在浏览器输入url用户输入url 例如 http://baidu.com 其中 http为协议 之后为网址,及指出需要的资源在哪台计算机上,此处为域名,为了方便记忆,但是为了让计算机理解这个地址还需解析为 IP 地址应用层DNS解析域名客户端先检查本地是否有对应的ip地址,若找到则返回相应的 IP 地址,若没找到则请求上级 DNS 服务器,直至找到或到根节点应用层客户端发送http请求http 请求包括请求报头和请求主体两个部分,包头包含重要信息传输层 tcp 传送报文 三次握手网络层 IP 协议查询 MAC 地址ip协议的作用是把tcp分割好的数据包传送给接收方数据到达数据库在找到对方的 mac 地址后 , 就将数据发送到数据链路层,这时客户端发送请求的阶段结束服务器接收数据接收端的服务器在链路层收到数据包 ,再层层向上直到应用层,这过程中包括在运输层通过 tcp 协议将分段的数据包重新组成原来的 http 请求报文服务器响应请求服务器收到 http 请求后 查找客户端请求的资源,并返回响应报文服务器返回相应的文件请求成功后 服务器会返回相应的 html 文件页面渲染jiexiHTML构建DOM树 =》 构建渲染树 =》 布局渲染树 =》 绘制渲染树 数据类型(面试题) Javascript 中什么是基本数据类型 ,什么是引用数据类型?以及各个数据类型是如何存储的?基本数据类型有NumberStringBooleanUndefinedSymbol(es6新增数据类型)bigInt引用数据类型统称为 Object 类型,细分的话有ObjectArraryDateFunctionRegExp 基本数据类型的数据直接存储在栈中;而引用数据类型的数据存储在堆中,在栈中保存数据的引用地址,这个引用地址指向的是对应的数据,以便快速查找到堆内存中的对象栈内存是自动分配的,而堆内存是动态分配的,不会自动释放,所以每次使用完对象的时候都要把它设置为 null, 从而减少无用内存的消耗 类型转换(面试题) 在 JS 中,浮点数时使用 64 位固定长度来表示的,其中的1位表示符号位,11位用来表示指数为,剩下的52位尾数,由于只有52位 表示符号尾数位 而0.1转为二进制是一个无限循环树 0.00011001100…. (1100循环) 十进制转二进制方法 由于只能存储52位尾数位,所以会出现精度缺失,把它存到内存中再取出来转化成十进制就不是原来的0.1了,就变成了 0.100000000000000005551115123126, 0.1+0.2 转成二进制刚好是0.30000000000000004 所以 0.1 + 0.2 > 0.3 那为什么0.2+0.3=0.5呢?(面试题) 0.2和0.3都转化为2进制后再进行计算,位数大于52位,而实际取值只取52位,就变成了0.10000…..https://zhuanlan.zhihu.com// 0.5 在内存中,0.1和0.2的尾数都是等于52位的,而他们相加必定大于52位,他们相加恰好前52位都是0 , 0.1000000……也就是0.5 那既然0.1不是0.1了 为什么在console.log(0.1)的时候还是0.1呢?(面试题) 在console.log的时候会二进制转换为十进制,十进制再转为字符串形式,在转换的过程中发生了就近取值,所以打印出来的是一个近似值的字符串 判断数据类型有几种方法 typeof缺点:typeof null 的值为Object,无法分辨是 null 还是 Objecttypeof undefined // undefinedtypeof “10” // Stringtypeof 10 // Numbertypeof false // Booleantypeof Symbol() // Symboltypeof Function // functiontypeof null // Objecttypeof [] // Objecttypeof {} // Objectinstanceof缺点:只能判断对象是否存在于目标对象的原型链上function Foo(){}var fi = new Foo()var d = new Number(1)console.log(fi instanceof Foo) // trueconsole.log(d instanceof Nmber)// trueconsole.log(123 instanceof Number) // false 不能判断字面量的基本数据类型constructorvar d = new Number(1)var e = 1function fn(){ console.log(“ming”)}var date = new Date()var arr = [1,2,3]var reg = /[hbc]at/giconsole.log(e.constructor)// Number(){[native code]}console.log(e.constructor.name) // Numberconsole.log(fn.constructor.name) // Functionconsole.log(date.constructor.name) // Dateconsole.log(arr.constructor.name) // Arrayconsole.log(reg.constructor.name) // RegexpObject.prototype.toString.call()一种最好的基本类型检测方式 Object.prototype.toString.call();它可区分null、string、boolean、number、undefined、arrary、function、object、date、math数据类型缺点:不能细分为谁谁的实例console.log(Object.prototype.toString.call(undefined)) // [object Undefined]console.log(Object.prototype.toString.call(null)) // [object Null]console.log(Object.protoyype.toString.call(123)) // [object Number]console.log(Object.prototype.toString.call(“abc”)) // [object String]console.log(Object.prototype.toString.call(true)) // [object Boolean]funcrion fn(){ console.log(“ming”)}var date = new Date()var arr = [1,2,3]var reg = /[hbc]at/giconsole.log(Object.prototype.toString.call(fn)) // [object Function]console.log(Object.prototype.toString.call(date)) // [object Date]console.log(Object.prototype.toString.call(arr)) // [object Arrary]console.log(Object.prototype.toString.call(reg)) // onject Regexp] 为什么 typeof null 是 Object 因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话。系统就判断为是 object 类型,而null的二进制全是0 , 自然也就判断为 Object 这个bug是初版本的 javascript 中留下来的,扩展一下其他五种标识位:000 对象1 整形010 双精度类型100 字符串110 布尔类型 == 和 === 有什么区别 ===是严格意义上的相等。会比较两边的数据类型和值大小数据类型不同返回fasle数据类型相同,但值大小不同,返回 falsse== 是非严格意义上的想的两边类型相同,比较大小两边类型不同,根据下方表格 再进一步进行比较Null == Undefined => trueString == Number => 将 String 转为 Number , 再比较大小Boolean == Number => 先将 Boolean 转为 Number,再比较Object == String, Number,Sombol => Object => 转为原始类型 手写 call、apply、bind call和 apply 实现思路主要是:判断是否是函数调用,若非函数调用抛异常通过新对象(context)来调用函数给 context 创建一个 fn 设置为需要调用的函数结束掉用完之后删除 fn 字面量创建对象和 new 创建对象有什么区别,new 内部都实现了什么,手写一个 new 字面量:字面量创建对象更简单,方便阅读不需要作用域解析,速度更快new 内部:创建一个新对象使新对象的 _ proto _ 指向原函数的 prototype改变 this 指向(指向新的 obj)并执行该函数,执行结果保存起来作为 result判断执行函数的结果是不是 null 或 Undefind,如果是 则返回之前的新对象,如果不是则返回 result手写一个 new :functon myNew(fn,…args){ // 创建一个空对象 let obj = {} // 是空对象的隐式原型指向原函数的显式原型 obj._proto_ = fn.prototype // this指向 obj let result = fn.apply(obj,args) // 返回 return resule instanceof Object ? result : obj} 执行栈和执行上下文 什么是作用域,什么是作用域链 规定变量和函数的可使用范围称作作用域 每个函数都有一个作用域链查找变量或者函数式,需要从局部作用域到全局作用域依次查找,这些作用于的集合称作作用域链。什么是执行栈,什么是执行上下文? 执行上下文分为:全局执行上下文创建一个全局的 window 对象,并规定 this 指向 window ,执行 js 的时候就压入栈底,关闭浏览器的时候才弹出函数执行上下文每次函数调用时,都会新创建一个函数执行上下文行上下文分为创建阶段和执行阶段创建阶段:函数环境会创建变量对象:arguments 对象(并赋值)、函数声明(并赋值)、变量声明(不复制),函数表达式声明(不赋值);会确定 this指向;会确定作用域;执行阶段:变量赋值、函数表达式赋值,使变量对象编程活跃对象eval执行上下文执行栈:首先 栈特点:先进后出当进入一个执行环境,就会创建出它的执行上下文,然后进行压栈,当程序执行完成时,它的上下文就会销毁,进行弹栈栈底永远是全局环境的执行上下文,栈顶永远是正在执行函数的执行上下文只有浏览器关闭的时候全局执行上下文才会弹出 闭包 什么是闭包?闭包的作用?闭包的应用? 函数执行,形成私有的执行上下文,是内部私有变量不受外界干扰,起到保护和保存的作用作用:保护;避免命名冲突;保存;解决循环绑定引发的索引问题;变量不会销毁;可以使用函数内部的变量,是变量不会被垃圾回收机制回收应用设计模式中的单例模式for 循环中的 保留 i 的操作防抖和节流函数柯里化缺点(会出现内存泄露的问题) 原型和原型链 什么是原型?什么是原型链?如何理解 原型:原型分为隐式原型和显式原型,每个对象都有一个隐式原型,它指向自己的构造函数的显式原型。原型链:多个 _ proto _ 组成的集合称为原型链所有实例的 _ proto _ 都指向他们构造函数的 prototype所有的 prototype 都是对象,自然它的 _ proto _ 指向的是 Object() 的 prototype所有的构造函数的隐式原型指向的都是 Function() 的显式原型Object 的隐式原型是 null 继承 说一说 JS 中的常用的继承方式有哪些?以及各个继承方式的有学点 原型继承组合继承寄生组合继承ES6的extend原型继承把父类的实例作为子类的原型缺点:子类的实例共享了父类的构造函数的引用属性,不能传参varperson = { friends:[‘a’,’b’,’c’]}var p1 = Object.create(person)p1.friend.push(‘aaa’)//缺点:子类的实例共享了父类构造函数的引用类型console.log(p1)// 缺点:子类共享了父类构造函数的引用属性组合继承在子函数中运行父函数,但是要利用call把this改变一下在子函数的 prototype 里面 new Father(),使 Father 的原型中的方法页得到继承,最后改变 Son 的原型中的 constructor// 缺点:调用了两次父类的构造函数,造成了不必要的消耗,父类方法可以服用// 有点可以传参,不共享父类引用属性function Father(name){ this.name = name this.hobby = [‘篮球’,’足球’]}Father.prototype.getName = function (){ console.log(this.name)}function Son(name,age){ Father.call(this,name) this.age = age}Son.prototype = new FatherSon.pototype.constructor = Sonvar s = new Son(‘ming’,20)console.log(s) 寄生组合继承function Father(name){ this.name = name this.hobby = [‘篮球’,’足球’]}Father.prototype.getName = function (){ console.log(this.name)}function Son(name,age){ Father.call(this,name) this.age = age}Son.prototype = Object.create(Father.prototype)Son.prototype.constructor = Sonvar s2 = new Son(‘ming’,10)console.log(s2) extend子类只要继承父类,可以不写 constructor , 一旦写了,则在 constructor 中的第一句话必须是 superclass Son3 extends Father{ constructor(y){ super(200) // super(200) => Father.call(this,200) this.y = y }} 内存泄漏,垃圾回收机制 什么是内存泄漏? 内存泄漏是指不再用的内存没有被即使释放出来,导致该段内容无法被使用就是内存泄漏 为什么会导致内存泄漏 内存泄漏之我们无法通过js访问某个对象,而垃圾回收机制确任务该对象还在被引用,因此垃圾回收机制不会释放该对象,导致该模块内存永远无法释放,积少成多,系统会越来越卡以至于崩溃 垃圾回收机制都有哪些策略? 标记清除法垃圾回收机制根并标记他们,然后访问并标记所有来自他们的引用,然后再访问这些对象并标记他们的引用……如此低进结束后若发现有没有被标记的(不可达的)进行删除,进入执行环境的不能进行删除引用计数法当声明一个变量并给该变量赋值一个引用类型的值时候,该值的计数+1,当该值赋值给另一个变量的时候,该计数+1,当改制被其他值取代的时候,该计数+1,当计数变为0的时候,说明无法访问该值了,垃圾回收机制清除该对象 浅拷贝和深拷贝 基本类型没问题赋值的是数据(基本数据类型不存在浅拷贝和深拷贝问题)引用数据类型有问题引用类型赋值时,赋的是地址用JSON的方式来演示浅拷贝和深拷贝定义json对象var p = { “id”:”007″, “name”:”刘德华”, “books”:new Array(“三国演义”,”红楼梦”,”水浒传”)//这是引用类型}
4. 把对象p进行复制一份浅拷贝var p2 = {};for (let key in p){ p2[key] = p[key] }p2.books[0] = ‘五国’console.log(p2)console.log(p)
内存
5. 深拷贝(初步)var p2 = {};for(let key in p){ if(trpeof p[key] == ‘object’){ p2[ket] = [] for(let i in p[key]){ p2[key][i] = p[key][i] } }else{ p2[key] = p[key] }}p2.books[0] = ‘四国’console.log(p2)console.log(p)
内存中
深拷贝(最终)深拷贝对象如果都是 json 对象,那么就用递归的方式如果对象的属性是对象,属性的属性也是引用类型,即层层嵌套很多,只能用递归var p = { “id”:”007″, “name”:”刘德华”, “wife”:{ “id”:”008″, “name”:”刘德的妻子”, “address”:{ “city”:”北京”, “area”:”海淀区” } }function copyObj(obj){ let newObj = {} for(let key in obj){ if(typeof obj[key] == ‘object’){ newObj[key] = copyObj(obj[key]) }else{ newObj[key] = p[key] } } return newObj}let pNew = copyObj(p)pNew.wife.name = ‘张三疯’pNew.wife.address.city = ‘香港’console.log(pNew)console.log(p)
深拷贝 如果属性书数组等非键值对的对象单独处理:给数组一个自我赋值的函数(建议)单独判断 // 给数组对象添加一个方法,用来赋值自己Array.prototype.copyself = function(){ let arr = new Array() for(let i in this){ arr[i] = this[i] } return arr}var p = { “id”:”007″, “name”:”刘德华”, “books”:new Array(“三国演义”,”红楼梦”,”水浒传”)//这是引用类型}function copyObj(obj){ let newObj = {} for(let key in obj){ if(typeof obj[key] == ‘object’){ newObj[key] = copyObj(obj[key]) }else{ newObj[key] = p[key] } } return newObj}var pNew = copyObj(p);pNew.books[0] = “四国”;console.log(pNew);console.log(p);
单线程,同步操作 为什么js使单线程的? 因为js里面有科视的dom,如果是多线程的话,这个线程正在删除 DOM 节点,另一个小城正在编辑 DOM 节点,导致浏览器不知道该听谁的 如何实现异步编程? 回调函数 Generrator 是怎样使用的以各个阶段的变化如何? 首先生成器是一个函数,用来返回迭代器的效用生成器后不会立即执行,而是通过返回的迭代器来控制这个生成器的一步一步执行的通过调用迭代器的 next 方法来请求一个一个的值,返回的对象有两个属性,一个是 value;另一个是 done,是个布尔类型,done为true 说明生成器执行完毕,没有可返回的值了done 为 true 后继续调用迭代器的 next 方法,返回值的 value 为 undefined状态变化每当执行到 yield 属性的时候,都会返回一个对象这时候生成器处于一个非阻塞的挂起状态调用迭代器的 next 方法的时候,生成器又从挂起状态改为执行状态,继续上一次的执行位置执行直到遇到下一次 yield 一次循环知道代码没有 yield 了,就会返回一个结果对象 done 为 true,value 为 undefined Promise原理(一) promise 也还是使用函数,只不过是吧回调封装在了内部,使用上一直通过 then 方法的链式调用 应用: 1. 基础版本 上述代码很简单大致逻辑是这样的 使用 then 方法,将想要在 Promise 异步操作成功时执行的 onFulfilled 放入 callbacks 队列,其实也就是注册回调函数 创建 Promise 实例时传入的参数会被赋予一个函数类型的参数,即 resolve ,它会接收一个参数 value, 代表异步操作返回的结果,异步操作执行成功后,会调用 resolve方法,这时候其实真正执行的操作是将 callbacks 队列中的回调一 一执行
then 方法注册的 onFulfilled 是存在一个数组中,可见 then可以调用多次,注册多个 onFilfilled 会在异步操作完成后根据添加的顺序依次执行: 链式调用 then: 2. 加入延时机制 上面 Promise 的实现存在一个问题:如果把 then 方法注册 onFulfilled 之前,resolve 就执行了,onFulfilled 就不会执行到了,比如上面的例子中我们把 setTimout 去掉: 执行结果显示,只有 “同步执行” 被打印了出来,后面的 “then1” 和 “then2” 没有打印出来 Promises/A+ 规范明确要求回调通过异步方式执行, 要保证在resolve之前,.then方法已经注册完所有的回调: 在resolve 中添加定时器,通过 setTimeout 机制,将resolve 中执行回调的逻辑放置到js任务队列末尾,以保证在resolve执行时,then方法的 onFulfilled 已经注册完成
但是这样依然存在问题,在resolve执行后 , 再通过then 注册上来的onFulfilled 都没有机会执行了。如下图所示,我们加了延迟后,then1和then2可以打印出来了,但下列中的 then3 依然打印不出来,所以我们需要增加状态,并且保存 resolve 的值 3. 增加状态 为了解决上一节抛出的问题,必须加入状态机制 注意:当增加完状态后。原先的_resolve中的定时器可以去掉了,当 resolve 同步执行时,虽然 callbacks 为空,回调函数还没有注册上来,但没有关系,因为后面注册上来时,判断状态为 fulfilled , 会立即执行回调
promise原理(二) 链式调用的实现 真正的链式 Promise是指在当前 Promise 达到fulfilled 状态后,即开始进行下一个 Promise (后邻 Promise)。那么我们如何衔接到当前 Promise 和后邻Promise呢?(难点) 上面的实现,我们可以看到:then方法中,创建并返回了新的 Promise 实例,这是串行 Promise 的基础,是实现真正链式调用的根本then 方法传入的形参 onFulfilled 以及创建新 Promise 实例时传入的 resolve 放在一起,被 push 到当前 Promise 的 callbacks队列中,这是衔接当前 Promise和后邻 Promise 的关键onFulfilled可以是空的,为空时不调用 onFulfilled 手写 Promise.all 宏任务和微任务都有哪些? 宏任务script setTimeout setInterval setImmediatedom渲染微任务promise.thenprocessnextTickObject.observeMutationObserver注意 : Promise 是同步任务微任务 > DOM渲染 > 宏任务 宏任务和微任务都是怎样执行的? 执行宏任务script进入script后,所有的同步任务之线程执行所有宏任务放入宏任务执行队列所有微任务放入任务执行队列先清空微任务队列再取一个宏任务,执行,再清空微任务队列依次循环下图所示
控制台输出 <img src=https://zhuanlan.zhihu.com/p/”https://ae01.alicdn.com/kf/Hf3fc8bdc35b64cae8d19369a27d5d9c7M.png” alt=”img” style=”zoom: 150%;” /> 变量提升 函数提升 变量提升和函数提升的优先级 对所有函数声明进行提升(除了函数表达式和箭头函数),引用类型的赋值开辟堆空间存储内容将地址赋给变量对变量进行提升,之声明不赋值,值为undefined var、let、const 有什么区别 var :声明变量可进行提升,let、const 不会var可以重复声明var 是再非函数作用域中定义挂载到window上的 let:声明的变量只在局部起作用防止变量污染不可再声明 const:具有 let 的所有特征不可被改变如果 const 声明的是对象的话,是可以修改对象里面的信息的 箭头函数和普通函数的区别?箭头函数可以当作构造函数 new 吗? 箭头函数是普通函数的简写,但是它不具备很多函数的特性this指向问题,箭头函数的this 指向它定义时所在的对象,而不是调用时所在的对象不会进行函数提升没有 arguemnts 对象,不能使用 arguments,如果要参数的话可以使用rest 运算符没有 yield 属性,不能作为生成器 Generator 使用不能new没有自己的 this,不能调用 call 和 apply没有 prototype,new关键字内部需要把新对象的 _ prototype_指向函数的 prototype Es6 和 commonjs的区别 commonjs 模块输出的是值得拷贝,而es6 输出得值是值的引用commonjs是在运行时加载,是一个对象,es6实在编译时加载,是一个代码块commonjs 的this指向当前模块 ,es6 的this指向 undefined 跨域的方式有哪些?他们的特点是什么 JSONP JSONP通过同源策略涉及不到的“漏洞”也就是像 img 中的 src,link标签的href ,script的 src 都没有被同源策略限制到 同源策略:同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。 JSONP只能Get 请求 document.domain 只能跨一级域名相同的域(www.sigusoft.com和www.id.sigusoft.com,二者都有 sigusoft.com) 在主域的情况下相同,把document.domain设置成自身或更高一级的父域,也需要引入iframe;CORS 通过自定义请求头来让服务器,和浏览器进行沟通 有简单请求和非简单请求 满足以下条件,就是简单请求 请求方法是 HEAD,POST,GET 请求头只有 Accept.AccepeLanguage,ContentType,ContentLanguage,Last-Event_id 简单请求,浏览器自动添加一个Origin字段 同时后端 需要设置的请求头 Access-Control-Allow-Origin — 必须 Access-Control-Expose-Headers SMLHttpRequest 只能拿到六个字段,要想拿到其他的需要在这里指定 Access-Control-Allow-Credentials — 是否可传 cookie 要是想传cookie,前端需要设置 xhr.withCredentials = true,后端设置 Access-Control-Allow-Credentials 非简单请求,浏览器判断是否为简单请求,如果是非简单请求 , 则浏览器先发送一个 header 头为 option 的请求进行预检 预检请求格式(请求行的请求方法为 OPTIONS(专门用来询问的)) Origin Access-Control-Request-Method Access-Control-Request-Header 浏览器检查了 Origin,Access-Control-Allow-Method和Access-Control-Request-Header之后确认允许就可以做出回应了 通过预检后,浏览器接下来的每次请求就类似于简单请求了nginx 代理跨爱与 neginx模拟一个虚拟服务器,因为服务器与服务器之间是不存在跨域的 发送数据时,客户端 -> nginx -> 服务端 返回数据时 ,服务端 -> neginx -> 客户端 讲一讲三次握手四次挥手,为什么是三次握手 而不是两次握手? 客户端和服务器之间通过三次握手建立连接,四次挥手释放连接三次握手:客户端先向服务端发起一个 SYN 包进入 SYN_SENT 状态,服务端收到 SYN 后,给客户端返回一个 ACK+SYN 包,表示已收到 SYN,并进入 SYN_RECEIVE 状态,最后客户端在向服务端发送一个 ACK 包表示确认,双方进入 establish 状态之所以是三次握手而不是两次,是因为如果只有两次,在服务端收到 SYN 后,向客户端返回一个 ACK 确认就进入 establish 状态,万一这个请求中间遇到网络情况而没有床给客户端,客户端一直是等待状态,后面服务端发送的信息客户端也接受不到了 四次挥手首先客户端发送一个 FIN 包,进入 FIN_WAIT1 状态,服务端收到后,向客户端发送 ACK 确认包,进入 CLOSE_WAIT 状态,然后客户端收到 ACK 包后进入 FIN_WAIT2 状态,然后服务器再把自己剩余没传完的数据发送给客户端,发送完毕后再发送一个 FIN+ACK 包, 进入 LAST_ACK (最后确认)状态,客户端收到 FIN+ACK 包后,再向服务器发送 ACK 包,在等在两个周期后关闭连接之所以等待两个周期是因为最后服务器端发送的 ACK 包可能会丢失,如果不等待 2 个周期的话,服务端在没收到 ACK 包之前,会不停的发送 FIN 包而不关闭,所以得等待两个周期 HTTP 的结构 请求行 请求头 请求体 空行 请求行包括 http 版本号,url, 请求方式 相应行包括,状态码, 原因 HTTP 头部有哪些字段 请求头cache-control 是否使用缓存Connection:keep-alive 与服务器的连接状态host 主机域返回头cache-controletag 唯一标识,缓存用的last-modified 最后修改时间 localStorage / SessionStorage / cookie / session 之间有什么区别 localStorage 生命周期:关闭浏览器后数据依然保留,除非手动删除,否则一直在作用域: 相同浏览器的不同标签在同源情况下可以共享 localStoragfesessionStorage生命周期: 关闭浏览器或标签后即生效作用域: 只在当前标签可用,当前标签的 iframe 中且同源即可共享cookie是保存在客户端的,一般由后端设置值,可以设置过期时间存储大小只有 4k 一般用来保存用户信息的在 http 下 cookie 是明文传输的 ,不安全cookie属性有http-only: 不能被客户端更改访问,防止xss攻击(保证 cookie 安全性的操作)Secure: 只允许在 https 下传输Max-age: cookie生成后失效的秒数expire:cookie 的最长有效时间,若不设置则cookie 生命周期会话其相同sessionsession 是保存在服务端的session的运行以来 sessionld , 而sessionld 有保存在 cookie 中, 所以如果禁用的cookie , session也是不能用的,不过硬要用也可以,可以把 sessionld保存在 URL中session 一般用来跟踪用户的状态session 的安全性更高,保存在服务端,一般为使服务器性能更加,会考虑信息保存在 cookie 中 http 缓存 缓存分为强缓存和协商缓存强缓存在浏览器加载资源时,先看看 cache-control 里的 max-age ,判断数据有没有过期,如果没有直接使用该缓存,有些用户可能会在没有过期的时候就点了刷新按钮,这个时候浏览器就回去请求服务端,想要避免这样做,可以在 caceh-control 里面加一个 immutablepublic 允许客户端和虚拟服务器缓存该资源,cache-control 中的一个属性private 只允许客户端缓存该资源no-cache不允许强缓存,可以协商缓存no-store不允许缓存协商缓存浏览器加载资源时,没有命中强缓存,这时就去请求服务器,去请求服务启动的时候,会带着两个参数,一个是 if-None-Match , 也就是响应头中的 etag 属性,每个文件对应一个 etag ;另一个参数时 -f-Mindified-Since,也就是响应头中的 Last-Modified 属性 ,带着这两个参数去检验缓存是否真的过期,如果没有过期,则服务器会给浏览器返回一个 304 状态码,表示缓存没有过期,可以使用就缓存 etag 的作用: 有时候编辑了文件,但是没有修改,但是 last-modified 属性的时间就会该变,导致服务器重新发送资源,但是 etag 的出现就完美的避开了这个问题,它是文件的唯一标识 缓存位置: 内存缓存 Memory-Cache 离线缓存 Service-Worker 磁盘缓存 Disk-Cache 推送缓存 Push-Cache tcp和udp有什么区别 连接方面tcp 面向连接,udp不需要连接tcp需要三次握手四次挥手请求连接可靠性tcp时可靠传输;一旦传输过程中丢包的话就会进行重传udp是不可靠传输,但会最大努力交付工作效率udp 实时性高,比 tcp 工作效率高因为不需要建立连接,更不需要复杂的握手以及挥手复杂的算法,也没有重传机制是否支持多对多tcp是点对点的udp支持一对一,一对多,多对一首部大小tcp首部占20字节udp首部占8字节 从浏览器输入 url 后都经历了什么 检查缓存解析dnstcp三次握手 发起http请求返回 html 关闭tcp 解析html渲染显示 先进行 DNS 域名解析,先查看本地 hosts 文件,查看有没有当前域名对应的 ip 地址, 若有直接发起请求,没有的话会在本地域名服务器去查找,该查找属于递归查找,如果本地服务器没查到,会从根域名服务器查找,该过程数据迭代查找,根域名会告诉你从哪个故武器查找,最后查找到对应的 ip 地址后把对应规则保存到本地的 host 文件中 如果想加速以上及之后的 http 请求过程的话可以使用缓存服务器 CDN,CDN过程如下: 用户输入url地址后,本地 DNS 会解析 url 地址,不会把最终解析权交给 CNAME 指向的 CDN 的 DNS 服务器 CDN 的 DNS 服务器会返回给浏览器一个全局负载均衡 ip 用户根据全局负载均衡 ip 请求全局负载均衡服务器 全局负载均衡服务器会根据 用户的 ip 地址,url 地址,会告诉用户一个区域负载均衡设备,让用户去请求它 区域负载均衡服务器会为用户选择一个里用户较近的最优的缓存服务器,并把 ip 地址给到用户 用户向缓存服务器发送请求,如果请求不到想要的资源的话,会一层层向上一级查找,直到查找到位置 进行 http 请求,三次握手四次挥手建立/断开连接 服务器处理,可能返回304 也可能返回200 返回304 说明客户端缓存可用,直接使用客户端缓存即可,该过程属于协商缓存 返回200的话会同时返回对应的数据 客户端自上而下执行代码 其中遇到 CSS 加载的时候 ,CSS不会阻塞 DOM 树的解析,但是会阻塞 DOM树的渲染,并且 CSS 会阻塞下面的 JS 的执行 然后是 JS 加载, JS 加载会影响 DOM 的解析,之所以会影响,是因为 JS 可能会删除添加节点,如果解析后加载的话,DOM树还得冲进解析,性能比较差,富国不想阻塞 DOM 树的解析的话,可以给 script 添加一个 defer 或者 async 的标签 defer : 不会阻塞 DOM 解析,等 DOM 解析完之后在运行,在 DOMContentloaed 之前 async:不会阻塞DOM 解析,等该资源下载完成之后立刻运行 进行 DOM 渲染和 Render 树渲染 html 并解析为 DOM 树 解析css 并形成一个 cssom(css树) 将 cssom 和 dom 合并成渲染树(render树) 进行布局(layout) 进行绘制(painting) 回流重绘 回流必重绘,重绘不一定引起回流 什么是 CDN? 关于 cdn、同源等问题一网打尽首先访问本地的 DNS , 如果没有命中,继续递归或者迭代查找,知道命中拿到对应的 ip 地址拿到对应的 IP 地址之后服务器端发送请求到目的地址,注意这里不要返回的,不直接是 cdn 服务器的地址,欸是全局负载均衡系统的 ip 地址全局负载均衡系统会根据客户端的 IP 地址 和请求的URL 和对应的区域负载均衡系统通信区域负载均衡系统 拿着这两个东西距离客户最近且有相应资源的 cdn 服务器的地址,返回给全局负载均衡系统全局负载均衡系统会返回确定的 cdn 缓存服务器的地址给客户端客户端请求缓存服务器上的文件 什么是xss? 什么是 csrf? xss 脚本注入 不需要你做任何的登录认证,他会通过合法的操作(比如在 url 输入、在评论框中输入),想你的页面注入脚本(可能是js、html代码块等) 防御 编码:对用户输入数据进行 HTML Entity 编码,把字符串转换成转义符,Encode 的作用是将 $var 等一些字符转化,使得浏览器在最终输出结果是一样的 过滤:移除用户输入的事件相关属性 csrf 跨域请求伪造 在未退出 A 网站的前提下访问 B ,B 使用 A 的cookie 去访问浏览器 防御: token,每次用户提交表单时需要带上 token (伪造者访问不到),如果 token 不合法,则服务器拒绝请求 什么是回流?什么是重绘? 回流 render 树中一部分或者全部素都要改变尺寸、布局、或者需要隐藏而需要重新构建。这个过程叫回流 回流必将引起重绘 重绘 render 树中一部分素改变,而不影响布局的、之影响外观的,比如颜色。该过程叫做重绘 页面至少经历一次回流和重绘(第一次加载的时候) 事件冒泡和时间捕捉有什么区别 事件冒泡 在 addEventListener 中的第三属性设置为 False(默认) 从下至上(儿子至祖宗)执行 事件捕获 在 addEventListener 中的第三属性设置为 true 从上至下(祖宗至儿子)执行 什么是防抖?什么是节流?手写一个 防抖 n 秒后执行改时间,若在n 秒内被重复触发,则重新及时 节流 n秒内只运行一次,若在n秒后被重复触发,只有一次生效
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/20803.html