前端面试题——js篇(二)

1. 解释下什么是变量声明提升?

JS引擎在运行一份代码的时候,首先,对代码进行预编译,将所有var声明的变量提升到所在作用域的顶部,赋值留在原地。

而let和const声明的变量不存在声明提升。

2. JS 的参数是以什么方式进行传递的?

基本类型:是值传递!

像对象数组,传递的是地址。

3.谈谈你对 JavaScript垃圾回收的理解?

js的垃圾回收机制指的是JS中对内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。

JS环境中分配的内存, 一般有如下生命周期

  1. 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存

  2. 内存使用:即读写内存,也就是使用变量、函数等

  3. 内存回收:使用完毕,由垃圾回收自动回收不再使用的内存

全局变量一般不会自动回收, 当关闭浏览器的时候会回收。一般局部变量的的值, 不用了, 会被自动回收掉

垃圾回收算法主要有两种:一种是引用算法,只要不再使用就会回收,但如果两个对象相互引用,会造成内存泄漏。还有一种是标记算法,从根部不能到达的对象,就标记不再使用,就会被回收。

4.谈谈你对 JavaScript 作用域链的理解?

JavaScript 在执⾏过程中会创建一个个的可执⾏上下⽂。在全局作用域有全局的可执行上下文, 在每个函数内部,有着函数的可执行上下文。

当在一个函数内部还有函数,存在多层函数嵌套时,若是执行最内层函数的上下文,首先会在当前作用域找是否有要可使用的变量,如果没有就会到上一级找,若是还没有就继续往外层找,直到找到全局作用域,就形成了作用域链。

5、谈谈你对闭包的理解

MDN的官方解释:

闭包是函数和声明该函数的词法环境的组合

更通俗一点的解释是:

内层函数, 引用外层函数上的变量, 就可以形成闭包

闭包的主要作用是什么?

在实际开发中,闭包最大的作用就是用来 变量私有

6、谈谈你对原型链的理解?

要讲清楚这个问题,主要着重这几个方面:

  • 什么是原型对象

  • 构造函数, 原型对象, 实例的三角关系图

  • 原型链如何形成

构造函数是创建对象的一种方式,构造函数具有一个特性的属性 prototype 指的就是原型对象,通过构造函数名.prototype.属性就可以为为原型对象注入公共属性。

基于同一个构造函数创建出来的实例对象, 都可以共享访问原型对象的属性。

原型链

一般情况下,实例对象访问属性或方法时,优先访问构造函数内部的属性或方法,如果没找到就会到原型对象上找,通过实例对象名.proto.属性或方法名,如果还没找到,就去继续往原型的原型中查找,直到找到根原型Object.prototype,这一层层的原型对象关系构成了原型链。

7、如何判断是否是数组?

Object.prototype.toString()

Array.isArray(arr)

8.谈谈你对this的理解?

有三种情况可以改变this指向,分别是call,apply,bind

call方法传递参数适用逗号分开,apply传递参数是放在一个数组中,bind改变函数this指向的同时会创建一个新的函数

箭头函数中没有属于自己的this,箭头函数中的this指向外层函数的this

9、Promise 的静态方法

promise的三个状态: pending(默认) fulfilled(成功) rejected(失败)

  1. resolve函数被执行时, 会将promise的状态从 pending 改成 fulfilled 成功

  2. reject函数被执行时, 会将promise的状态从pending 改成 rejected 失败

Promise.all([promise1, promise2, promise3])** 等待原则, 是在所有promise都完成后执行, 可以用于处理一些并发的任务

Promise.race([promise1, promise2, promise3]) 赛跑, 竞速原则, 只要三个promise中有一个满足条件, 就会执行.then(用的较少)

10、宏任务 微任务 是什么

宏任务: 主线程代码属于一个宏任务, 一个定时器setTimeout 属于一个宏任务, 上一个宏任务执行完, 才会考虑执行下一个宏任务。

微任务: promise .then .catch的需要执行的内容, 属于微任务, 满足条件的微任务, 会被添加到当前宏任务的最后去执行。

事件循环队列:js是单线程的,js执行代码是从上往下一层一层执行,当遇到异步函数时会交给浏览器,浏览器是多线程的,可以同时执行多个事件,只有主线程执行完,才会按顺序执行异步任务。

11、 相较于 Promise,async/await有何优势?

async放在一个异步函数前,将异步函数转为promise对象,变为跟随主线程同步执行。

await是放在promise函数调用前,阻塞主线程,强制async函数中其他代码等待,直到 Promise 完成并返回结果 再执行后续代码。

优势:让代码更规范,提高阅读性,方便程序员阅读和维护,

12、深拷贝 浅拷贝

引用类型数据像对象或数组, 进行赋值时, 赋值的是地址,两个对象会指向同一个地址,不属于浅拷贝和深拷贝。

浅拷贝:会指向内存中同一个地址,修改一个对象数据,另外一个对象数据也会被修改

深拷贝:会克隆出一个完整的对象,需要利用递归来实现,比较麻烦

13、undefined和null的区别

Undefined类型只有一个值,即undefined。当声明的变量没有赋值时,变量的默认值为undefined。

null类型也只有一个值,即null。null用来表示一个不存在的对象。

14、js怎么实现多线程

js是单线程语言,这是因为js的主要功能是实现用户与浏览器的交互,以及操作dom。这决定了它只能是单线程,否则会带来很复杂的同步问题。

但如果实现多线程可以通过webworker来实现,在主程序中创建worker对象,并传入work子文件,两者就可以进行数据传递。

15、栈内存和堆内存

对于原始类型,数据结构简单,是将数据之间存在栈内存中,而对象数组引用类型,将数据存在了堆内存中,同时会生成一个地址,然后将地址保存到了栈内存的变量中。

16、数组常用的api

Join将数组转为字符串 slice截取数组,splice删除数组,push,unshift shift,reverse sort

17、class面向对象的三大特征

封装、继承、多态

18、promise.all

该方法用于将多个Promise实例,包装成一个新的Promise实例。

**只有b1、b2、b3都是fulfilled(成功)时,b才是fulfilled(成功),只要有一个失败,最终都是显示失败的数据

另外一种方法:先声明一个变量,初始值是1,假如说要发四个网络请求,让请求每成功就加1,最后判断是不是四就行了。

19、判断数据类型的方法

typeOf 不能判断数组

instanceof 判断引用类型数据,包括构造函数 底层是判断左右原型是否是同一个

Object.prototype.toString()

20、箭头函数和普通函数的区别

参数上的区别

普通函数的参数是arguments,而箭头函数的的是args

this指向的不同

箭头函数的this指向上层函数作用域的this对象

原型和构造函数的问题

箭头函数不能使用new生成实例,因为箭头函数没有prototype

21、数组去重的方法

new Set来进行去重,然后利用Array.from 来让变成标准化的数组。。。

22、es6模块化规范

1. const 和 let

2、解构赋值

3、模板字符串

4、数组对象展开运算符

5、promise async/aswait

6、class继承

7、模块化规范

8、数组新用API

你可能感兴趣的:(javascript,前端,面试)