前端面试题集




1、 [1,2,3].map(parseInt)输出结果?

        答案:1,NaN,NaN

        解析:

array.map(function callback(currentValue,index,array){}[,thisArg])方法的作用是遍历array中的每一项,并为每个元素都执行callback函数;

parseInt()方法有两个作用:①当参数为一个时,将其他类型数据转换成字符串

                                             ②当参数为两个时,以第二个参数解析数据,进行进制的数据转换(第二个参数需满足大于2小于36,0表示10进制)

这里,第一个参数为数组中的每个元素,第二个参数为index,即是考察parseInt的第二个用法所以表示为:

parseInt(1,0);parseInt(2,1));parseInt(3,2)

得1,NaN,NaN

2、手写一个完整的继承

        答案:

前端面试题集_第1张图片

3、eventLoop事件循环和事件队列

        答:js的异步机制由事件循环和任务队列构成。(js本身是单线程)

            javascript主线程拥有一个执行栈以及一个任务队列,主线程会依次执行代码,当遇到函数时,会先将函数入栈,函数运行完毕后会再将该函数出栈,直到所有代码执行完毕。

            遇到异步操作,例如:setTimeout、ajax时,异步操作会由浏览器执行,浏览器会再这些任务完成后,将事先定义的回调函数推入主线程的任务队列中,当主线程的任务栈清空后会读取任务队列中的回调函数,然后去执行,从而进入一个无线循环,这就是事件循环。

            一个浏览器环境只能拥有一个事件循环,而一个事件循环可以多个任务队列,每个任务都有一个任务源。任务队列是一个先进先出的队列

4、https的工作原理

            解析:https在传输数据之前需要客户端(浏览器)和服务器之间进行一次握手,在握手过程中确立双方加密传输数据的密码信息。TLS/SSL是一条加密传输协议,使用了对称加密,非对称加密以及hash算法。

握手的过程:浏览器将自己支持的一套加密规则发送给服务器;网站从汇总选出一组加密算法与hash算法,并将自己的身份信息以整数的形式发送给浏览器。证书里包含了网址,加密公钥,以及证书的颁发机构等信息,浏览器获得证书后要验证证书的合法性,如果证书不受信任会给出提示,如果证书受信任,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。使用约定好的hash算法发计算握手消息,并使用生成的随机数对消息进行加密,最后将之前生成的所有信息发送给网站。

网站接受浏览器发送来的数据要做一下的操作:使用自己的私钥将信息解密,取出密码,使用密码解密浏览器发来的握手信息,并验证hash是否一致。使用密码加密一段握手消息发送给浏览器。

               客户端如何验证证书的合法性:校验证书的颁发机构是否受客户端信任;通过CRL或OCSP的方式校验证书是否被吊销;对比系统时间,校验证书是否在有效期内;通过校验对方是否存在证书的私钥,判断证书的网站域名是否与证书颁发的域名一致;

5、https和http的区别

        答:https比较安全,经过TLS/SSL加密,需要ca证书,需要收费;

                https和http的端口号不同,https默认端口号是443,http默认端口号是80;

                http是超文本传输协议,信息是明文传旭,https是具有安全性的加密传输协议;

                http连接很简单,是无状态的;https协议是由ssl+http协议构建的可加密传输,身份认证的网络协议比http协议安全;

6、http2 和http1 的区别

            答:http2采用二进制格式而非文本格式,解析起来更高效;

                    http2是完全多路复用的,即一个tcp连接上同时跑多个http请求

                     http2使用报头压缩,降低了开销;

                    http2让服务器可以将响应主动推送到客户端缓存中,支持服务端推送,就是服务器可以对一个客户请求发送多个响应;

7、请求报头举例

            答:Accept:客户端可识别的内容类型列表,用于指定客户端接受那些类型的消息;

                    cache-control:用于指定缓存指令,缓存指令是单向的且是独立的,一个消息的缓存指令不会影响另一个消息的缓存指令

                    host:请求主机名;

                    user-agent:发送请求的浏览器类型、操作系统等信息

                    Accept-Language:表示浏览器支持的语言类型;

