js加es6面试题整理

闭包

定义:

一个函数的作用域可以访问另一个函数的局部变量,这个变量所在的函数就是闭包函数

闭包使得内部函数可以访问外部函数的属性(变量或方法)

在 JavaScript 中, 每当创建一个函数, 闭包就会在函数创建的同时被创建出来

闭包本身就是 javascript 的重要知识点

闭包的作用:

1、读取函数内部的变量;2、让这些变量始终保持在内存之中。

优点:

  1. 不会造成全局变量的污染;

  2. 可以在函数的外部访问到函数内部的局部变量(实现所谓的变量‘公有化’)。

  3. 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。

缺点:

  1. 闭包导致作用域链的不释放,会造成内存溢出,所以就会占用内存空间(内存泄漏)

二、闭包的使用场景

1.setTimeout

原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。

 function f1(a) {
    function f2() {
        console.log(a);
    }
     return f2;
 }
 var fun = f1(1);
 setTimeout(fun,1000);

2.回调

定义行为,然后把它关联到某个用户事件上(点击或者按键)。代码通常会作为一个回调(事件触发时调用的函数)绑定到事件。

3.函数防抖

在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

实现的关键就在于setTimeOut这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。

4.封装私有变量

如下面代码:用js创建一个计数器

...(展开运算符) 的使用场景有哪些

1.数组的解构赋值

2 .对象的解构赋值

3.数组的合并

4.对象的拼接

5.Vuex中辅助性函数的映射

说一说JS数据类型有哪些,区别是什么?、

原始数据类型:number、string、boolean、undefined、null、symbol、bigint 引用数据类型:object(包括Array,Function、Object类等) 区别:前七中原生数据类型的存放在栈中,引用数据类型存放在堆中,它的地址在栈中,一般我们访问就是它的地址

箭头函数

特点:

  1. 相比普通函数,箭头函数有更加简洁的语法。

  2. 箭头函数不绑定this,会捕获其所在上下文的this,作为自己的this。

    这句话需要注意的是,箭头函数的外层如果有普通函数,那么箭头函数的this就是这个外层的普通函数的this,箭头函数的外层如果没有普通函数,那么箭头函数的this就是[全局变量]

    js加es6面试题整理_第1张图片

     

  3. 箭头函数是匿名函数,不能作为构造函数,不可以使用new命令,否则后抛出错误。

  4. 箭头函数不绑定arguments,取而代之用rest参数解决,同时没有super和new.target。

  5. 使用call,apply,bind并不会改变箭头函数中的this指向。

当对箭头函数使用call或apply方法时,只会传入参数并调用函数,并不会改变箭头函数中this的指向。 ​ 当对箭头函数使用bind方法时,只会返回一个预设参数的新函数,并不会改变这个新函数的this指向。

  1. 箭头函数没有原型对象prototype这个属性

由于不可以通过new关键字调用,所以没有构建原型的需求,所以箭头函数没有prototype这个属性。

7.不能使用yield关键字,不能用作Generator函数

async await的实现原理

1.当调用一个 async 函数时,会返回一个 Promise 对象 (关键)

2.async 函数中可能会有 await 表达式,await表达式 会使 async 函数暂停执行,直到表达式中的Promise解析完成后继续执行 async 中 await 后面的代码并返回解决结果。 3.既然返回的是Promise 对象,所以在最外层不能直接获取其返回值,那么肯定可以用原来的方式:then() 链来处理这个 Promise 对象 原理: 1.async/await 函数其实就是一种语法糖 2.async/await 是基于promise实现的,async 函数其实就是把 promise 做了一个包装 3.await 返回值是一个 Promise 对象,它只是把 await 后面的代码放到了 Promise.then()

使用场景:

async和await主要用来处理异步的操作,执行第一步,将执行第一步的结果返回给第二步使用,在ajax中先拿到一个接口的返回数据,后使用第一部返回的数据执行第二步操作的接口调用,达到异步操作。

promise相关的问题

