目录
1.说一说JavaScript有几种方法判断变量的类型?
有4种方法,分别是typeof、instanceof、Object.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型) 。typeof(根据二进制判断):常用于判断基本数据类型,对于引用数据类型除了function返回’function‘,其余全部返回’object'。instanceof(根据原型链判断):主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。constructor(根据构造器判断):用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。 Object.prototype.toString.call()(用Object的toString方法判断):适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据)返回的是该数据类型的字符串。这四种判断数据类型的方法中,各种数据类型都能检测且检测精准的就是Object.prototype.toString.call()这种方法。
2.说一说JS实现异步的方法?
所有异步任务都是在同步任务执行结束之后,从任务队列中依次取出执行。回调函数是异步操作最基本的方法,比如AJAX回调,优点是简单、容易理解和实现,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(联系紧密),使得程序结构混乱、流程难以追踪(尤其是多个回调函数嵌套的情况),而且每个任务只能指定一个回调函数。此外它不能使用try catch捕获错误,不能直接return。Promise包装了一个异步调用并生成一个Promise实例,当异步调用返回的时候根据调用的结果分别调用实例化时传入的resolve 和 reject方法,then接收到对应的数据,做出相应的处理。Promise不仅能够捕获错误,而且也很好地解决了回调地狱的问题,缺点是无法取消,错误需要通过回调函数捕获。 Generator函数是 ES6 提供的一种异步编程解决方案,Generator 函数是一个状态机,封装了多个内部状态,可暂停函数, yield可暂停,next方法可启动,每次返回的是yield后的表达式结果。优点是异步语义清晰,缺点是手动迭代`Generator` 函数很麻烦,实现逻辑有点绕。async/await是基于Promise实现的,async/await使得异步代码看起来像同步代码,优点是使用方法清晰明了,缺点是await将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了await会导致性能上的降低,代码没有依赖性的话,完全可以使用 Promise.all 的方式。事件监听element.addEventListener,优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。setTimeout定时器、setInterval。
3.说一说数组去重都有哪些方法?
一:利用对象属性key排除重复项:遍历数组,每次判断对象中是否存在该属性,不存在就存储在新数组中,并且把数组元素作为key,设置一个值,存储在对象中,最后返回新数组。优点是效率较高,缺点是占用了较多空间,使用的额外空间有一个查询对象和一个新的数组。二:利用Set类型数据无重复项:new一个Set,参数为需要去重的数组,Set 会自动删除重复的元素,再将 Set 转为数组返回。优点是效率更高,代码简单,思路清晰,缺点是可能会有兼容性问题。三:filter+indexof 去重:和第一种方法类似,利用Array自带的filter方法,返回arr.indexOf(num)等于index的num。原理就是indexOf会返回最先找到的数字的索引,假设数组是 [1, 1],在对第二个1使用indexOf方法时,返回的是第一个1的索引0。优点是可以在去重的时候插入对元素的操作,可拓展性强。四:从头遍历数组,如果元素在前面出现过,则将当前元素挪到最后面,继续遍历,直到遍历完所有元素,之后将那些被挪到后面的元素抛弃。优点是直接操作数组,所以占用内存较少。五:reduce +includes去重:利用reduce遍历和传入一个空数组作为去重后的新数组,然后内部判断新数组中是否存在当前遍历的元素,不存在就插入到新数组中。这种方法时间消耗多,内存空间也有额外占用。
以上方法中,在数据低于10000条的时候没有明显的差别,高于10000条,第一种和第二种的时间消耗最少,后面三种时间消耗依次增加,由于第一种内存空间消耗比较多,且现在很多项目不再考虑低版本浏览器的兼容性问题,所以建议使用第二种去重方法,简洁方便。
4.说一说样式优先级的规则是什么?
CSS样式的优先级分成四大类,由高到低:第一类`!important`,无论引入方式是什么,选择器是什么,它的优先级都是最高的。第二类引入方式,行内样式的优先级要高于嵌入和外链,嵌入和外链如果使用的选择器相同就看他们在页面中插入的顺序,在后面插入的会覆盖前面的。第三类选择器,选择器优先级:id选择器(权重100)>(类选择器 | 伪类选择器 | 属性选择器)(权重10)>(后代选择器 | 伪元素选择器 | 标签选择器)>(子选择器 | 相邻选择器)>通配符选择器*。第四类继承样式,第五类浏览器默认样式优先级最低。
使用!important要谨慎,一定要优先考虑使用样式规则的优先级来解决问题而不是`!important`,只有在需要覆盖全站或外部CSS的特定页面中使用`!important`,不要在插件中使用`!important`,不要在全站范围的CSS代码中使用。`!important`优先级的比较指的是相同的样式属性,不同样式属性优先级比较失效,比如:在设置`max-width`时注意,已经给元素的`max-width`设置了`!important`但是还不生效,很有可能就是被width覆盖了。举例:`div`最终的宽度还是`200px`,div { max-width: 400px !important; height: 200px;background-color: tomato; width: 200px; }
5.说一说Vuex是什么,每个属性是干嘛的,如何使用 ?
Vuex是集中管理项目公共数据的。Vuex有state、mutations、getters、actions、module属性。state属性用来存储公共管理的数据。mutations属性定义改变state中数据的方法,处理同步事件(注意:不要在mutation中的方法中写异步方法ajax,那样数据就不可跟踪了)。Action可以包含任意异步操作,action属性类似于 mutation,不同在于:Action提交的是mutation,而不是直接变更状态。getters 属性可以认为是定义store的计算属性,用于过滤数据。module属性是将store分割成模块。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块,从上至下进行同样方式的分割。
使用方法:state:直接以对象方式添加属性;mutations:通过`store.commit`调用;action:通过`store.dispatch`方法触发;getters:直接通过store.getters调用。可以使用mapState、mapMutations、mapAction、mapGetters一次性获取每个属性下对应的多个方法。Vuex在大型项目中比较常用,非关系组件传递数据比较方便。
6.说一说Vue2.0 双向绑定的原理与缺陷?
vue的双向绑定是采用数据劫持结合发布者订阅者模式的方式来实现响应式,Vue响应式指的是:组件的data发生变化,立刻触发试图的更新。原理:Vue采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理。 通过原生js提供的监听数据的API,当数据发生变化的时候,在回调函数中修改dom。核心API:Object.defineProperty。Object.defineProperty API的使用: 用来定义对象属性,特点: 默认情况下定义的数据的属性不能修改,描述属性和存取属性不能同时使用,使用会报错。响应式原理:获取属性值会触发getter方法 设置属性值会触发setter方法,在setter方法中调用修改dom的方法。
(来源:牛客网)