8、输入URL后网页到底做了什么

            答:通过域名(DNS)解析IP地址,查找域名对应的ip地址

                    根据ip地址建立TCP的三次握手

                                ①客户端发送syn包到服务器,等待服务器确认:syn_send;
                                ②服务器手动syn包,确认客户端的syn并发送自己的syn包:syn_recv;
                                ③客户端收到服务器端发送的syn+ack包,向服务器发送确认包ack,此包发送完毕:established;完成三次握手

                    浏览器与服务器通信:浏览器发起请求,服务器响应请求

                                  ①浏览器根据URL内容生成http请求;
                                  ②服务器收到请求后会根据内容获取相应的html文件,将得到的HTML发送给客户端;
                                  ③在浏览器还没有完全接收html文件时便开始渲染,显示网页;
                                  ④在执行html文件时,根据需要请求图片,css,js等文件

                    浏览器与服务器断开链接(TCP的四次挥手


                  计算机网络体系结构:7层模型

                       应用层(HTTP、SMTP、FTP、POP3);

                        传输层(TCP、UDP);

                        网络层(IP、路由器):

                        数据链路层(网桥 ppp CD);

                        物理层(集线器);

9、浏览器渲染展示网页的过程:

               答:html代码转化为DOM树,css代码转化成css object model;结合dom和cssom生成一颗渲染树;生成布局,将所有渲染树的节点进行平面合成;将布局绘制到屏幕上;使用JavaScript脚本来动态的修改dom,以便给web应用带来动态行为;最后,web应用执行;

                回流:当render tree中的一部分或全部因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就称之为回流。每个页面至少有一次回流,也就是页面第一次加载的时候。完成回流后,浏览器会重新绘制受影响的部分到屏幕中去,这就称之为重绘。

                触发回流的几种情况:
                        1.添加或者删除可见的dom元素;
                        2.元素位置改变;
                        3.元素尺寸改变-边距、填充、边框、宽度、高度;
                        4.页面渲染初始化;
                        5.内容改变-文本改变或者图片大小改变,引起计算值宽度,高度的改变;
                        6.浏览器尺寸大小的改变-resize事件发生时;

                   重绘:回流必将引起重绘,重绘不一定会引起回流

                    减少重绘回流的实现:
                    1.css :使用transform代替top;
                                 使用visibility代替display:none;
                                 避免使用table布局
                                  尽可能在dom树的最末端改变class,限制了回流的范围,使其影响尽可能少的节点;
                                  避免设置多层内联样式;避免层级过多;
                                  避免使用css表达式,将频繁重绘或者回流的节点设置为图层;
                       2.javascript:避免频繁操作样式,最好一次性重写style样式;
                                    避免频繁操作DOM,最好创建一个documentFragment,在它上面应用所有的DOM操作,最后再把它添加到文档中。
                                    避免频繁读取会影响重绘回流的属性,用一个变量缓存起来;
                                    对一个复杂动画的元素使用绝对定位,使他脱离文档流,否则会引起父元素以及后续元素频繁回流;

10、xss攻击和csrf攻击防御

            答:xss的防御:1.对用户输入的内容进行解析和过滤或编码(过滤有危险的dom节点,如script img link style iframe等)
                                       2.对cookie做保护,设置httpOnly,防止客户端通过document.cookie读取cookie;

                    csrf的防御:1.尽量减少使用get请求;
                                         2.使用验证码;
                                         3.referer check;
                                         4.使用token;

11、数组去重

              解析:

前端面试题集_第2张图片

12、跨域

            jsonp的原理:动态创建一个script标签,动态加载一个js文件,载入成功后会执行在URL参数中指定的函数,并把需要的json数据所谓参数传入;

            优缺点:只能传递get请求,有一定得限制;


前端面试题集_第3张图片

            cros跨域资源共享:(原理)服务器对于cros的支持,设置Access-Control-Origin为你传输的origin的值,浏览器监测到响应的设置,支持跨域;

            优缺点:支持所有类型的请求 get、post、put、delete、update等;

            node中间件代理跨域:通过启用一个代理服务器,实现数据的转发;node+vue+webpack-dev-server大力接口跨域,在开发模式下,只需要设置devServer=>proxy即可

前端面试题集_第4张图片

14、this的使用场景+apply、call、bind的区别,手动封装

            this的使用场景:this的值会随着函数的使用场景的不同而发生变化,但是一个原则就是,this指的是调用函数的那个对象,即谁调用指向谁;

            ①作为对象的方法调用;
            ②构造器调用;
            ③function.prototype.call 或 function.prototype.apply调用;
            ④作为普通函数调用;

             call和apply的用途:①改变this的指向;②借用其他对象的方法 
                                                call的另外一个作用就是:将伪数组转换为数组:Array.prototype.slice.call(divs);---divs为要转换的伪数组

              call 和apply 的区别:都是用来改变this的指向,都可以借用其他对象的方法,不同是apply的第二个参数传值方式必须是集合,即伪数组或者数组,call的第二个参数传值是依次传入各个值,用逗号分隔;他们的第一个参数都代表的是函数体内this的指向;

               bind和call、apply的区别:call和apply是立即执行函数,bind非立即执行,为函数体,执行时在后面加小括号,小括号中传值

15、ES6的重要知识点:

           1> Generator函数是es6提供的异步编程解决方案,可以理解为是一个状态机,封装了多个内部状态;
            2>Generator函数会返回一个遍历器对象;可以依次遍历函数内部的内一个状态,特征:function关键字与函数名之间有一个*号,二是,函数体内部使用yield表达式,定义不同的内部状态;
            3>Generator函数是分段执行的,yield表达式是暂停执行的标记,next方法每次执行,内部指针就从函数头部或者上次停下来的地方开始执行,直到遇到下一个yield表达式为止。
            4>es6中let const命令:不存在变量提升,不允许声明前使用,会报错;let声明的是块级作用域;这时候会存在一个临时死区,即{}中间都为临时死区,不受外部的影响。let不允许相同作用域内重复声明一个变量。
            5>为什么需要块级作用域?---场景① 内层变量可能会覆盖外层变量(由于存在变量提升);场景②用来计数逇循环变量泄露为全局变量;
            6>内层作用域可以定义外层作用域同名的变量,块级作用域的出现替换掉了原来的匿名函数IIFE;函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域中声明。块级作用域必须有大括号,没有就报错;严格模式下,函数声明只能在当前作用域的顶层;
            7>const命令声明的变量不能改变值,这意味着,一旦声明立即执行初始化,不能留到以后赋值,只声明不赋值就会报错;
            8>es6提供了新的数据结构Set。类似于数组,但是成员的值都是唯一的,没有重复的值;本身是一个构造函数,用来生成set数据结构。
            9>字符串去重:

            10>Set实例的属性和方法:
                    ①Set.prototype.constructor:构造函数,默认就是Set函数;
                    ②Set.prototype.size:返回Set实例的成员总数;
                    ③Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
                    ④Set.prototype.clear():清楚所有成员,没有返回值;
                    ⑤Set.prototype.keys():返回键名的遍历器;
                    ⑥Set.prototype.values():返回键值得遍历器;可省略valuse方法,直接用for...of 循环遍历set。
                    ⑦Set.prototype.entries():返回键值对的遍历器;
                    ⑧Set.prototype.forEach():使用回调函数遍历每个成员;语法:forEach(function(value,key,集合本身--可省略));
                    ⑨
            

前端面试题集_第5张图片

            11>promise对象:

                    promise是异步编程的一种解决方案,可以获取异步操作的消息,提供统一的API,是一个容器,保存着未来才会结束的事件;对象的状态不受外界的影响,一旦状态改变,就不会在变,从pending(进行中)变成fulfilled(已成功) 和从 pending变为rejected(已失败)

                    缺点:一旦新建就会立即执行,无法中途取消。如果不设置回调函数,promise内部会抛出错误,但是不会反应到外部,pending状态时无法无法得知进展到哪一个阶段;

                    promise构造函数接收一个函数作为参数,改函数有两个参数,resolve 和reject,他们是两个函数由JavaScript引擎提供,不用自己部署;resolve函数的作用是将promise对象的状态从未完成变为成功(pending--resolved);reject函数的作用是将promise对象的状态从未完成变成失败(pending--rejected)

前端面试题集_第6张图片

16、VUE项目中给列表组件绑定key的作用:

            答:key是给每一个vnode的唯一id,可以依靠key更准确,更快的拿到原来节点中对应节点,否则如果对节点进行了增删操作,节点无变化,但是节点的内容发生了更新;绑定唯一的id后key就无法复用了,利用key的唯一性生成map对象来获取对应节点;

17、防抖节流的概念,有什么区别,如何实现

            防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算事件;
            实现:每次触发事件时,都取消之前的延时调用方法,或者清定时器;

            节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
            实现:每次触发事件时都判断当前是否由等待执行的延时函数;

18、Set、Map、WeakSet、WeakMap之间的区别

            Set:成员唯一、无序且不重复;可以遍历,方法有add、delete、has; [value,value],键值与键名是一致的,可以理解为没有键名;
            WeakSet:成员都是对象;成员都是弱引用,可以被垃圾回收机制回收,可以用来保存dom节点,不容易造成内存泄漏;不能遍历,方法有add、delete、has
            Map:本质上是键值对的集合,类似集合;可以遍历,方法很多,可以跟个数据格式转换;
            WeakMap:只接受对象作为键名,null除外,不接受其他类型的值作为键名;弱引用,键值任意,键名指向的对象可以被垃圾回收机制回收,不能遍历;

19、事件循环中函数的执行顺序问题(async、await、setTimeout、Promise函数)

            任务队列:js分为同步任务异步任务
            同步任务都在主线程上执行,形成一个执行栈,主线程外事件触发线程管理一个任务队列,异步任务就会注册回调函数,存放到任务队列中去,一旦主线程执行栈中的所有同步任务执行完毕,就会读取任务队列,将可运行的异步任务添加到可执行栈中执行;
            一个eventloop中可以有一个或者多个taskqueue 一个任务队列就是一个任务集合;每一个任务都有一个任务源,源自同一个tasksource 的task必须放到同一个任务队列,从不同源来的则被添加到不同队列。setTimeout/Promise等API便是任务源,进入任务队列的就是他们制定的具体执行任务;

            宏任务:每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行);浏览器为了能够是的js内部的宏任务与dom任务能够有序的执行,会在一个宏任务执行结束后,在下一个宏任务执行开始前,对页面进行重新渲染
            宏任务主要包含:script整体代码、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate

            微任务:可以理解是当前task执行结束后立即执行的任务,也就是在当前task任务后,下一个task之前,在渲染之前;所以微任务的响应速度相比setTimeout会更快,无需等渲染,也就是说,在某一个宏任务执行完毕后,就会在它执行期间产生的所有微任务都执行完毕(渲染前)。
            微任务主要含:Promise.then 、MutationObserver、Process.nextTick   

            运行机制:每进行一次循环操作称之tick,每一次tic的步骤如下:
                    执行一个宏任务,栈中没有就从任务队列中获取;
                    执行过程中如果遇到微任务,就将它添加到微任务的任务队列中;
                    宏任务执行完毕后,立即执行当前微任务队列中的所有微任务;
                    当前微任务执行完毕开始检查渲染,然后GUI线程接管渲染;
                    渲染完成后,js线程继续接管,开始下一个宏任务


