中Web前端面试题,直击BAT:JavaScript篇
1.模块化
模块化开发在现代开发中已是必不可少的一部分,它大大提高了项目的可维护、可拓展和可协作性。通常,我们在浏览器中使用ES6的模块化支持,在Node中使用commonjs的模块化支持。
分类:
es6:import/export
commonjs:require/module.exports/exports
amd:require/defined
require与import的区别
require支持动态导入,import不支持,正在提案(babel下可支持)
require是同步导入,import属于异步导入
require是值拷贝,导出值变化不会影响导入值;import指向内存地址,导入值会随导出值而变化
2.防抖与节流
防抖与节流函数是一种常用的高频触发优化方式,能对性能有较大的帮助。
防抖(debounce):将多次高频操作优化为只在后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。
function debounce(fn,wait,immediate){let timer=null return function(){let args=arguments let context=this if(immediate&&!timer){fn.apply(context,args)}if(timer)clearTimeout(timer)timer=setTimeout(()=>{fn.apply(context,args)},wait)}}
节流(throttle):每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景:滚动条事件或者resize事件,通常每隔100~500 ms执行一次即可。
function throttle(fn,wait,immediate){let timer=null let callNow=immediate return function(){let context=this,args=arguments if(callNow){fn.apply(context,args)callNow=false}if(!timer){timer=setTimeout(()=>{fn.apply(context,args)timer=null},wait)}}}
3.函数执行改变this
由于JS的设计原理:在函数中,可以引用运行环境中的变量。因此就需要一个机制来让我们可以在函数体内部获取当前的运行环境,这便是this。
因此要明白this指向,其实就是要搞清楚函数的运行环境,说人话就是,谁调用了函数。例如:
obj.fn(),便是obj调用了函数,既函数中的this===obj
fn(),这里可以看成window.fn(),因此this===window
但这种机制并不完全能满足我们的业务需求,因此提供了三种方式可以手动修改this的指向:
call:fn.call(target,1,2)
apply:fn.apply(target,[1,2])
bind:fn.bind(target)(1,2)
4.ES6/ES7
由于Babel的强大和普及,现在ES6/ES7基本上已经是现代化开发的必备了。通过新的语法糖,能让代码整体更为简洁和易读。
声明
let/const:块级作用域、不存在变量提升、暂时性死区、不允许重复声明
const:声明常量,无法修改
解构赋值
class/extend:类声明与继承
Set/Map:新的数据结构
异步解决方案:
Promise的使用与实现
generator:
yield:暂停代码
next():继续执行代码
function*helloWorld(){yield'hello';yield'world';return'ending';}const generator=helloWorld();generator.next()//{value:'hello',done:false}generator.next()//{value:'world',done:false}generator.next()//{value:'ending',done:true}generator.next()//{value:undefined,done:true}复制代码
await/async:是generator的语法糖,babel中是基于promise实现。
async function getUserByAsync(){let user=await fetchUser();return user;}const user=await getUserByAsync()console.log(user)复制代码
5.AST
抽象语法树(Abstract Syntax Tree),是将代码逐字母解析成树状对象的形式。这是语言之间的转换、代码语法检查,代码风格检查,代码格式化,代码高亮,代码错误提示,代码自动补全等等的基础。例如:
function square(n){return n*n}复制代码
通过解析转化成的AST如下图:
6.babel编译原理
babylon将ES6/ES7代码解析成AST
babel-traverse对AST进行遍历转译,得到新的AST
新AST通过babel-generator转换成ES5
7.函数柯里化
在一个函数中,首先填充几个参数,然后再返回一个新的函数的技术,称为函数的柯里化。通常可用于在不侵入函数的前提下,为函数预置通用参数,供多次重复调用。
const add=function add(x){return function(y){return x+y}}const add1=add(1)add1(2)===3add1(20)===21
8.数组(array)
map:遍历数组,返回回调返回值组成的新数组
forEach:无法break,可以用try/catch中throw new Error来停止
filter:过滤
some:有一项返回true,则整体为true
every:有一项返回false,则整体为false
join:通过指定连接符生成字符串
push/pop:末尾推入和弹出,改变原数组,返回推入/弹出项
unshift/shift:头部推入和弹出,改变原数组,返回操作项
sort(fn)/reverse:排序与反转,改变原数组
concat:连接数组,不影响原数组,浅拷贝
slice(start,end):返回截断后的新数组,不改变原数组
splice(start,number,value...):返回删除元素组成的数组,value为插入项,改变原数组
indexOf/lastIndexOf(value,fromIndex):查找数组项,返回对应的下标
reduce/reduceRight(fn(prev,cur),defaultPrev):两两执行,prev为上次化简函数的return值,cur为当前值(从第二项开始)
数组乱序:
var arr=[1,2,3,4,5,6,7,8,9,10];arr.sort(function(){return Math.random()-0.5;});
数组拆解:flat:[1,[2,3]]-->[1,2,3]
Array.prototype.flat=function(){this.toString().split(',').map(item=>+item)}
尾声
今天的内容就先告一段落了,希望整个系列可以给大家带来帮助~