当前位置: 首页 > Web前端 > JavaScript

腾讯前端必遇面试题集

时间:2023-03-27 17:28:32 JavaScript

什么是闭包闭包是一个特殊的对象,它由两部分组成:执行上下文(代码A),和在执行上下文中创建的函数(代码B),当B执行时,如果访问了A中的变量对象的值,那么就会产生一个闭包,这个执行上下文A的函数名用来引用Chrome中的闭包。CSSSprites的理解CSSSprites(spritemap)将一个页面涉及的所有图片都包含成一张大图,然后结合CSSbackground-image、background-repeat、background-position属性进行背景定位。优点:使用CSSSprites可以减少网页的http请求,从而大大提高页面的性能。这是CSSSprites最大的优势;CSSSprites可以减少图片的字节数,将3张图片合并为1张图片的字节数总是小于这3张图片的字节数之和。缺点:合并图片时,必须将多张图片有序合理地合并为一张图片,并且要留出足够的空间,防止版块中出现不必要的背景。宽屏高分辨率下的自适应页面,如果背景不够宽,很容易把背景弄坏;CSSSprites在开发的时候比较麻烦,需要用photoshop或者其他工具测量每个背景单元Location的精确值。维护:CSSSprites维护起来很麻烦。当页面背景有细微变化时,必须改变合并后的图片。尽量不要更改不需要更改的部分,以免更改更多的CSS。如果在原来的地方放不下去,只能(最好)往下加图片,这样图片的字节会变大,css也得改。函数柯里化什么是函数柯里化?实际上,它是一种将使用多个参数的函数转换为一系列使用一个参数的函数的技术。仍不知道?让我们举个例子。functionadd(a,b,c){returna+b+c}add(1,2,3)letaddCurry=curry(add)addCurry(1)(2)(3)现在是实现curry的功能,使函数从一次调用传递多个参数到每次调用一个参数多次调用。functioncurry(fn){letjudge=(...args)=>{if(args.length==fn.length)returnfn(...args)return(...arg)=>judge(...args,...arg)}returnjudge}Object.isImplementation标题说明:Object.is不会对被比较的两个值进行类型转换,更类似于===,也有一些区别他们之间的区别。1、NaN在===中不相等,但在Object.is中相等2、+0和-0在===中相等,但在Object.is中不相等实现代码如下:Object.is=function(x,y){if(x===y){//目前的情况只有一种情况比较特殊,即+0-0//Ifx!==0,Thenreturntrue//Ifx===0,需要判断+0和-0,可以直接用1/+0===Infinity和1/-0===-Infinity来判断returnx!==0||1/x===1/y;}//对于x!==y的情况,只需要判断是否为NaN即可。如果x!==x,则表示x是NaN。同样,ySame//当x和y同时为NaN时,返回truereturnx!==x&&y!==y;};深/浅拷贝首先判断数据类型是否为对象,如果是对象(数组|对象),则递归(深/浅拷贝),否则直接拷贝。functionisObject(obj){returntypeofobj==="object"&&obj!==null;}这个函数只能判断obj是不是对象,不能判断是数组还是对象。哪些情况会导致内存泄漏以下四种情况会导致内存泄漏:意外的全局变量:由于使用了未声明的变量,意外创建了一个全局变量,这个变量一直留在内存中,无法回收。忘记定时器或回调函数:设置setInterval定时器忘记取消。如果循环函数引用了一个外部变量,那么这个变量就会一直留在内存中,不能被回收。ReferencesfromDOM:获取一个DOM元素的引用,后一个元素被删除。由于对该元素的引用已保留,因此无法回收。闭包:闭包的不合理使用,导致某些变量被保留在内存中。数组有哪些原生方法?数组和字符串转换方法:toString()、toLocalString()、join()其中join()方法可以指定转换为字符串时的分隔符。数组尾操作的方法有pop()和push(),push方法可以传入多个参数。用于数组头操作的方法shift()和unshift()以及用于重新排序的方法reverse()和sort()。sort()方法可以传入一个比较函数,传入前后两个值。如果返回值为正数,则交换两个参数的位置。数组连接的concat()方法返回连接后的数组而不影响原始数组。数组截取方法slice()用于在不影响原数组的情况下截取数组的一部分返回。数组插入方法splice()、影响原数组查找特定项索引的方法、indexOf()和lastIndexOf()迭代方法every()、some()、filter()、map()和forEach()方法数组合并方法reduce()和reduceRight()方法实现对象的flatten方法标题描述:constobj={a:{b:1,c:2,d:{e:5}},b:[1,3,{a:2,b:3}],c:3}flatten(obj)返回结果如下//{//'a.b':1,//'a.c':2,//'a.d.e':5,//'b[0]':1,//'b[1]':3,//'b[2].a':2,//'b[2].b':3//c:3//}实现代码如下:functionisObject(val){returntypeofval==="object"&&val!==null;}functionflatten(obj){if(!isObject(obj)){返回;}让res={};constdfs=(cur,prefix)=>{if(isObject(cur)){if(Array.isArray(cur)){cur.forEach((item,index)=>{dfs(item,`${prefix}[${index}]`);});}else{for(letkincur){dfs(cur[k],`${prefix}${prefix?".":""}${k}`);}}}else{res[prefix]=cur;}};dfs(obj,"&qu哦;);返回res;}flatten();代码输出函数a(xx){this.x=xx;returnthis};varx=a(5);vary=a(6);console.log(x.x)//undefinedconsole.log(y.x)//6输出结果:undefined6分析:最重要的是varx=a(5),函数a是在全局作用域调用的,所以函数内部的this指向window对象所以this.x=5等价于:window.x=5。然后返回this,即比方说,varx=a(5)中x变量的值是window,其中x会覆盖函数内部x的值。然后执行console.log(x.x),即console.log(window.x),window对象中没有x属性,所以会输出undefined。当指向y.x时,6被赋值给全局变量中的x,所以打印出6。IE兼容attchEvent('on'+type,handler)detachEvent('on'+type,handler)下面说说原型链和原型链的继承。所有普通的[[Prototype]]链最终都会指向内置的Object.prototype。它包含许多JavaScript中的常用函数。为什么可以创建一个具有特殊属性的“类”:所有的函数默认都会有一个通用的不可枚举的属性prototype,它会指向另一个对象,这个对象通常被称为函数的原型functionPerson(name){this.name=name;}Person.prototype.constructor=Person当一个新的构造函数调用发生时,创建的新对象的[[Prototype]]将链接到Person.prototype指向的对象,这种机制被称为原型链。继承方法定义在原型上,属性定义在构造函数上。首先说一下JS原型和实例的关系:每个构造函数(constructor)都有一个原型对象(prototype),这个原型对象包含一个指向这个构造函数的指针属性,通过new调用构造函数生成的实例,thisinstance包含一个指向原型对象的指针,也就是通过[[Prototype]]对象链接到这个prototype再说说JS中的属性查找:当我们试图引用一个实例对象的某个属性时,我们以这种方式搜索。首先,我们检查实例对象上是否存在该属性。如果没有找到,我们构造实例查找对象的构造函数原型所指向的对象。如果还是找不到,就从原型对象指向的构造函数的原型对象中查找什么是原型链:这个一步步查找好像是一个链,通过[[Prototype]]属性链接,所以称为原型链。什么是原型链的继承,类比类的继承:当有两个构造函数A和B时,构造函数A的原型对象会通过其[[Prototype]]属性链接到原型对象上对于另一个B构造函数,这个过程称为原型继承。标准答案更正确的解释了什么是原型链?当一个对象搜索一个属性时,如果在自身中没有找到,它就会搜索自己的原型。如果还没有找到原型,就会继续寻找原型的原型,直到找到Object.prototype的原型。此时原型为null,搜索停止。这种通过原型链接逐步向上搜索的链称为原型链。什么是原型继承?一个对象可以使用另一个对象的属性或方法,这称为继承。具体来说,通过将这个对象的原型设置为另一个对象,根据原型链的规则,如果你找一个对象的属性不存在,就会去寻找另一个对象,相当于一个对象可以使用另一个对象。属性和方法。说说常用的git操作gitbranch查看本地所有分支gitstatus查看当前状态gitcommitsubmitgitbranch-a查看所有分支gitbranch-r查看所有远程分支gitcommit-am"nit"提交并添加注释gitremoteaddorigingit@192.168.1.119:ndshowgitpushoriginmaster推送文件到服务器gitremoteshoworigin显示远程库origin中的资源gitpushoriginmaster:developgitpushoriginmaster:hb-dev对比本地库和服务器上的库关联gitcheckout--trackorigin/dev切换到远程dev分支gitbranch-Dmasterdevelop删除本地库developgitcheckout-bdev新建本地分支devgitmergeorigin/dev合并分支dev与当前分支gitcheckoutdev切换到本地dev分支gitremoteshow查看远程库gitadd.gitrm文件名(含路径)从git中删除指定文件gitclonegit://github.com/schacon/grit.git发送代码到服务器from服务器下拉gitconfig--list查看所有用户gitls-files查看提交的gitrm[filename]删除文件gitcommit-a提交当前仓库的所有更改gitadd[filename]添加afiletogitindexgitcommit-v使用-v参数时,可以看到commit的区别gitcommit-m"Thisisthemessagedescribingthecommit"添加提交信息gitcommit-a-a代表添加,添加所有改动gitindex然后commitgitcommit-a-v一般提交命令gitlog查看你的提交日志gitdiff查看没有暂存的更新gitrma.aremovefiles(从暂存区和工作区删除)gitrm--cacheda.aremovefiles(只从暂存区删除)gitcommit-m"remove"移除文件(从Git中删除)gitrm-fa.a强制移除修改过的文件(从暂存区和工作区中删除)gitdiff--cached或$gitdiff--staged查看尚未更新的更新提交gitstashpush将文件推送到临时空间gitstashpop从临时空间弹出文件代码输出结果functionrunAsync(x){constp=newPromise(r=>setTimeout(()=>r(x,console.log(x)),1000))returnp}functionrunReject(x){constp=newPromise((res,rej)=>setTimeout(()=>rej(`Error:${x}`,console.log(x)),1000*x))returnp}Promise.all([runAsync(1),runReject(4),runAsync(3),runReject(2)]).then(res=>console.log(res)).catch(err=>console.log(err))输出结果如下s://output13after1s//output2after2sError:2//output4after4s看catch第一个错误被捕获了,本题第一个错误就是runReject(2)的结果。如果一组异步操作出现异常,则不会进入.then()的第一个回调函数参数。将被.then()的第二个回调函数捕获。如何判断一个对象是否为空对象?Object.keys(obj).length===0手写题:在线编程,getUrlParams(url,key);是一个很简单的获取url某个参数的问题,但是必须考虑边界条件,多个返回值等代码输出functionfoo(){console.log(this.a);}functiondoFoo(){foo();}varobj={a:1,doFoo:doFoo};vara=2;obj.doFoo()output:2在Javascript中,this指向函数执行时的当前对象。foo执行时,执行环境是doFoo函数,执行环境是全局的。因此,foo中的this指向window,因此将打印2。async/await的理解async/await其实就是Generator的语法糖,它能达到的效果可以用then链来实现,就是为了优化then链而开发的。从字面上看,async是“异步”的简写,await就是等待,所以很好理解,async用来声明一个函数是异步的,await用来等待一个异步方法完成。当然语法上规定await只能出现在asnyc函数中。首先,让我们看一下异步函数返回的内容:asyncfunctiontestAsy(){return'helloworld';}letresult=testAsy();console.log(result)所以,异步函数返回的是一个Promise对象。异步函数(包括函数语句、函数表达式和Lambda表达式)将返回一个Promise对象。如果函数中返回的是直接量,async会通过Promise.resolve()将直接量封装成一个Promise对象。async函数返回的是一个Promise对象,所以如果最外层不能使用await获取它的返回值,当然要用原来的方法:then()链来处理这个Promise对象,像这样:asyncfunctiontestAsy(){return'helloworld'}letresult=testAsy()console.log(result)result.then(v=>{console.log(v)//helloworld})如果异步函数没有返回值,应该怎么办如何?很容易想象它会返回Promise.resolve(undefined)。想一想Promise的特点——没有等待,所以如果你执行一个async函数没有await,它会立即执行,返回一个Promise对象,永??远不会阻塞后面的语句。这与返回Promise对象的普通函数没有什么不同。注意:Promise.resolve(x)可以看成是newPromise(resolve=>resolve(x))的简写,可以用来快速将文字对象或者其他对象封装成Promise实例。浏览器缓存机制的理解浏览器缓存的全过程:浏览器第一次加载资源,服务器返回200,浏览器从服务器下载资源文件,缓存资源文件和响应头,用于下次比较加载使用;下次加载资源时,由于强制缓存优先级高,先比较当前时间和上次返回200的时间差,如果没有超过cache-control设置的max-age,则不会过期并命中强缓存。直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用expires头判断是否过期;如果资源已过期,则表示未命中强制缓存,然后开始协商缓存,并发送带有If-None-Match和If-Modified-Since请求的消息;服务端收到请求后,首先根据Etag值判断请求的文件是否被修改过。如果Etag值一致,没有修改,命中协商缓存,返回304;如果不一致,则有变化,直接返回新的资源,给文件带上新的Etag值,返回200;如果服务器收到的请求没有Etag值,则将If-Modified-Since与请求文件的最后修改时间进行比较,如果匹配则命中协商缓存并返回304;不一致则返回新的last-modified和文件并返回200;许多网站资源后跟版本号。这样做的目的是:每次升级JS或CSS文件后,为了防止浏览器缓存,强制改版本号,客户端浏览器会重新下载新的JS或CSS文件,从而达到确保用户能够及时获得网站的最新更新。让我们谈谈HTML页面中的WebWorker。如果脚本执行时页面的状态为非响应状态,则在脚本执行完成之前,页面不会变为响应状态。webworker是后台运行的js,独立于其他脚本,不会影响页面的性能。并通过postMessage将结果传回主线程。这样,在执行复杂操作时,不会阻塞主线程。webworker的创建方法:检测浏览器对webworker的支持情况创建webworker文件(js、返回函数等)创建webworker对象CDN的原理CDN和DNS密不可分,下面看一下域名解析DNS的过程,浏览器输入的解析过程如下:(1)检查浏览器缓存(2)检查操作系统缓存,如常用的hosts文件(3)检查路由器缓存(4)如果前面的步骤没有找到,会查询ISP(InternetServiceProvider)的LDNS服务器(5)如果没有找到LDNS服务器,会请求根域名服务器(RootServer)解析,分分为以下步骤:根服务器返回顶级域名(TLD)服务器,例如.com、.cn、.org等的地址。本例中会返回.com的地址然后请求发送给顶级域名服务器,然后是二级域名的地址(SLD)服务器将被返回。本例中会返回.test的地址,然后向二级域名服务器发送请求,然后返回通过域名查询到的目标IP。在此示例中,将返回www.test.com的地址。LocalDNSServer会将结果缓存起来返回给用户。CDN在缓存系统中的工作原理:(1)用户不使用CDN缓存资源的过程:浏览器通过DNS解析域名(即上面的DNS解析过程),得到IP地址依次对应域名。浏览器根据获取到的IP地址向域名提供服务主机发送数据请求服务器返回响应数据给浏览器(2)用户使用CDN缓存资源的过程:对于被点击的URL数据,经过本地DNS系统解析,发现该URL对应一个CDN专用的DNS服务器,DNS系统会将域名解析权交给CNAME指向的CDN专用的DNS服务器。CND的专用DNS服务器将CND的全局负载均衡设备的IP地址返回给用户。用户向CDN的全局负载均衡设备发起数据请求。CDN的全局负载均衡器根据用户的IP地址和用户请求的内容URL选择用户。所属区域的区域负载均衡设备告诉用户向该设备发起请求。区域负载均衡设备选择合适的缓存服务器提供服务,并将缓存服务器的IP地址返回给全局负载均衡设备。全局负载均衡设备向服务器发送用户的IP地址返回给用户。用户向缓存服务器发起请求,缓存服务器响应用户的请求,将用户需要的内容发送给用户终端。如果缓存服务器没有用户想要的内容,缓存服务器会向上级缓存服务器请求内容,以此类推,直到获取到需要的资源。最后还是没有,就回到自己的服务器去获取资源。CNAME(意思:别名):在域名解析中,实际解析的是指定域名对应的IP地址,或者该域名的一个CNAME,然后根据这个CNAME查找对应的IP地址。