前端面试题集_第7张图片

            Promise和async中的立即执行:Promise中的异步体现在then和catch中,所以写在Promise中的代码是被当做同步任务立即执行的,而在async/await中,在await出现前,其中的代码也是立即执行的,那么出现await,后面的表达式会先执行一遍,将await后面的代码加入到微任务中,然后就会跳出整个async函数来执行后面的代码。(await其实就是微任务)

            执行顺序为:宏任务>执行栈>微任务
            script代码先执行,遇见async/await时,await前的代码会立即执行,awit后的表达式会先执行,awit后的代码会加入到微任务队列中去,接着会跳出async;

20、js的异步发展历程以及优缺点

            答:①回调函数:缺点:不能用try catch捕获错误,不能return;
                    ②promise 为了解决callback的问题产生的。实现链式调用,每次then返回的都是一个全新的promise,如果我们在then中return,return的结果会被promise的resolve()包装。缺点:无法取消promise,错误需要回调函数来捕捉;
                    ③Generator:可以控制函数的执行,可以配合co函数库使用
                    ④Async/await异步的终极解决方案:await会导致性能上的降低;

                     ⑤promise构造函数是同步执行的,then方法是异步执行的;

21、npm安装机制,为什么输入npm install 就可以自动安装对应的模块?

               答:npm安装机制:发出npm install命令后会查询node_modules目录之中是否已经存在指定的模块,若存在,则不需要重新安装,若不存在,npm向registry查询模块压缩的网址;放在根目录.npm目录里;解压压缩到当前node_modules目录;
                npm实现原理:执行工程自身preinstall;确定首层依赖模块,也就是dependencies和devdependencies属性中直接指定的模块;接着获取模块,首先要确定其版本,package.json中往往是语义化版本,如果有信息直接拿即可,如果没有,则从仓库中获取最新版本;