【基础回答】Promise是什么?有什么作用?解决了什么问题?【进阶回答】Promise相关的一些知识点(这样也可以让面试官顺藤摸瓜,沿着你的回答提问)

Promise是ES6新增的语法,是一种异步编程的一种解决方案,Promise本质上是一个绑定了回调的对象。 Promise在一定程度上解决了回调函数的书写结构问题,解决了回调地狱的问题。Promise可以看作是一个状态机,它有三种状态:pending,fulfilled,rejected,其中初始状态是pending,可以通过函数resolve(表示成功)把状态变为fulfilled,或者通过函数reject(表示失败)把状态变为rejected,状态一经改变就不能再次变化。

Promise有几种状态?

pending resloved( fulfilled ) rejected

Promise的状态可变吗?

状态不可变

什么是回调地狱?

答: 回调地狱就是嵌套回调问题,具体来说就是异步返回值又依赖于另一个异步返回值(看下面的代码)

js加es6面试题整理_第2张图片

 

Promise是如何解决地狱回调的?

js加es6面试题整理_第3张图片

 

then里面可以return Promise,来防止地狱回调

prmoise.all()

Promise.all([]).then(res=> {}).catch(err => {})

该方法接收一个可迭代对象(如Array,Map,Set),返回一个Promise(新期约),只有当该数组中所有的Promise完成后才会有pending转变为resolved执行then里面的回调函数;若数组中有任意一个promise被拒绝则会执行失败回调,即catch方法会捕获到首个被执行的reject函数。通过该方法获得的成功结果的数组里面的数据顺序和接收到的promise数组顺序是一致的。

Promise.race()

Promise.race([]).then(res => {}).catch(err => {})

Promise.race()和Promise.all()一样都是将多个Promise实例组合成一个Promise的静态方法 不同的是:Promise.race()当传入的数组中有任意一个promise被拒绝或者成功,则会采用第一个promise作为返回值,若成功则执行then,失败执行catch。

Promise.any()

Promise.any([]).then(res => {}).catch(err => {})

区别于Promise.all(), Promise.any() 只要有一个成功,就返回成功的promise,如果没有一个成功,就返回一个失败的promise

Promise.allSelected()

Promise.allSelected([]).then(res => {}).catch(err => {})

返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果

Promise.catch 异常的情况, 对于try…catch…

如何让Promise顺序执行?应用场景是什么?

js加es6面试题整理_第4张图片

 

####手写promise.alljs加es6面试题整理_第5张图片

 

js加es6面试题整理_第6张图片

 

ts对比js的优势及不同点

优势:Typescript 是 JavaScript 的超集,可以被编译成 JavaScript 代码。用 JavaScript 编写的合法代码,在 TypeScript 中依然有效。Typescript 是纯面向对象的编程语言,包含类和接口的概念。相较而说 Typescript 更容易理解 更加规范 更偏向 面向对象 等

a. 静态输入 静态类型化是一种功能,可以在开发人员编写脚本时检测错误。查找并修复错误是当今开发团队的迫切需求。有了这项功能,就会允许开发人员编写更健壮的代码并对其进行维护,以便使得代码质量更好、更清晰。

b. 大型的开发项目 有时为了改进开发项目,需要对代码库进行小的增量更改。这些小小的变化可能会产生严重的、意想不到的后果,因此有必要撤销这些变化。使用TypeScript工具来进行重构更变的容易、快捷。

c. 更好的协作 当发开大型项目时,会有许多开发人员,此时乱码和错误的机也会增加。类型安全是一种在编码期间检测错误的功能,而不是在编译项目时检测错误。这为开发团队创建了一个更高效的编码和调试过程。

d. 更强的生产力 干净的 ECMAScript 6 代码,自动完成和动态输入等因素有助于提高开发人员的工作效率。这些功能也有助于编译器创建优化的代码。

主要不同点如下:

