面试题之javascript
这篇面试题,主要来源于网上,当作自己日常学习提高用途
1.「2021」高频前端面试题汇总之JavaScript篇(上) 这个文章总结的很多了,可以时常的看一看,我这里仅仅是摘录了一些,比如:原型和原型链;执行上下文、作用域、必包等等,分门别类,都总结的非常的好
2.Web 中高级前端面试题集合(200+)
3.「2021」高频前端面试题汇总之JavaScript篇(上) 这在掘金上的,感觉央视还是挺好看的。
1.for…in和for…of的区别
for…of 是ES6新增的遍历方式,允许遍历一个含有iterator接口的数据结构(数组、对象等)并且返回各项的值,和ES3中的for…in的区别如下
for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链;
对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;
总结: for…in 循环主要是为了遍历对象而生,不适用于遍历数组;for…of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。
2.ajax、axios、fetch的区别
(1)AJAX
Ajax 即“AsynchronousJavascriptAndXML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。它是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。其缺点如下:
- 本身是针对MVC编程,不符合前端MVVM的浪潮
- 基于原生XHR开发,XHR本身的架构不清晰
- 不符合关注分离(Separation of Concerns)的原则
- 配置和调用方式非常混乱,而且基于事件的异步模型不友好。
(2)Fetch
fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多。fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。
fetch的优点:
- 语法简洁,更加语义化
- 基于标准 Promise 实现,支持 async/await
- 更加底层,提供的API丰富(request, response)
- 脱离了XHR,是ES规范里新的实现方式
fetch的缺点:
- fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
- fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: ‘include’})
- fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
- fetch没有办法原生监测请求的进度,而XHR可以
(3)Axios
Axios 是一种基于Promise封装的HTTP客户端,其特点如下:
- 浏览器端发起XMLHttpRequests请求
- node端发起http请求
- 支持Promise API
- 监听请求和返回
- 对请求和返回进行转化
- 取消请求
- 自动转换json数据
- 客户端支持抵御XSRF攻击
3.什么是尾调用,使用尾调用有什么好处?
尾调用指的是函数的最后一步调用另一个函数。代码执行是基于执行栈的,所以当在一个函数里调用另一个函数时,会保留当前的执行上下文,然后再新建另外一个执行上下文加入栈中。使用尾调用的话,因为已经是函数的最后一步,所以这时可以不必再保留当前的执行上下文,从而节省了内存,这就是尾调用优化。但是 ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。
4.常见的DOM操作有哪些?
DOM 节点的获取,
1
2// 按照 css 选择器查询
var pList = document.querySelectorAll('.mooc')DOM 节点的创建
DOM 节点的删除
修改 DOM 元素
5.forEach和map方法有什么区别?
这方法都是用来遍历数组的,两者区别如下:
- forEach()方法会针对每一个元素执行提供的函数,对数据的操作会改变原数组,该方法没有返回值;
- map()方法不会改变原数组的值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值;
6.哪些情况会导致内存泄漏?
以下四种情况会造成内存的泄漏:
- 意外的全局变量: 由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
- 被遗忘的计时器或回调函数: 设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
- 脱离 DOM 的引用: 获取一个 DOM 元素的引用,而后面这个元素被删除,由于一直保留了对这个元素的引用,所以它也无法被回收。
- 闭包: 不合理的使用闭包,从而导致某些变量一直被留在内存当中。
7.!! 运算符能做什么?
!!运算符可以将右侧的值强制转换为布尔值,这也是将值转换为布尔值的一种简单方法。
1 | console.log(!!null); // false |
8.简述前端性能优化
- 页面内容方面
1.通过文件合并、css 雪碧图、使用 base64 等方式来减少 HTTP 请求数,避免过多的请求造成等待的情况;
2.通过 DNS 缓存等机制来减少 DNS 的查询次数;
3.通过设置缓存策略,对常用不变的资源进行缓存;
4.通过延迟加载的方式,来减少页面首屏加载时需要请求的资源,延迟加载的资源当用户需要访问时,再去请求加载;
5.通过用户行为,对某些资源使用预加载的方式,来提高用户需要访问资源时的响应速度;
- 服务器方面
1.使用 CDN 服务,来提高用户对于资源请求时的响应速度;
2.服务器端自用 Gzip、Deflate 等方式对于传输的资源进行压缩,减少传输文件的体积;
3.尽可能减小 cookie 的大小,并且通过将静态资源分配到其他域名下,来避免对静态资源请求时携带不必要的 cookie;
9.webpack 中 loader 和 plugin 的区别是什么?
loader:loader 是一个转换器,将 A 文件进行编译成 B 文件,属于单纯的文件转换过程;
plugin:plugin 是一个扩展器,它丰富了 webpack 本身,针对是 loader 结束后,webpack 打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听 webpack 打包过程中的某些节点,执行广泛的任务。
10.如何实现函数的柯里化?
1.什么是函数柯里化?
把接收多个参数的函数变换为接收一个单一参数(最初函数的第一个参数)的函数,并返回接收剩余参数而且返回结果的新函数的技术。JS 函数柯里化的优点:
- 可以延迟计算,即如果调用柯里化函数传入参数是不调用的,会将参数添加到数组中存储,等到没有参数传入的时候进行调用;
- 参数复用,当在多次调用同一个函数,并且传递的参数绝大多数是相同的,那么该函数可能是一个很好的柯里化候选;
2.怎么实现?
1 | function curringAdd() { |
11.webpack 中 loader 和 plugin 的区别是什么?
loader
loader 是一个转换器,将 A 文件进行编译成 B 文件,属于单纯的文件转换过程;plugin
plugin 是一个扩展器,它丰富了 webpack 本身,针对是 loader 结束后,webpack 打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听 webpack 打包过程中的某些节点,执行广泛的任务。
12.什么是防抖和节流?有什么区别?如何实现?
网友总结的口诀: DTTV(Debounce Timer Throttle Variable - 防抖靠定时器控制,节流靠变量控制)。
- 防抖
触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间。
1 | function debounce(fn, timing) { |
- 节流
1 | function throttle(fn, timing) { |
13.函数内部 arguments 变量有哪些特性,有哪些属性,如何将它转换为数组
- arguments 所有函数中都包含的一个局部变量,是一个类数组对象,对应函数调用时的实参。如果函数定义同名参数会在调用时覆盖默认对象
- arguments[index]分别对应函数调用时的实参,并且通过 arguments 修改实参时会同时修改实参
- arguments.length 为实参的个数(Function.length 表示形参长度)
- arguments.callee 为当前正在执行的函数本身,使用这个属性进行递归调用时需注意 this 的变化
- arguments.caller 为调用当前函数的函数(已被遗弃)
- 转换为数组:var args = Array.prototype.slice.call(arguments, 0);
14.this、apply、call、bind?
1.this 永远指向最后调用它的那个对象。
2.怎么改变 this 的指向:
使用 ES6 的箭头函数;在函数内部使用 _this = this;使用 apply、call、bind;new 实例化一个对象。
3.箭头函数的 this 始终指向函数定义时的 this,而非执行时。
4.bind() 方法会创建一个新函数,当这个新函数被调用时,它的 this 值是传递给 bind() 的第一个参数, 它的参数是 bind() 的其他参数和其原本的参数。
1.this、apply、call、bind?
15.es5和es6的区别,说一下你所知道的es6?
ECMAScript5,即ES5,是ECMAScript的第五次修订,于2009年完成标准化ECMAScript6,即ES6,是ECMAScript的第六次修订,于2015年完成,也称ES2015ES6是继ES5之后的一次改进,相对于ES5更加简洁,提高了开发效率ES6新增的一些特性:
(1) let声明变量和const声明常量,两个都有块级作用域ES5中是没有块级作用域的,并且var有变量提升,在let中,使用的变量一定要进行声明
(2) 箭头函数ES6中的函数定义不再使用关键字function(),而是利用了()=>来进行定义
(3) 模板字符串模板字符串是增强版的字符串,用反引号(`)标识,可以当作普通字符串使用,也可以用来定义多行字符串
(4) 解构赋值ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值
(5) for of循环for…of循环可以遍历数组、Set和Map结构、某些类似数组的对象、对象,以及字符串
(6) import、export导入导出ES6标准中,Js原生支持模块(module)。将JS代码分割成不同功能的小块进行模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用
(7) set数据结构:Set数据结构,类似数组。所有的数据都是唯一的,没有重复的值。它本身是一个构造函数
(8) … 展开运算符可以将数组或对象里面的值展开;还可以将多个值收集为一个变量
(9) 修饰器 @decorator是一个函数,用来修改类甚至于是方法的行为。修饰器本质就是编译时执行的函数
(10) class 类的继承:ES6中不再像ES5一样使用原型链实现继承,而是引入Class这个概念
(11) async、await使用 async/await, 搭配promise,可以通过编写形似同步的代码来处理异步流程, 提高代码的简洁性和可读性async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成
(12) promise:Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理、强大
(13) Symbol:Symbol是一种基本类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的
(14) Proxy代理使用代理(Proxy)监听对象的操作,然后可以做一些相应事情
1.es5和es6的区别,说一下你所知道的es6?
8.setTimeout、Promise、Async/Await 的区别?
事件循环中分为宏任务队列和微任务队列其中setTimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行async函数表示函数里面可能会有异步方法,await后面跟一个表达式async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行。
9.isNaN 和 Number.isNaN 函数的区别?
- 函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。
- 函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。
1.高频前端面试题汇总之JavaScript篇(上) 自查自纠倒是挺好的。
10.为什么0.1+0.2 ! == 0.3,如何让其相等
这个主要的原因就是浮点数存储的精度问题。一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。
1.为什么0.1+0.2 ! == 0.3,如何让其相等? 这里对于上面的这个问题回答的很详细,可以参考。
11.== 操作符的强制类型转换规则
对于 == 来说,如果对比双方的类型不一样,就会进行类型转换。假如对比 x 和 y 是否相同,就会进行如下判断流程:
1.首先会判断两者类型是否相同,相同的话就比较两者的大小;
2.类型不相同的话,就会进行类型转换;
3.会先判断是否在对比 null 和 undefined,是的话就会返回 true
4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断
1.== 操作符的强制类型转换规则?
12.var
,let
和const
的区别是什么?
1.var声明的变量会挂载在window上,而let和const声明的变量不会。
2.var声明变量存在变量提升,let和const不存在变量提升。
3.let和const声明形成块作用域。
4.同一作用域下let和const不能声明同名变量,而var可以。
5.let/const有暂存死区特性。
6.const: 一旦声明必须赋值,不能使用null占位;声明后不能再修改;如果声明的是复合类型数据,可以修改其属性
1.
var
,let
和const
的区别是什么?13.什么是事件冒泡?什么是事件捕获?
1.冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
2.捕获型事件:事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。
3.支持W3C标准的浏览器在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。
1.2019前端面试题 | JS部分(附带答案)