22、判断数组类型的三种方法优劣分析:

                解析:Object.prototype.toString.call() 每一个继承Object的对象都有一个toString的方法,如果toString方法没有被重写,会返回object type 其中type为对象的类型。但是当除了object对象外,其他类型直接使用toString方法会直接返回内容的字符串,所以需要使用call或者apply方法来改变toString方法的执行上下文;基本的数据类型都能判断,null 和undefined都可以--用于判断浏览器内置对象;
                instanceof的内部机制是通过判断对象的原型链中是不是能找到类型的prototype。判断一个对象是否为数组,会判断这个对象的原型链上是否会找到对应的Array的原型,找到返回true,否者返回false;只能用来判断对象类型,原始类型不可以;并且所有对象类型instanceof object都是返回true;
                Array.isArray()是es5新增的方法,当不存在的时候,可用object.prototype.toString.call()方法;性能最好;

23、观察者模式 vs 发布订阅者模式:

            答:观察者模式中主体和观察者是互相感知的,发布-订阅模式是借助第三方vuex来实现调度的,发布者和订阅者之间互不感知;发布订阅者模式更适合于复杂场景;

24、cookie和token为什么token不会被劫持

            答:cookie登录后后端生成一个sessionid放在cookie中返回给客户端,并且服务器一直记录着这个sessionid,客户端以后每次请求都会带上这个sessionid,服务端通过这个sessionid来验证身份之类的操作哦,所以别人拿到了cookie也就是拿到了存放的sessionid,就可以完全替代;
              token:登录后后端返回一个token给客户端,客户端将这个token存储起来,每次客户端发送请求都需要开发者手动将token放到header中去,服务端每次只需要对这个token进行验证就能使用token中的信息来进行下一步操作了;

