1.什么是事件委托?为什么这样做?
答:它还有一个名字叫事件代理,事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
为什么这样做呢?通过事件委托可以减少事件处理程序数量,这样就能大大的减少与dom的交互次数,提高性能;
2.js数据类型?
答:JS的数据类型有8种。
在ES5的时候,我们认知的数据类型确实是 6种:Number、String、Boolean、undefined、object、Null。
ES6 中新增了一种 Symbol 。这种类型的对象永不相等,即始创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记。
谷歌67版本中还出现了一种 bigInt。是指安全存储、操作大整数。(但是很多人不把这个做为一个类型)。
JS数据类型:Object 中包含了哪几种类型?其中包含了Date、function、Array等(这三种比较常用)。
3.for in、Object.keys()区别?哪个要用于遍历 原型链上的属性?
答:for-in 是javaScript中最常见的迭代语句,常常用来枚举对象的属性。某些情况下,可能按照随机顺序遍历数组元素;而Object.keys(),可以返回以对象的属性为元素的数组。数组中属性名的顺序跟使用,for-in遍历返回的顺序是一样的。
二者遍历的数量是不同的,for-in 不单可以枚举自身属性,也可以枚举继承自原型链上的属性,Object.keys()只可以枚举自身属性。
for-in会遍历原型链上的属性,而Object.keys不会。
4.NaN == NaN 的结果是什么?为什么?
答:NaN == NaN 的执行结果是 false。因为JavaScript规定,NaN表示的是非数字,但是这个非数字也是不同的,因此 NaN 不等于 NaN,两个NaN永远不可能相等。
5.说一下你对Promise的了解?说说你对Promise的原理的理解?
答:Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
所谓promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
6.Promise.all(),一个失败后,其他的还返回吗?
答:不会返回,promise.all()失败的时候只返回最先被reject失败状态的那个实例对象的值
7.Promise.all()、Promise.race()区别?‘
答:两者都是可以同时调用多个promise实现,Promise.all可以将多个实例组装成一个新的实例,成功的时候返回一个成功数组,失败的时候则返回最先被reject失败状态的值;其中有一个实例不成功则返回reject.race()是赛跑的意思,也就是说Promise.race([p1, p2, p3])里面的结果哪个获取的快,就返回哪个结果,不管结果本身是成功还是失败
8.Promise有哪些状态。
答:有三个状态:pending : 等待 fullfilled(resolved) :成功 reject: 失败
9.简单说一下async/await的了解?(****)(请参考https://www.jianshu.com/p/fd6933ff6b81)
答:async/await是写异步代码的新方式,它是generator的语法糖,以前的方法有回调函数和 Promise。async/await是基于Promise实现的,它不能用于普通的回调函数。async/await与Promise一样,是非阻塞的。async/await使得异步代码看起来像同步代码,这正是它的魔力所在。单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了
10.Async&await和promise有什么区别?(参考https://www.jianshu.com/p/51f5fd21588e)
答:(1)函数前面多了一个async关键字。await关键字只能用在async定义的函数内。async函数会隐式返回一个promise
(2)简洁:使用async和await明显节约了不少代码,不需要.then,不需要写匿名函数处理promise的resolve的值,不需要定义多余的data变量,还避免了嵌套代码。
(3)async/await让try/catch 可以同时处理同步和异步错误。try/catch不能处理JSON.parse的错误,因为他在promise中。此时需要.catch,这样的错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂
(4)async/await能够使得代码调试更简单
11.有10个任务,使用promise如何同时运行5个任务
答:可以利用Promise.all()方法来同时支行5个任务
12.简单介绍原型链?
答:所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain)最终都可以上溯到Object.prototype Object.prototype对象有没有它的原型呢?回答Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
13.如果后端有3个请求,如何保证顺序
答:可以使用Promise链式调用,按顺序执行;也可以使用async函数和关键字await顺序执行
14.await后面可以是一个普通的函数吗?
答:可以,但是其结果会转化为promise的resolve状态
15.es6的set、map介绍?
答:set和map都是es6新增的数据结构。其中set是一个类数组结构,值是唯一的,没有重复的值。map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
16.axios的原理,基于什么实现的。
答:Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
axios还是属于 XMLHttpRequest, 因此需要实现一个ajax;还需要一个promise对象来对结果进行处理。
17.数组去重除了set外,还可以怎么做?
答:
- filter()和indexOf()实现去重
- reduce()和includes()实现去重
- 双重for循环 + splice() 或 双重for循环 + push() (ES5的方法)
18.简述一下对闭包理解?
答:闭包:在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。经常用闭包来实现面向对象编程
一个函数和它的周围状态的引用捆绑在一起的组合
是一个可以读取其他函数内部变量的函数,在js中只有函数内部的函数才可以读取该函数内部的变量,因此,闭包可以是一个函数中返回的函数。
闭包的好处:可以读取其他函数内部的变量,并将其一直保存在内存中。
坏处: 可能会造成内存泄露或者内存溢出
19.es6相关的知识知道哪些?
答:有很多,如Promise async函数 箭头函数 Symbol新的基本数据类型,class类等等
20.对箭头函数的了解,箭头函数的优缺点?
答:箭头函数是匿名函数,ES5匿名函数的语法糖,并且没有自己的this,arguments,super或 new.target。
它的优点是:
(1)简洁的语法、
(2)隐士返回,如 下面的代码可以去掉return,代码移到一行,减少代码量numbers.map((number)=>number*2)
(3)解决了this的指向问题,原生的写法this指向的是调用者,箭头函数this绑定的是定义时的那个对象。如果有对象嵌套的情况,则this绑定到最近的一层对象上
它的缺点是:
(1)做为构造函数的时候不能使用箭头函数
(2)真正需要this的时候如给元素绑定click事件的 时候,执行的回调函数不能使用箭头函数。
(3)我们需要使用arguments对象的时候不能使箭头函数。箭头函数中没有arguments对象。
21.箭头函数与普通函数的区别?
答:
(1)定义的形式不同。
(2)箭头函数全都是匿名函数。
(3)普通函数的this指向调用者,箭头函数的 this 永远指向其上下文的 this,任何方法都改变不了箭头函数this指向,如 call() , bind() , apply()
(4)箭头函数不具有prototype属性,新建的对象的隐式原型无法被指定为箭头函数的原型
(5)箭头函数不能用于构造函数
(6)箭头函数不能Generator函数
(7)箭头函数不具有arguments对象
22.const、let、var的区别?
答:var 声明的变量属于函数作用域,let 和 const 声明的变量属于块级作用域;
var 存在变量提升现象,而 let 和 const 没有此类现象;
var 变量可以重复声明,而在同一个块级作用域,let 变量不能重新声明,const 变量不能修改
Var 不存在暂时性死区,而let const存在暂时性死区
23.get、post区别?
答: Get 方法通过 URL 请求来传递用户的数据,将表单内各字段名称与其内容,以成对的字符串连接,置于 action 属性所指程序的 url 后,数据都会直接显示在 url 上,就像用户点击一个链接一样;Post 方法通过 HTTP post 机制,将表单内各字段名称与其内容放置在 HTML 表头(header)内一起传送给服务器端交由 action 属性能所指的程序处理,该程序会通过标准输入(stdin)方式,将表单的数据读出并加以处理;
Get 方式需要使用 Request,QueryString 来取得变量的值;而 Post 方式通过RequestForm 来访问提交的内容;
Get 方式传输的数据量非常小,一般限制在 2 KB 左右,但是执行效率却比 Post 方法好;而 Post 方式传递的数据量相对较大,它是等待服务器来读取数据,不过也有字节限制,这是为了避免对服务器用大量数据进行恶意攻击。建议:除非你肯定你提交的数据可以一次性提交,否则请尽量用 Post 方法;
Get 方式提交数据,会带来安全问题,比如一个登陆页面,通过 Get 方式提交数据时,用户名和密码将出现在 URL 上,如果页面可以被缓存或者其他人可以访问客户这台机器,就可以从历史记录获得该用户的帐号和密码,所以表单提交建议使用 Post 方法;
get是从服务器上获取数据,post是向服务器传送数据。
get方式的安全性较Post方式要差些,包含机密信息的话,建议用Post数据提交方式;
在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式。
24.Axios二次分装的目的?
答:二次封装axios,方便我们后续项目的使用。
api统一管理,不管接口有多少,所有的接口都可以非常清晰,容易维护.通常我们的项目会越做越大,页面也会越来越多,如果页面非常的少,直接用axios也没有什么大的影响,那页面组件多了起来,上百个接口呢,这个时候后端改了接口,多加了一个参数什么的呢?那就只有找到那个页面,进去修改.整个过程很繁琐不易于项目的维护和迭代.
25.说说constructor()?
答: constructor的作用是可以知道实例对象的构造函数是谁,constructor属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。
26.class与function定义类的区别?
答:
- 关于构造器constructor:在function定义的构造函数中,其prototype.constructor属性指向构造器自身,在class定义的类中,constructor其实也相当于定义在prototype属性上
- 重复定义:function会覆盖之前定义的方法;class会报错
- 原型或者类中方法的枚举:class中所有方法不可枚举
- class没有变量提升,function有
(5)class定义的类没有私有方法和私有属性
27.Session Storage一刷新还有吗?
答: 刷新页面session stroage是不会消失的,只有关闭浏览器才会消失,如果出现了页面刷新导致session storag消失的问题,请排查页面刷新时是否执行了sessionStroage.clear()操作。
28.1+2等于3吗,在程序里面?
答: 等于,但是0.1+0.2 = 0.30000000000000004。原因是由于JS浮点数存储机制:
解决方法:自己实现浮点数加法,先转化可以计算的整数,再相加,最后转化为小数,精度取一定位数如5
29.发布订阅怎么实现的?
答:发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
30.自己实现发布订阅者模式 如何实现?
答:
1. 创建一个对象
2. 在该对象上创建一个缓存列表(调度中心)
3. on 方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心)
4. emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
5. off 方法可以根据 event 值取消订阅(取消订阅)
6. once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)
31.如何移除订阅发布者模式
答:实现一个off方法根据event值取消订阅,从订阅列表中移除即可。
32.如果用本机存储的方式实现定时任务过期?
答:本题的核心是考查的是如何实现localstorage本地定时缓存?方案:ES5扩展Storage,思路很简单,存储的值加一个时间戳,下次取值时验证时间戳;注意: localStorage只能存储字符,存入时将对象转为json字符串,读取时也要解析
33.暂时性死区的报错是什么样的,为什么会有暂时性死区,Var为什么没有暂时性死区?
答:
if(true){console.log(tmp); let tmp = 90;}如上代码会出现暂时性死区报错,报措信息“Uncaught ReferenceError: Cannot access 'tmp' before initialization at <anonymous>:3:7”
出现暂时性死区的原因:let/const 命令会使区块形成封闭的作用域。若在声明之前使用变量,就会报错。总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为 “暂时性死区”( temporal dead zone,简称 TDZ)。
Var 具有声明提升的特性,所以在使用前调用该变量值为undefined,并不会出现暂时性死区现象
34.数组里面常用的方法
答:
1. push 向数组的末尾添加一项或多项元素
2. pop 删除数组的最后一项
3. shift 删除数组的首项
4. unshift 向数组的开头添加一或多项
5. splice 增删改
6. slice 截取数组(复制数组)
7. join 用指定的分隔符将数组每一项拼接为字符串
8. concat 用于连接两个或多个数组
9. sort 对数组的元素进行排序
10. reverse 倒序数组
35.forEach和map循环区别
答:最大的区别是forEach没有返回值,map有返回值,可以return;
36.影响js性能的操作
答:
- for()语句性能优于for(...in...)语句
- 避免重复创建函数,避免使用闭包。推荐使用prototype追加方法
- 判断一个js对象是否支持某个属性或方法时使用if(typeof(person.attr)!='undefined') ,考虑到当person.attr=null,0,false的情况
- 在IE中根据name属性取得SPAN元素:w3c规范中getElementsByName是按着name属性进行检索的,而MS的IE却是按着id来检索,导致不能得到应该得到的Elements。可用getElementsByTagName后再getAttribute("name")判断。
- 得到字符串所占的字符个数: if (intCode>=0&&intCode<=128) { totallength=totallength+1;//非中文单个字符长度加 1}else{ totallength=totallength+2; //中文字符长度则加 2}
- 原始类型(string,number,boolean,null,undefined):值; 复合类型(object,array,function):访问地址。
- 使用{}创建对象
- 使用[]创建数组,如果你不知道数组长度,使用Array#push。当你需要复制数组的时候,请使用Array#slice。
- 对于字符串,使用单引号'
- 字符串拼接,可以使用Array#join。尤其是对IE浏览器。
- 绝对不要在非函数块(if,while)申明一个函数。可以把函数申明变成一个函数表达式 var test = function test(){...}
- 访问属性使用点(.)操作符, 当以变量的方式访问属性的时候,用下标符号([])。——除非特殊需求,否则尽量避免使用obj[variable]的方式进行属性访问。
- 使用一个var定义多个变量,每个变量在一个新行上,把不进行赋值的变量放置到最后
- 在选择时,最好以ID选择符作为开头
- 尽量少用选择符,而使用逗号
- 在循环次数很多时避免使用$().each,而使用for循环
- 尽量减少对DOM的操作
- 如果参数可以是JS对象,尽量使用对象:$("div").css({ "display": "block", "background-color": "blue" });
37.谈谈对深浅拷贝的理解,怎么实现深浅拷贝的?
答:浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
浅拷贝的实现方式:
(1)Object.assign()
(2)Array.prototype.concat()
(3)Array.prototype.slice()
深拷贝的实现方式:
- JSON.parse(JSON.stringify())
(2)手写递归方法:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝(源码可参考:https://www.cnblogs.com/secretAngel/p/10188716.html)
38.类数组有用过吗,什么情况下用,怎么转化成真正数组
答:有用过,比如document.getElementsByTagName()的返回值就是一个类数组,比如函数中的arguments对象也是一个类数组。
常用的类数组转数组的方法有3种:
- Array.from(类数组);
- [...类数组]
- Array.prototype.slice.call(类数组)
39.谈谈this指向。
答:this是函数运行时自动生成的一个内部对象,只能在函数内部使用,但总指向调用它的对象。它的指向由调用它的对象来决定,如:
1.在全局中this指向window
2.直接调用函数this指向window
3.事件处理函数中this指向绑定事件的元素
4.obj.fn(); fn函数中this指向obj
5.回调函数中this指向window
6.构造函数中this指向实例化对象
40.js里哪些操作会造成内存泄漏
答:(1)在函数中定义全局变量(2)闭包。闭包可以维持函数内局部变量,使其得不到释放。(3)删除元素却没有清除DOM元素引用(4)被遗忘的定时器或者回调(5)子元素存在引用引起的内存泄漏
41.js里什么是垃圾回收机制
答:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔,周期性的执行。
两种方法:1.标记清除 2.引用计数
42.js延迟加载都有哪些方式
答:JS延迟加载,也就是等页面加载完成之后再加载 JavaScript 文件。
- script标签中加入defer属性
- script标签中加入async属性
- 动态创建dom的方法
- 使用jQuery的getScript方法
- setTimeout
- 最后 引入js
43.js缓存的三种方法及区别与特点
答:H5本地存储:sessionStorage:临时的会话存储,只要当前的会话窗口未关闭,存储的信息就不会丢失,即便刷新了页面或者在编辑器中更改了代码,存储的会话信息也不会丢失。localStorage是一种永久存储,会一直将数据存储在客户端的储存方式,即使关闭了浏览器,下次打开的时候仍然可以看到之前存储的未主动清除的数据(即便是杀毒软件或者浏览器自带的清除功能,也不能将localStorage存储的数据清除掉)
Cookie:Cookie是存储在用户计算机上的小文件,保存特定客户端和网站的适量数据,并可以由Web服务器或客户端浏览器访问,允许服务器提供针对特定用户定制的页面,或者页面本身可以包含一些知道cookie中的数据的脚本。
cookie和H5本地存储的区别
1.cookie兼容所有的浏览器(本地cookie谷歌不支持),storage不支持IE6~8;
2.二者对存储的内容均有大小限制,前者同源情况写一般不能存储4kb的内容,后者同源一般能存储只能存储5MB的数据
3.cookie有过期时间,localStorage是永久存储(如果你不手动去删除的话)
4.一些浏览器处于安全的角度可能会禁用cookie,但无法禁用localStorage
44.cookie有什么弊端
答:cookie兼容所有的浏览器,但其存储的数据是有大小限制的,一般同源是4kb;cookie本地存储的数据会被发送到服务器(所以建议在服务器环境下使用cookie);存在跨域访问问题;浪费带宽等等;
45.怎么阻止冒泡和浏览器默认事件
答:标准浏览器: 阻止冒泡e.stopPropagation() 阻止默认事件e.preventDefault()
ie浏览器: 阻止冒泡e.cancleBubble=true 阻止默认事件e.returnValue = fasle;
46.什么是面向对象编程,三个属性是什么
答:面向对象编程是一种编程开发思想。 它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。,每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。 因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。
三个属性:封装、继承、多态
47.前端调试bug都有哪些方法
答:
- 断点调试
- console.log调试
- 检测dom事件执行顺序
- 打开控制台CSS调试
48.Js里面的事件循环
答:答案参考https://www.jianshu.com/p/184988903562来学习
49.怎么实现图片懒加载(答案参考:https://www.jianshu.com/p/6d3e38728c10)
答:定义:当打开一个有很多图片的页面时,先只加载页面上看到的图片,等滚动到页面下面时,再加载所需的图片。这就是图片懒加载。
作用:减少或延迟请求数,缓解浏览器的压力,增强用户体验
实现方式:
设置图片src属性为同一张图片,同时自定义一个data-src属性来存储图片的真实地址
页面初始化显示的时候或者浏览器发生滚动的时候判断图片是否在视野中
当图片在视野中时,通过js自动改变该区域的图片的src属性为真实地址
50.假如有一个很长的数字,怎么给他做千分位的格式化分元呢! (数字从右往左每三位一个逗号)
答:正则匹配
的下标,但是foreach循环中的i表示的是数组的key是string类型,因为js中一切皆为对象。强烈要求不要用for in 遍历数组.
51.什么是块作用域,什么是函数作用域?
答:块作用域:ES5中没有块作用域;ES6的块级作用域,任何一对花括号中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域
函数作用域:函数作用域是针对局部变量来说的,在函数中定义的变量在函数外不能获取
52.我声明了一个构造函数,调用的时候 我写new 和没有写new有什么区别?
答:任何函数,如果不通过 new 操作符来调用,就是直接执行函数体。
如果使用 new调用,则不单执行函数,还会返回个实例对象。以这种方式调用构造函数实际上会经历以下4个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
53.通过ES5的方法怎么把类数组转成真正的数组?
答:方法1:遍历类数组,将类数组里面的元素依次放入一个新的数组
方法2:使用 apply 和 call,apply方法的第二个参数是数组,也可以是类数组,在调用的时候会将第二个参数依次展开
54.简单说一下事件冒泡
答:IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深
的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。事件沿 DOM 树向上传播,在每一级节点上都会发生,直至传播到 document 对象。
所有现代浏览器都支持事件冒泡,但在具体实现上还是有一些差别。IE5.5 及更早版本中的事件冒泡会跳过<html>元素(从<body>直接跳到 document)。IE9、Firefox、Chrome 和 Safari 则将事件一直冒泡到 window 对象。
55.普通函数和箭头函数的this指向的区别
答:普通函数this指向由调用决定,this指向调用该函数的对象,而箭头函数this指向由定义时决定,this指定父级作用域的this
56.new一个关键字做了哪些事情
答:使用 new 操作符。以这种方式调用构造函数实际上会经历以下4个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
57.有一串手机号,我想把中间的四位替换成****,我要用什么方法实现?
答:利用正则表达式:
var tel = 15617076160;
tel = "" + tel;
var reg=/(\d{3})\d{4}(\d{4})/;
var newTel = tel.replace(reg, "$1****$2");
console.log(newTel);//156****6160
58.循环的方法有哪些,每个循环有哪些特点呢?
答:1.for循环:特点是先判断后执行,当条件成立才会执行,适用于循环次数已知的循环;2.while循环:特点也是先判断后执行,当条件成立才会执行,适用于循环次数未知的循环;3.do...while循环:特点是先执行后判断,先执行一遍循环体,再判断条件是否成立,成立则继续循环,不成立则结束循环。
59.Async函数用法和promise区别
答:简单的说async函数就相当于自执行的Generator函数,相当于自带一个状态机,在await的部分等待返回, 返回后自动执行下一步。而且相较于Promise,async的优越性就是把每次异步返回的结果从then中拿到最外层的方法中,不需要链式调用,只要用同步的写法就可以了。更加直观而且,更适合处理并发调用的问题。但是async必须以一个Promise对象开始 ,所以async通常是和Promise结合使用的。总的来说,async函数主要就是为了解决异步的并发调用使用的 ,直接将参数从then里取出来,相比promise的链式调用,传参更加方便,异步顺序更加清晰。
60.Async和promise如何捕捉错误信息
答: async可以使用try...catch语句;promise可以使用实例方法catch捕获异常
61.Extends继承和js5核心区别?
答:这道题面试官考查的是你对Es5与ES6继承的理解,它俩的区别主要集中在以下几点:
(1)ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this)).
(2)ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。
(3)ES5的继承时通过原型或构造函数机制来实现。
(4)ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。
62.Js中如何处理同步和异步的
答:同步的话代码依次执行,异步的处理方式有:(1)回调函数 (2)promise (3)Generator (4)Async/await (5)定时器函数 (6)ajax等
63.call bind apply 的区别
答:(1)bind不会立刻执行,会返回绑定this之后的函数,call和apply会立即执行(2)三者都可以传参,但是apply是数组,而call和bind传过去的是一系列参数
64.javascript原型和原型链
答:原型:每一个javascript对象(除null外)创建的时候,都有一个__proto__属性指向与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。
原型链:每个构造函数都有原型对象,每个构造函数实例都包含一个指向原型对象的内部指针(proto),如果我们让第一个构造函数的原型对象等于第二个构造函数的实例,结果第一个构造函数的原型对象将包含一个指向第二个原型对象的指针,再然第三个原型对象等于第一个构造函数的实例,这样第三个原型对象也将包含指向第一个原型对象的指针,以此类推,就够成了实例于原型的链条,这就是原型链的基本概念。
65.说说你对spa单页面应用的理解
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点:
• 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
• 基于上面一点,SPA 相对对服务器压力小;
• 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
缺点:
• 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
• 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
• SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。