JavaScript面试题(套题)
选择题 | 填空题 | 问答题 | 编程题 | 试题难度 |
---|---|---|---|---|
0 | 0 | 37 | 1 | 比较难 |
问答题
1、简述同步与异步的区别
同步是阻塞模式,异步是非阻塞模式。
同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
2、什么是跨域请求?怎样解决?
- 跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
- 所谓同源是指,域名,协议,端口均相同,浏览器执行js脚本的时候,会检查这个脚本属于哪一个页面,如果不是同源页面,就不会执行。
- 解决方法
- jsonp(jsonp 的原理是动态插入 script 标签)
- document.domain + iframe
- window.name、window.postMessage
- 服务器上设置代理页面
3、怎样添加、删除、移动、复制、创建和查找节点?(考原生)
在添加节点之前,通过createElement创建一个节点对象,然后通过父节点对象,调用appendChild()、insertBefore()来添加节点。当然也可以通过innerHTML属性添加也是可以的。
使用removeChild()删除节点
查看节点的方式有
- childNodes 返回包括文本节点和元素节点,不常用
- children 返回元素的子节点;
- parentNode 返回指定节点的父节点,如果没有父节点则返回null;
- firstChild 返回指定节点的首个子节点,IE兼容;firstElementChild 返回指定节点的首个子节点,非IE兼容;
- firstChild 返回指定节点的首个子节点,IE兼容;firstElementChild 返回指定节点的首个子节点,非IE兼容;
- nextSibling 返回指定节点的下一个兄弟节点,IE兼容;nextElementSibling 返回指定节点的下一个兄弟节点,非IE兼容;如果没有下一个兄弟节点则返回null;
- previousSibling 返回指定节点的上一个兄弟节点,IE兼容;previousElementSibling 返回指定节点的上一个兄弟节点,非IE兼容;如果没有上一个兄弟节点则返回null;
4、事件是什么?如何阻止事件冒泡?
- 事件:用于监听浏览器的操作行为,浏览器触发动作时被捕捉到而调用相应的函数。事件执行三个阶段
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
- 捕获型事件是自上而下,而冒泡型事件是自下而上的,而我们程序员通常要做的就是第二阶段,完成事件的动作。而第一、三阶段由系统封装自动调用完成。
- 阻止冒泡
event.stopPropagation()
IE浏览器 event.cancelBubble = true;
5、手写Ajax
var xhr = new XMLHttpRequest(); xhr.open("GET","api",false); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ alert(xhr.responseText); } } } xhr..send(null);
6、闭包的理解 / 你是怎么理解闭包的?以及它的优缺点是啥?
这个我在项目的防抖节流的函数有用到过,我的理解是函数套函数,建立一个私有的作用域空间,避免被其它的方法干扰。变量定义在外层函数里,内部函数使用外部函数的变量,然后return内部函数的引用,这样就构成了闭包。
它的缺点是会消耗更多的内存,导致垃圾回收机制回收不到这些变量而造成内存泄漏。解决办法就是手动对我们不要的变量或对象设置为null。
8、JSON 格式是什么?你了解吗?
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小{"age":"12", "name":"back"}
9、原型链的理解 / 什么是原型链?
原型链是JavaScrip实现对象继承的一种方式,对象是通过new 构造函数创建的,构造函数对象有一个原型对象prototype,用来设置构造类型的公共属性和方法。对象在查找属性时,会在对象本身查找,如果找不到,就会去原型链对象proto找,其实就是去构造函数原型对象上找,如果找不到会继续通过原型对象的proto向上查找,如果都找不到就会抛出错误,这种通过原型不断向上查找的链条,称之为原型链。
10、谈谈你对this的理解?
this是js的一个关键字,随着函数使用场合不同,this的值会发生变化。 但是有一个总原则,那就是this指的是调用函数的那个对象。 this一般情况下:是全局对象Global。 作为方法调用,那么this就是指这个对象
11、call() 和 apply() 的区别?
- 相同点:两个方法产生的作用是完全一样的,动态改变某个类的某个方法的运行环境。
- 不同点:调用的参数不同,比较精辟的总结:
foo.call(this,arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)
14、new操作符具体干了什么呢?
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
- 属性和方法被加入到 this 引用的对象中。
- 新创建的对象由 this 所引用,并且最后隐式的返回 this。
- var obj = {};
- obj.proto = Base.prototype;
- Base.call(obj);
15、请描述一下 cookies,sessionStorage 和 localStorage 的区别?
在较高版本的浏览器中,js提供了sessionStorage和globalStorage。在HTML5中提供了localStorage来取代globalStorage。
html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage。
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。
但是Cookie也是不可以或缺的:Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生
浏览器的支持除了IE7及以下不支持外,其他标准浏览器都完全支持(ie及FF需在web服务器里运行),值得一提的是IE总是办好事,例如IE7、IE6中的UserData其实就是javascript本地存储的解决方案。通过简单的代码封装可以统一到所有的浏览器都支持web storage。
localStorage和sessionStorage都具有相同的操作方法,例如setItem、getItem和removeItem等
16、说说cookie的弊端和优点
cookie虽然在持久保存客户端数据提供了方便,分担了服务器存储的负担,但还是有很多局限性的。 第一:每个特定的域名下最多生成20个cookie
1.IE6或更低版本最多20个cookie 2.IE7和之后的版本最后可以有50个cookie。 3.Firefox最多50个cookie 4.chrome和Safari没有做硬性限制 IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie。
cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节。
IE 提供了一种存储可以持久化用户数据,叫做uerData,从IE5.0就开始支持。每个数据最多128K,每个域名下最多1M。这个持久化数据放在缓存中,如果缓存没有清理,那么会一直存在。
优点:极高的扩展性和可用性
1.通过良好的编程,控制保存在cookie中的session对象的大小。 2.通过加密和安全传输技术(SSL),减少cookie被破解的可能性。 3.只在cookie中存放不敏感数据,即使被盗也不会有重大损失。 4.控制cookie的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的cookie。
缺点: 1.
Cookie
数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。2.安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。
3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。
17、常见WEB安全及防护原理(当拓展知识用)
- SQL注入
- 原理:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
- 防护:总的来说有如下。
1.永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。
2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。
- XSS攻击
- 原理:Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意 html标签或者javascript代码。比如:攻击者在论坛中放一个看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息;或者攻击者在论坛中加一个恶意表单,当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点。
- 防范:
1.首先代码里对用户输入的地方和变量都需要仔细检查长度和对”<”,”>”,”;”,”’”等字符做过滤; 2.其次任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。这一个层面做好,至少可以堵住超过一半的XSS 攻击。
3.首先,避免直接在cookie 中泄露用户隐私,例如email、密码等等。 其次,通过使cookie 和系统ip 绑定来降低cookie 泄露后的危险。这样攻击者得到的cookie 没有实际价值,不可能拿来重放。
4.如果网站不需要再浏览器端对cookie 进行操作,可以在Set-Cookie 末尾加上HttpOnly 来防止javascript 代码直接获取cookie。
5.尽量采用POST 而非GET 提交表单
- CSRF的防御
- 服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。
- 通过验证码的方法
18、说几条JavaScript的基本规范?
1.不要在同一行声明多个变量。
2.请使用 ===/!==来比较true/false或者数值
3.使用对象字面量替代new Array这种形式
4.不要使用全局函数。
5.Switch语句必须带有default分支
6.函数不应该有时候有返回值,有时候没有返回值。
7.For循环必须使用大括号
8.If语句必须使用大括号
9.for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。
19、编程实现函数柯里化
函数式编程curry的概念: 只传递给函数一部分参数来调用函数,然后返回一个函数去处理剩下的参数。
简单的例子如:
function add(num1,num2){ return num1+num2; } function curriedAdd(num2){ return add(5,num2); } alert(add(2,3)); //5 alert(curriedAdd(3)); //8
21、用JavaScript脚本为Array对象添加一个去除重复项的方法。(数组去重)
- 用JavaScript脚本为Array对象添加一个去除重复项的方法。(数组去重)
- 使用for循环结合对象一起使用
22、应用程序存储和离线web应用
HTML5新增应用程序缓存,允许web应用将应用程序自身保存到用户浏览器中,用户离线状态也能访问。 1.为html元素设置manifest属性:
<html manifest="myapp.appcache">
,其中后缀名只是一个约定,真正识别方式是通过text/cache-manifest
作为MIME类型。所以需要配置服务器保证设置正确 2.manifest文件首行为CACHE MANIFEST
,其余就是要缓存的URL列表,每个一行,相对路径都相对于manifest文件的url。注释以#开头 3.url分为三种类型:CACHE
:为默认类型。NETWORK
:表示资源从不缓存。FALLBACK
:每行包含两个url,第二个URL是指需要加载和存储在缓存中的资源, 第一个URL是一个前缀。任何匹配该前缀的URL都不会缓存,如果从网络中载入这样的URL失败的话,就会用第二个URL指定的缓存资源来替代。以下是一个文件例子:CACHE MANIFEST CACHE: myapp.html myapp.css myapp.js FALLBACK: videos/ offline_help.html NETWORK: cgi/
23、递归
递归算法在项目开发中有用到过,我在做商城后台管理系统时,由于SKU数据层级不确定,采用递归的方式清洗数据,只取商品的分类数据,剔除商品的属性节点数据。递归主要的特点就是调用自身。
24、浮点数精度丢失
-
这个和数据存储的方式有关系,浮点数是以双精度64位存储的,这64位由三部分组成,第1位是符号位,中间11位是指数位,最后52位为尾数位,浮点数在计算时都会转成二进制 ,问题是浮点数以二进制表示是无穷的,按 0舍1入保留52位,这样就造成了精度丢失。
解决这个问题可以采用扩大倍数法,目的是将小数变成整数后做运算。有多少位小数就扩大到10的n次方,然后在将结果除以10的n次方。不过我们公司的项目统一采用lodash工具库的数学函数实现的。
25、描述一下promise / promise的原理 / promise和acync await的区别?
在项目开发中有使用过Promise,Axios就是基于Promise的。
Promise是ES6提供的一种异步编程方案,可以解决回调地狱。使用new Promise创建对象,在Promise构造函数传一个处理函数,有两个参数,为resolve 和 reject 两个函数。
resolve函数用于返回成功的结果,reject返回失败的结果。成功的结果使用then来处理,错误的结果使用catch来处理。
Promise还可以链式调用,这样就可以用同步的编程方式处理异步的结果。
在ES7新增了acync await两个关键词,异步强行转为同步处理。需要将异步的结果作为一个函数的结果返回就必须使用async和await。我在做令牌无痛刷新就是通过这个方式解决。
26、防抖节流的区别。怎么实现的 / 说一下防抖和节流,以及他们应用的场景 / 怎么做防抖节流
防抖和节流在我们的项目中都是有使用的,为了防止用户频繁的点击按钮操作,我们做了防抖,在回到顶部的滑动效果我们做了节流处理。
防抖是指在事件触发n秒数后在执行回调,这个n就是指定的秒数,如果n秒内有触发就会重新计时。在实现中需要运用到闭包。代码具体实现步骤是:在一个函数里定一个定时器变量,然后return一个函数,在内部函数做判断,如果计时器存在就清楚计时器,否则在指定的时间执行计时器调用需要操作的函数并且将计时器设置为null
节流是指如果持续触发某个事件,则每隔n秒执行一次,实现的过程和防抖差不多,只是在判断处理有一点差异,如果计时器对象存在就return;
方便大家理解贴一下代码
27、微任务和宏任务你怎么理解 / 宏服务和微服务有什么区别
宏任务和微任务对理解代码执行的顺序是非常有帮助的,特别是在有Promise,setTimeout,asyc await等这些异步处理的代码情况
我的理解是这样的,JavaScript是单线程,一次只能处理一件事情,JavaScript有同步代码和异步代码,会先执行同步代码,再来执行异步代码,而异步代码具有不确定性,如果有多个异步代码,就需要按照一种规则去执行。
这个规则里就引出了宏任务和微任务的两个概念,在异步处理中有setTimeout,setInterval,Promise,aysnc await 。那么对这些做分类setTimeout,setInterval归为宏任务,Promise,async await(是Promise的语法糖)归为微任务。执行的顺序是这样:
如果有宏任务就先执行宏任务,执行结束后,在看看有没有可执行的微任务,如果没有就开始新的宏任务,如果有就执行完所有的微任务,而后开始新的宏任务;会不断的这样循环起来,称之为事件循环。
方便理解,贴流程图
28、说说对WebSocket的理解?应用场景?/ 及时通讯WebSocket有了解过吗
WebSock是有用过的,用于及时通讯,因为WebSock是双攻通信的方式,与服务器握手一次就建立了一个长连接,客户端可以发信息到服务器,服务器也可以发信息到客户端。这样通讯就更及时。
使用步骤也很简单
第一步:new WebSocket("服务器地址") 与服务器建立连接,协议是ws
第二步:注册三个事件
onopen表示与服务器连接成功的回调函数
onmessage 收到服务器数据后的回调函数
onclose 连接关闭后的回调函数
第三步:send() 函数向服务器发送数据
29、前端储存的⽅式有哪些?
比较常用的有localStorage、sessionStorage、cookie,存储的都是字符类型的数据
localStorage是永久存储,需要手动删除,存储大小在5M左右,SessionStorage是临时存储,浏览器关闭就消除。
cookie存储大小4KB左右,一个域名只能存储20个左右,可以设置过期时间,到期后自动清除,cookie的数据是要往返与客户端和服务器端。
30、说一下常见的检测数据类型的几种方式?
我在项目中常用的是对象的constructor.name的方式,这样是非常准确的得知对象的数据类型名称的。
判断数组可以使用Array.isArray。也可以使用typeof和instanceof但这些判断都有一些缺陷。
31、js的基本数据类型和引用数据类型,它们之间的区别
基本数据类型分为String、Number、Boolean、Undefined、Null、symbol
引用数据类型又分为Object、Function、Array、Date、RegExp等
区别在于基本数据类型的值都是保存在栈内存当中的,值与值之间是相互独立的,而引用数据类型的值是保存到堆内存当中。
在赋值的时,值类型拷贝的是一个副本,彼此独立;引用类型拷贝的是内存地址,引用的是同一个对象。
32、数组方法有哪些?/ 数组变异和非变异方法有哪些?
数组分变异方法和非变异方法,变异方法是指会改变原数组,而非变异方法不会改变原数组,返回一个新数组。
数组变异方法有:
push() //数组尾部追加一个元素
pop() //数组尾部弹出一个元素
shift() //数组头部弹出一个元素
unshift() //数组头部插入一个元素
splice() //删除或替换某一个元素
sort() //按照特定的规则排序(数字根据从小到大排序,字符串根据unicode位点排序)
reverse() //反转数组
数组非变异方法:
filter() //过滤数组中某些元素,返回符合条件的元素组成的新数组
concat() //合并两个或两个以上的数组,可以链式调用,返回合并后的数组
slice() //切割数组中某一段元素,返回一个切割出来的数组
map() //使用map方法会产生一个新的数组,数组的每一项就是我们return出去的值(所以map方法必须有返回值,如果没有return,那么新数组的每一项都为undefined),数组的个数与原数组一样
some() //会遍历数组中的每个元素,让每个值都执行一遍callback函数,如果有一个元素满足条件,返回true , 剩余的元素不会再执行检测。如果没有满足条件的元素,则返回false。
forEach() //遍历数组
every() //检测数组所有元素是否满足条件
33、谈一谈你对于面向对象的理解
我认为JavaScript一切都是对象,每个对象都有自己的属性和方法,属性是描述对象的特征,方法是描述对象的行为。通过new 构造器来创建一个对象的实例,每个对象都是相互独立,JavaScript允许通过原型对象prototype设置共享的属性和方法。通过原型链实现对象的继承。这个就是我对对象的理解。
34、import和require的区别?
在项目开发中使用import来导入自定义组件和样式,使用require引入打包工具需要的模块。
require 是
CommonJS
的标准使用于Node.js 。 import是es6标准适用于浏览器的模块化开发。
35、call() 和 apply() bind()的区别?
相同点:都是调用一个对象的一个方法,用另一个对象替换当前对象
不同点:
- call,apply可以立即执;bind不会立即执行,因为bind返回的是一个函数,执行需要加括号()。
- 参数不同,apply第二个参数是数组,call和bind有多个参数需要用逗号分开挨个写。
36、JS中阻止冒泡事件的三种方法?
event.canceBubble() 只支持 IE,
return false:阻止了事件冒泡,也阻止了默认行为
stopPropagation() 阻止了事件冒泡,除了IE浏览器都支持
编程题
1、js对象的深度克隆代码实现
function clone(Obj) { var buf; if (Obj instanceof Array) { buf = []; // 创建一个空的数组 var i = Obj.length; while (i--) { buf[i] = clone(Obj[i]); } return buf; } else if (Obj instanceof Object){ buf = {}; // 创建一个空对象 for (var k in Obj) { // 为这个对象添加新的属性 buf[k] = clone(Obj[k]); } return buf; }else{ return Obj; } }