25、vue的双向数据绑定,以及view如何改变model,model如何改变view

            答:vue双向数据绑定的核心是利用es5的object.defineProperty,这也就是为什么vue不能兼容ie8以下的浏览器的原因;Object.defineProperty方法会直接在一个对象上定义一个新属性,或者修改一个对象现有的属性,并返回这个对象;
             Object.defineProperty(obj,prop,descriptor)---obj定义属性的对象,prop要定义或者要修改的属性;descriptor将被定义或者修改属性的描述【核心】;
              observe的功能就是监测数据的变化。它是一个类,它的作用是给对象添加getter和setter,用于依赖收集和派发更新;
               依赖收集getter:*const dep = new Dep()//实例化一个dep实例
                                           *在get函数中通过dep.depend做依赖收集;
                派发更新setter: *childOb = !shallow && observe(newval) //如果shllow为false的情况,会对新设置的值编程一个响应式对象;
                                            *dep.notify() //通知所有订阅者
                 派发的过程:当我们的组件中对响应的数据做了修改,就会触发setter的逻辑,最后调用dep.notify()方法,他是dep的一个实例方法,具体做法是遍历依赖收集中建立的subs,然后调用每个watcher的update方法; vue在做派发更新时的一个优点,它并不会每次数据改变都会触发watcher回调,而是把这些watcher先添加到一个队列中,然后再nextTick(属于微任务)后执行watcher的run函数

                vue中子组件不可以修改父组件传递的prop的值,原因是:为了保证单向数据流,易于监测数据的流动,出错容易定位,如果修改了,会触发props的set方法时发现更新,会给出警告;

                Object.defineProperty的缺点:无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应
                Object.defineProperty只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy可以劫持整个对象,并返回一个新的对象。


