前言这个面经系列也算是即将接近尾声了,已经连载了4篇文章了:一篇CSS:“金三银四”,让我们愉快的开始准备Web面经吧:CSS篇,
2篇JavaScript:
“金三银四”,让我们愉快的开始准备Web面经吧:JavaScript-上
元宵节,猿宵节,写代码之余面经走一波:JavaScript篇
再加上今天的JavaScript篇,已经接下来的浏览器篇。这个系列就先告一段落,容我休息一下~
正文1. 模块化
模块化开发在现代开发中已是必不可少的一部分,它大大提高了项目的可维护、可拓展和可协作性。通常,我们 在浏览器中使用 ES6 的模块化支持,在 Node 中使用 commonjs 的模块化支持。
分类:es6: import / exportcommonjs: require / module.exports / exportsamd: require / definedrequire与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 === objfn(),这里可以看成 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 代码解析成 ASTbabel-traverse 对 AST 进行遍历转译,得到新的 AST新 AST 通过 babel-generator 转换成 ES57. 函数柯里化
在一个函数中,首先填充几个参数,然后再返回一个新的函数的技术,称为函数的柯里化。通常可用于在不侵入函数的前提下,为函数 预置通用参数,供多次重复调用。
const add = function add(x) { return function (y) { return x + y }}const add1 = add(1)add1(2) === 3add1(20) === 218. 数组(array)
map: 遍历数组,返回回调返回值组成的新数组forEach: 无法break,可以用try/catch中throw new Error来停止filter: 过滤some: 有一项返回true,则整体为trueevery: 有一项返回false,则整体为falsejoin: 通过指定连接符生成字符串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 )}尾声今天的内容就先告一段落了,希望整个系列可以给大家带来帮助~