1.TS 是一种面向对象编程语言,而 JS 是一种脚本语言(尽管 JS 是基于对象的)。 2.TS 支持可选参数, JS 则不支持该特性。 3.TS 支持静态类型,JS 不支持。通过类型声明,在书写代码的时候,通过.运算符就可以有准确的智能提示,提高效率。 严格的类型声明,可以在开发阶段就对代码的正确性做了一道保障。 4.TS 支持接口,JS 不支持接口。

说一说你对闭包的理解?

闭包形成的原理:作用域链,当前作用域可以访问上级作用域中的变量 闭包解决的问题:能够让函数作用域中的变量在函数执行结束之后不被销毁,同时也能在函数外部可以访问函数内部的局部变量。 闭包带来的问题:由于垃圾回收器不会将闭包中变量销毁,于是就造成了内存泄露,内存泄露积累多了就容易导致内存溢出。 加分回答 闭包的应用,能够模仿块级作用域,能够实现柯里化,在构造函数中定义特权方法、Vue中数据响应式Observer中使用闭包等。

说一说JS实现异步的方法?

所有异步任务都是在同步任务执行完成后,从任务队列中取出依次执行。settimeout 事件监听,回调函数,promise, generator, async/await

说一下重绘、重排区别如何避免?

回流:当一个元素的位置、尺寸等发生改变的时候 浏览器需要重新计算该元素的几何属性并且摆放到正确的位置的过程就叫做回流。一般像页面初次渲染、带有动画的元素、添加/删除功能、图片放大缩小、浏览器窗口发生改变的时候都会触发回流。 重绘:当一个元素的外观、样式发生改变而布局不会改变,重新绘制的过程叫做重绘。 回流必定会触发重绘,而重绘则不一定会触发回流。一般来说,回流对性能的损耗更多一点

重绘不一定引起重排、但重排一定会引起重绘。避免:使用translate替代top、使用visibility代替display:hidden、none、DOM离线后修改、使用class去修改样式、使用 absolute 或 fixed 脱离文档流 、使用GPU加速提升网站的动画渲染性能:transform、transform: translateZ(0); 或 transform: translate3d(0,0,0);不要选择table布局

说一说call apply bind的作用和区别?

作用:改变this指向 区别:call立即执行,返回执行结果,第一个参数为this,后面陆续传入执行参数。apply 立即执行,返回执行结果,第一个参数为this,第二个参数为执行参数组成的数组。bind,返回一个函数,不会立即执行,第一个参数为this,后面陆续传入参数,支持参数柯里化

this指向问题

this当在普通函数调用时,如果处于非严格模式之中将会是指向window、如果是严格模式将会是指向undefined。 在对象之中调用,将会是指向当前的对象。通过new创建出来的对象将会是指向当前的新对象 如果是使用call、bind、apply修改了指向,将会指向绑定后的this 在箭头函数之中将会指向函数的外层执行上下文,当函数定义之后将会确定当前的this。继承了上一层执行环境的this

说一说数组去重都有哪些方法?

1.array.from(new Set(arr)):不考虑兼容性,这种方法去重代码最少。这种方法还没无法去掉“{}”空对象;2.利用for嵌套for,使用splice(ES5中常用);3.利用indexOf去重,新建一个空的结果数组,for循环原数组,判断结果数组中是否存在当前元素,如果存在则跳过,如果不存在,就push到结果数组;4.利用sort(倒叙方法,然后根据排序后的结果进行遍历及相邻的元素比较);5.利用include,判断数组中书否包含某个值,不包含则push,包含则跳过;6.利用map数据结构去重:创建一个空的map数据结构,遍历需要去重的数组,把数组的每个元素作为key存在map中。由于map中不会出现相同的值,所以最终得到的是去重之后的结果;7.[...new Set(arr)]