26、改造下面代码,使之输入0-9,写出你能想到的所有解法。
                                                        

前端面试题集_第8张图片

27、BFC的概念及其应用

            答:BFC就是块级格式上下文,是页面盒模型布局的一种渲染模式,相当于一个独立的容器,里面的元素和外面的元素相互不影响,创建bfc的方式有: html根元素、float浮动、绝对定位、overflow不为visiable; display为表格布局或者弹性布局;
            BFC的主要作用:清浮动、防止同一bfc容器中的相邻元素间的外边距重叠问题

28、发送数据埋点使用1X1的透明gif图片的原因:

            答:①没有跨域问题,img天然支持跨域;②不会阻塞页面加载,不影响用户体验;性能更好;③gif的最低合法体积最好,相比较bmp、png、jpg而言

29、让一个div水平垂直居中:

            方法一:

前端面试题集_第9张图片

            方法二:

前端面试题集_第10张图片

            方法三:

前端面试题集_第11张图片

            方法四:

前端面试题集_第12张图片

30、对MVVM开发模式的理解:

31、canvas画布与svg的区别:

            答:canvas为标量图,是通过JavaScript绘制的2D图形,不支持事件处理器,文本渲染力弱,最适合图形密集型的游戏;svg为矢量图,是通过xml描述的2D图形,支持事件处理器,不适合游戏的应用,适合带有大型渲染区域的应用程序,如百度地图,谷歌地图等;

32、px、em和rem三者的区别与联系:

            答:  px即Pixel像素,是长度单位,可以理解为绝对像素,像素是相对于显示器屏幕而言,IE无法调整那些使用px作为单位的字体大小;
            em可以理解为相对长度,相对于当前对象内文本的字体尺寸;    10px=1em ,所以px除以10加em就可以转换为em;em的值并不是固定的,会继承父级字体的大小 ;
            rem是css3中新增的一个相对单位,相对于根html元素;修改根元素的大小就成比例的调整所有字体大小;可以从浏览器字体设置中继承字体大小;

33、git和svn的区别:        

            答:最核心的区别git是分布式的,svn不是,即使没有网络也可以commit,查看历史版本记录,创建项目分支等操作,等网络连接再push到server端;git没有一个全局版本号,git的内容完整性要优于svn;git把内容用元数据方式存储,svn是按文件,git clone效率高;

34、webpack.json 文件中必备字段:

            答:两种依赖:dependencies(生产环境包的依赖:正常运行该包所需要的依赖项) 和 devDependencies(开发环境包的依赖:开发的时候需要的依赖项)


35、遍历数组的方法:

            答案:① 使用for循环遍历数组;
                       ② 使用foreach((item,index,array)=>{回调函数});  -------没有返回值,对原数组无影响,支持IE;
                        ③ 使用array.map(function (value,index,array){回调函数  return XXX});有返回值,可以return出来,不影响原来的数组;
                        ④ 使用 for of ;
                        ⑤filter 进行遍历

你可能感兴趣的:(前端面试题集)