1.箭头函数与普通函数的区别?
答:
(1)定义的形式不同。
(2)箭头函数全都是匿名函数。
(3)普通函数的this指向调用者,箭头函数的 this 永远指向其上下文的 this,任何方法都改变不了箭头函数this指向,如 call() , bind() , apply()
(4)箭头函数不具有prototype属性,新建的对象的隐式原型无法被指定为箭头函数的原型
(5)箭头函数不能用于构造函数
(6)箭头函数不能Generator函数
(7)箭头函数不具有arguments对象
2.const、let、var的区别?
答:var 声明的变量属于函数作用域,let 和 const 声明的变量属于块级作用域;
var 存在变量提升现象,而 let 和 const 没有此类现象;
var 变量可以重复声明,而在同一个块级作用域,let 变量不能重新声明,const 变量不能修改
Var 不存在暂时性死区,而let const存在暂时性死区
3.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方式。
4.axios的原理,基于什么实现的。
答:Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
axios还是属于 XMLHttpRequest, 因此需要实现一个ajax;还需要一个promise对象来对结果进行处理。
5.Axios二次分装的目的?
答:二次封装axios,方便我们后续项目的使用。
api统一管理,不管接口有多少,所有的接口都可以非常清晰,容易维护.通常我们的项目会越做越大,页面也会越来越多,如果页面非常的少,直接用axios也没有什么大的影响,那页面组件多了起来,上百个接口呢,这个时候后端改了接口,多加了一个参数什么的呢?那就只有找到那个页面,进去修改.整个过程很繁琐不易于项目的维护和迭代.
6.说说constructor()?
答: constructor的作用是可以知道实例对象的构造函数是谁,constructor属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。
7.class与function定义类的区别?
答:
(1)关于构造器constructor:在function定义的构造函数中,其prototype.constructor属性指向构造器自身,在class定义的类中,constructor其实也相当于定义在prototype属性上
(2)重复定义:function会覆盖之前定义的方法;class会报错
(3)原型或者类中方法的枚举:class中所有方法不可枚举
(4)class没有变量提升,function有
(5)class定义的类没有私有方法和私有属性
8.Session Storage一刷新还有吗?
答: 刷新页面session stroage是不会消失的,只有关闭浏览器才会消失,如果出现了页面刷新导致session storag消失的问题,请排查页面刷新时是否执行了sessionStroage.clear()操作。
9.1+2等于3吗,在程序里面?
答: 等于,但是0.1+0.2 = 0.30000000000000004。原因是由于JS浮点数存储机制:
解决方法:自己实现浮点数加法,先转化可以计算的整数,再相加,最后转化为小数,精度取一定
位数如5
10.发布订阅怎么实现的?
答:发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
11.自己实现发布订阅者模式 如何实现?
答:1. 创建一个对象
2. 在该对象上创建一个缓存列表(调度中心)
3. on 方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心)
4. emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
5. off 方法可以根据 event 值取消订阅(取消订阅)
6. once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)
12.如何移除订阅发布者模式
答:实现一个off方法根据event值取消订阅,从订阅列表中移除即可。
13.如果用本机存储的方式实现定时任务过期?
答:本题的核心是考查的是如何实现localstorage本地定时缓存?方案:ES5扩展Storage,思路很简单,存储的值加一个时间戳,下次取值时验证时间戳;注意: localStorage只能存储字符,存入时将对象转为json字符串,读取时也要解析
14.暂时性死区的报错是什么样的,为什么会有暂时性死区,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,并不会出现暂时性死区现象
15.。数组里面常用的方法
答:1. push 向数组的末尾添加一项或多项元素
2. pop 删除数组的最后一项
3. shift 删除数组的首项
4. unshift 向数组的开头添加一或多项
5. splice 增删改
6. slice 截取数组(复制数组)
7. join 用指定的分隔符将数组每一项拼接为字符串
8. concat 用于连接两个或多个数组
9. sort 对数组的元素进行排序
10. reverse 倒序数
16.forEach和map循环区别
答:最大的区别是forEach没有返回值,map有返回值,可以return
17.影响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" })
18.谈谈对深浅拷贝的理解,怎么实现深浅拷贝的?
答:浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
浅拷贝的实现方式:
(1)Object.assign()
(2)Array.prototype.concat()
(3)Array.prototype.slice()
深拷贝的实现方式:
- JSON.parse(JSON.stringify())
2.手写递归方法:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
19.类数组有用过吗,什么情况下用,怎么转化成真正数组
答:有用过,比如document.getElementsByTagName()的返回值就是一个类数组,比如函数中的arguments对象也是一个类数组。
常用的类数组转数组的方法有3种:
1.Array.from(类数组);
2.[...类数组]
3.Array.prototype.slice.call(类数组)
20.谈谈this指向。
答:this是函数运行时自动生成的一个内部对象,只能在函数内部使用,但总指向调用它的对象。它的指向由调用它的对象来决定,如:
1.在全局中this指向window
2.直接调用函数this指向window
3.事件处理函数中this指向绑定事件的元素
4.obj.fn(); fn函数中this指向obj
5.回调函数中this指向window
6.构造函数中this指向实例化对象