typeof和instanceof区别

  • typeof判断所有变量的类型,返回值有number,boolean,string,function,object,undefined。

  • typeof对于丰富的对象实例,只能返回"Object"字符串。

  • instanceof用来判断对象,代码形式为obj1 instanceof obj2(obj1是否是obj2的实例),obj2必须为对象,否则会报错!其返回值为布尔值。

  • instanceof可以对不同的对象实例进行判断,判断方法是根据对象的原型链依次向下查询,如果obj2的原型属性存在obj1的原型链上,(obj1 instanceof obj2)值为true。

说一说JavaScript有几种方法判断变量的类型?

  1. typeof(根据二进制判断),不能判断数据类型:null和object 2. intanceof(根据原型链判断),原生数据类型不能判断 3. constructor.name(根据构造器判断),不能判断null数据类型 4. Object.prototype.toString.call()(用Object的toString方法判断)所有类型数据都能判断,记住判断结果打印为:'[object Xxx]'

说一说数组去重都有哪些方法?

方法1、利用for嵌套for,然后splice去重(ES5中最常用)

这是一个最笨的方法,双重循环。

方法2、for循环 +findIndex

主要利用findIndex 的特性,查找元素找不到返回-1, 接下来就需要判断,如果是-1,说明没找到,就往新数组里面添加元素。

方法3、sort 排序

首先利用 sort 方法进行排序。进行循环,如果原数组的第 i 项和新数组的i - 1 项不一致,就push进去。

方法4、Set

ES6中新增了数据类型Set,Set的一个最大的特点就是数据不重复。Set函数可以接受一个数组(或类数组对象)作为参数来初始化,利用该特性也能做到给数组去重。

[...new Set(arr)]

方法5、set + Array.from

利用 set数据不重复的特点,结合 Array.from

Array.from(new Set(arr))

方法6、filter + indexOf

indexOf,可以检测某一个元素在数组中出现的位置,找到返回该元素的下标,没找到返回 -1

方法7、利用includes

方法8、利用Map数据结构去重

思路:遍历原始数组,将数组中的每一个元素作为Key存到Map中,因为Map集合中不会出现相同的Key值,因此最终得到的Map中所有的Key值就是去重后的结果

方法9、reduce +includes去重:

这个方法就是利用reduce遍历和传入一个空数组作为去重后的新数组,然后内部判断新数组中是否存在当前遍历的元素,不存在就插入到新数组中。

说一说null 和 undefined 的区别,如何让一个属性变为null

null表示一个值被定义了,但是是空值,但是undefined表示未被定义。null和undefined在if判断中都会被解析为false,但是在用Number运算时,null的结果为0,undefined的结果为NaN,让属性变为null就需要先定义,再赋空值。

说一说JS变量提升?

var声明的变量存在变量提升、let与const声明的变量不存在提升,但是存在暂时性死区的问题。 变量提升:在js编译阶段将该被声明的变量提升至代码的最前面。同时声明优先级来说,函数提升优先级大于变量提升,变量提升会覆盖掉函数提升 暂时性死区:暂时性死区是在变量未定义之前,就访问该变量所造成的的问题

说一说map 和 forEach 的区别

相同点:1.都能遍历数组 2.中途不能被break打断 3.函数中都有三个参数,当前遍历的元素,当前元素的索引,原数组。 不同:1.forEach没有返回值,也就是返回undefined,map会开辟新的一个内存空间,返回新的数组,这点也方便链式调用其他数组方法。 2.map的效率比forEach高

说一说事件循环Event loop,宏任务与微任务?

在JS单线程的特性下,出现同步异步代码区分,异步代码就显得很难处理(若也是主调用栈顺序执行则会长期占据执行权),因此出现Event Loop机制。将异步代码进行种类划分(宏任务和微任务),并先执行同步代码,执行完后查询微任务队列,执行清空该队列全部任务,再执行一个宏任务(将执行过程中遇到的微任务收集起来),再清空微任务队列。(以此类推)直到所有任务执行完毕。 补充:微任务:promise、process.nextTick、async/await 。 宏任务:定时器、ajax、操作DOM、requestAnimationFrame

你可能感兴趣的:(javascript,es6,开发语言)