前言

目前在杭州工作,很多敌人都转战上海了,金九银十在敌人的怂恿下,投了上海的几家互联网公司,面试的根本都是中高级前端岗位,面试运气不错根本都拿到offer。面试也很久了,闲暇下来记录下面试记录。

在文章里我不仅会列出面试题,还会给到一些答题倡议,根本都是点到为止,面试的时候根本都有开展答复,篇幅无限就不开展了。集体能力无限,也不能保障我答复都正确,如果有谬误,心愿能纠我。题目排序不分先后,不辨别公司,简略做了分类,就是纯记录下,都是十分惯例的题目。

面试过的公司

莉莉丝、米哈游、哔哩哔哩、小红书、微盟、得物等,本文次要记录面试过的二线互联网公司,当然还面过阿里、美团、拼多多等公司,权且把他们算到一线营垒,这边就没有进行记录了。具体看下一篇哦!

了解问答

1.实现图片懒加载的思路

判断图片所在位置是否在可视区内,图片移到可视区内进行加载,提供三种判断办法

  1. offsetTop < clientHeight + scrollTop
  2. element.getBoundingClientRect().top < clientHeight
  3. IntersectionObserver
2.如何解决跨域
跨域解决的计划是在太多太多了,咱们公司次要是通过nginx进行转发,前端发动申请的地址是和页面地址统一的所以不存在跨域,nginx将申请转发到正确的服务。页面地址:web.taobao.com,申请接口地址web.taobao.com/api.taobao.com/*
3.表单能够跨域吗
表单提交是能够进行跨域的,不受浏览器的同源策略限度,预计是历史遗留起因,也有可能是表单提交的后果js是拿不到的,所以不限度问题也不大。然而存在一个问题,就是csrf攻打,具体不开展了,因为能够主动带上cookie造成攻打胜利,而cookie的新属性SameSite就能用来限度这种状况
4.请为什么说js是单线程,而不是多线程呢,说说你的了解
JavaScript的单线程,与它的用处无关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很简单的同步问题。比方,假设JavaScript同时有两个线程,一个线程在某个DOM节点上增加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
5.为什么typeof能够检测类型,有没有更好的办法
typeof 个别被用于判断一个变量的类型,咱们能够利用 typeof 来判断number, string, object, boolean, function, undefined, symbol 这七种类型,这种判断能帮忙咱们搞定一些问题,js在底层存储变量的时候会在变量的机器码的低位1-3位存储其类型信息(000:对象,010:浮点数,100:字符串,110:布尔,1:整数),然而null所有机器码均为0,间接被当做了对象来对待。
那么有没有更好的方法辨别类型呢,个别应用
6.说说你对GraphQL的了解

GraphQL 对你的 API 中的数据提供了一套易于了解的残缺形容,使得客户端可能精确地取得它须要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建弱小的开发者工具。

  1. 多终端的呈现,APP、小程序、PC端都须要雷同的接口,然而又略有差别,惯例接口须要提供几套,GraphQL的话只须要写好查问语句即可
  2. 天生的聚合接口,以前一个页面须要申请不同的数据,咱们能够申请多个接口,咱们能够让服务端进行聚合,有了GraphQL后咱们能够本人去聚合想要的数据
  3. 不必被版本困扰,之前写接口的时候为了兼容老的我的项目能够失常被拜访,尤其是APP,线上的我的项目,咱们接口必定是不能影响线上的,所以有比拟大的扭转的时候,只能降级版本,有了GraphQL后就无需关怀版本问题了,接口还是那个接口查问语句变一下就好了
  4. 迁徙很简略,服务端在之前的接口上稍加革新就好,前端写查问语句

7.什么是事件委托?它有什么益处?
事件委托是利用事件冒泡机制解决指定一个事件处理程序,来治理某一类型的所有事件
利用冒泡的原理,将事件加到父级身上,触发执行成果,这样只在内存中开拓一块空间,既节俭资源又缩小DOM操作,进步性能
动静绑定事件,列表新增元素不必进行从新绑定了
8.应用js如何扭转url,并且页面不刷新?
扭转URL的目标是让js拿到不同的参数,进行不同的页面渲染,其实就是vue-router的原理

最简略的就是扭转hash,扭转hash是并不会刷新页面的,也会扭转URL,也能监听hashchange事件进行页面的渲染

还有一种就是应用history.pushState()办法,该办法也能够扭转url而后不刷新页面,然而该办法并不可能触发popstate事件,不过pushState使咱们手动触发的,还能不晓得url扭转了么,其实这时候并不需要监听popstate咱们就可能晓得url扭转拿到参数并渲染页面

9.要实现一个js的继续动画,你有什么比拟好的办法?
应用requestAnimationFrame
10.应用css3动画代替js的动画有什么益处?

css和js动画各有优劣

  1. 不占用JS主线程
  2. 能够利用硬件加速
  3. 浏览器可对动画做优化(元素不可见时不动画,缩小对FPS的影响)
11.js中自定义事件的应用与触发
var event = new Event('build');// Listen for the event.elem.addEventListener('build', function (e) { ... }, false);// Dispatch the event.elem.dispatchEvent(event);
12.如果当初让你从vue/react/angularjs三个中抉择一个,你会选哪个?说说你的理由
看团队吧,集体都能承受,对vue和react绝对相熟一点
13.为什么应用jsx开发,vue不是都用template么
jsx的灵活性更高,用写js的思路来写html,更加的高效
14.请解释JSONP的工作原理
JSONP 是一种非正式传输协定,容许用户传递一个callback给服务端,而后服务端返回数据时会将这个callback 参数作为函数名来包裹住 JSON 数据,这样客户端就能够随便定制本人的函数来主动解决返回数据了。当GET申请从后盾页面返回时,能够返回一段JavaScript代码,这段代码会主动执行,能够用来负责调用后盾页面中的一个callback函数。
15.怎么在JavaScript中创立一个worker线程?
具体看文档就好了,理论中我也只是一个我的项目中应用过一次,并不罕用
16.你认为PC端开发和挪动端开发次要有什么区别呢?
因人而异吧
17.做挪动端开发时,你是如何调试的?
应用最多的就是charles和chrome://inspect/#devices进行调试,当然理论开发中还是应用chrome的开发这工具,真机的时候是应用charles代理或者chrome://inspect/#devices代理,ios的话应用的是safari真机调试,当然也应用过vconsole,weinre等进行调试
18.如何实现H5手机端的适配?
flexible + rem进行适配

19.如何解决在挪动端1px的问题?
伪元素缩放
20.css盒模型
IE盒模型,惯例盒模型以及其余衍生问题
21.如何实现换肤性能
这个我也没搞过,查了下有同学给了比拟具体的计划:https://juejin.im/post/684490...
22.Hybrid如何通信的?
  1. API注入,原理其实就是 Native 获取 JavaScript环境上下文,并间接在下面挂载对象或者办法,使 js 能够间接调用,Android 与 IOS 别离领有对应的挂载形式
  2. WebView 中的 prompt/console/alert 拦挡,通常应用 prompt,因为这个办法在前端中应用频率低,比拟不会呈现抵触
  3. WebView URL Scheme 跳转拦挡

23.能简略说下weex么?
知乎下面有一篇文章说的很分明:https://zhuanlan.zhihu.com/p/...

24.请形容晋升页面性能的形式有哪些,如何进行首页加载优化?
开展来说可讲的货色太多了,把本人晓得的都扯了一些,而后理论中应用到的也都扯了
25.如何进行性能优化?
同上
26.谈一谈你晓得的前端性能优化计划有哪些?
同上
27.能聊一聊页面缓存么?
强缓存协定缓存具体也不开展论述了
28.js动画和css动画有什么区别?
具体也不开展论述了,能够放到性能优化中去说
58.说说你了解的同步和异步的区别是什么?
同步,能够了解为在执行完一个函数或办法之后,始终期待零碎返回值或音讯,这时程序是出于阻塞的,只有接管到返回的值或音讯后才往下执行其余的命令。 异步,执行完函数或办法后,不用阻塞性地期待返回值或音讯,只须要向零碎委托一个异步过程,那么当零碎接管到返回值或音讯时,零碎会主动触发委托的异步过程,从而实现一个残缺的流程。
60.实现异步编程有哪些形式?举荐用哪种?
回调函数、Generator、Promise、async/await
59.介绍下promise的个性、优缺点,外部是如何实现的?

Promise是一种异步解决方案,Promise对象承受一个回调函数作为参数, 该回调函数承受两个参数,别离是胜利时的回调resolve和失败时的回调reject;另外resolve的参数除了正常值以外, 还可能是一个Promise对象的实例;reject的参数通常是一个Error对象的实例。

  1. 长处就是更好的异步解决方案
  2. 毛病就是无奈勾销Promise,一旦新建它就会立刻执行,无奈中途勾销

30.https的申请能够拦挡么,如何做?
齐全是有可能的,不然charles抓包是怎么做到的,当然前提是客户端上装了相应的证书
31.https是如何保障数据传输的平安的?
传输加密啊,具体流程是比较复杂的能够开展一篇文章来讲
32.解说一下https对称加密和非对称加密?
非对称加密的加解密效率是非常低的,只作用在证书验证阶段,对称加密在数据传输阶段
33.能说一下你我的项目中遇到了哪些平安问题么,个别都是怎么解决的?
xss、csrf、爬虫、薅羊毛等平安问题

传输加密、接口加签、环境变量、token、输出校验等

34.说说你对XSS和CSRF的了解,他们之间的区别是啥?
具体能讲的货色也很多这边也不开展来说了

xss前端次要是管制好输出,cookie设置http-only

csrf须要严格的cookie策略,减少token校验等

35.你认为前端传输过程的参数须要加密吗?为什么?怎么加密更平安?
看状况而定,惯例的申请参数:搜寻关键词,分页参数没有任何加密的必要。非凡的字段:身份证校验必定是须要加密的。同时前端游戏游戏数据也是必须要加密的,不仅仅须要加密还须要加签。
36.中间人攻打是什么?
中间人攻打是指攻击者与通信的两端别离创立独立的分割,并替换其所收到的数据,使通信的两端认为他们正在通过一个私密的连贯与对方 直接对话,但事实上整个会话都被攻击者齐全管制。

37.webpack打包速度太慢怎么办?
应用高版本的 Webpack、多线程/多实例构建、放大打包作用域、充分利用缓存晋升二次构建速度、DLL
38.loader和plugin的区别?
loader,它是一个转换器,将A文件进行编译成B文件,比方:将A.less转换为A.css,单纯的文件转换过程。

plugin是一个扩展器,它丰盛了webpack自身,针对是loader完结后,webpack打包的整个过程,它并不间接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行宽泛的工作

40.我的项目中有写过plugin么?
我的项目中写过几个解决打包后文件的插件,就简略说了下
41.用过除了webpack外的其余打包工具么?
rollup等
42.晓得npm ci么,和npm install的区别是啥?
npm install读取package.json以创立依赖关系列表,并应用package-lock.json告知要装置这些依赖关系的版本。如果依赖项不在package-lock.json中,它将由npm install增加。

npm ci(以继续集成命名)间接从package-lock.json装置依赖关系,并且仅应用package.json来验证没有不匹配的版本。如果短少任何依赖项或版本不兼容,则将引发谬误。

速度上ci显著比install快,线上公布打包的时候应用ci是优于install的

43.能简略说下vue的响应式原理么
这种题目能说的货色很多,每一个点都能够开展,次要看本人对源码的相熟水平,能够说Object.defineProperty,能够说Watcher,各个方面开展说一点即可,也能够从一个变量的变动如何渲染到实在的dom下来去论述这个流程,可能分明的说分明就好

44.说一下对vue3.0的理解?
Proxy、CompositionAPI、TypeScript等
45.vue3.0为什么要引入CompositionAPI?
  1. 更好的代码组织,options api造成了代码的跳来跳去
  2. 逻辑复用更加的不便,尽管mixin也可能很好的复用代码,然而当mixin多了当前就不晓得变量哪里来的了,还会造成命名抵触
  3. 没有让人捉摸不透的this
46.双向绑定和vuex是否抵触?
是有抵触的,其实官网上就有解释https://vuex.vuejs.org/zh/gui...
v-model会去批改state的值,然而vuex数据批改又必须通过mutation,这样就抵触了
简略的方法就是不要应用v-model,本人进行数据绑定即可
47.页面刷新后vuex的state数据失落怎么解决?
store里的数据是保留在运行内存中的,当页面刷新时,页面会从新加载vue实例,store外面的数据就会被从新赋值初始化。实践上咱们是不须要长久存储vuex的值的,因为申请咱们会去接口拿数据,进行从新渲染,和第一次进入一样
然而如果非要保留上一次的长期状态,其实能够应用localStorage进行长久化存储,然而这个时候又得去解决和服务端数据同步的问题
48.为啥要有vuex,应用localStorage本地存储不行么?
Vuex 是一个专为 Vue.js 利用程序开发的状态管理模式,Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地失去高效更新。
当多个组件领有同一个状态的时候,vuex可能很好的帮咱们解决
能够很好的应用vue开发者工具调试vuex的状态
这些劣势是localStorage不可能很好的模仿的
50.vue组件里写的原生addEventListeners监听事件,要手动去销毁吗?为什么?
要在 beforeDestroy 手动销毁,否则如果在 mounted 中应用 addEventListeners,可能会多次重复注册导致内存透露。
51.能简略说下你们我的项目代码是如何组织的么?
简略形容下工作中应用的各种我的项目模板,应用的场景是啥样的,模板是怎么组织代码的,这样组织的起因是啥,以及技术选型,单页还是多页,template还是jsx,js还是ts等
52.对于加班你是怎么看的?
适当加班能够了解,适度加班还不给工资不能承受
53.我的项目中有哪些难点,怎么解决的?
每个人遇到的状况都不一样,可能是技术问题,可能是我的项目推动问题,反正啥都说了一些
54.如何治理好本人的我的项目?
从一个产品的姿势去理解我的项目,从一个PM的姿势去跟进我的项目,从一个技术的角度去实现我的项目,从多个方面去形容本人如何去参加到一个我的项目中去,以及我的项目后续的数据跟踪,问题复盘,总结推广等
55.平时怎么写我的项目技术文档,如何进行我的项目复盘的?
平时技术文档都是在相熟理解需要文档的根底下来写,业务流程,技术选型,接口定义(有些前端定,有些后端定,咱们没有太强的归属),而后和后端进行接口对接,定下来交互模式后进行开发
我的项目复盘次要是从我的项目遇到的问题,数据状况等进行复盘,说了挺多的
56.公司前端的根底建设有哪些?本人是否参加过其中的开发?
从本身状况论述吧,是否写过组件库,是否参加过啥啥啥零碎的开发,以及本人的角色
57.团队合作,以前的开发流程?
开放型题目,理论状况理论形容吧

编程题

1.绍防抖节流原理、区别以及利用,并用JavaScript进行实现
防抖 肯定工夫内继续触发是不会反复调用,当超过肯定工夫后再回执行,次要利用在输入框这种中央,当须要查问一个货色的时候,继续输出是不会申请接口
function debounce(fn, delay) {    let timer = null    return function (...args) {        clearTimeout(timer)        timer = setTimeout(() => {            fn.apply(this, args)        }, delay)    }}
节流示意的是不始终触发,肯定工夫触发一次,罕用在滑动滚动或者视窗大小变动的管制
function throttle(fn, delay) {    let start = +Date.now()    let timer = null    return function(...args) {        const now = +Date.now()        if (now - start >= delay) {            clearTimeout(timer)            timer = null            fn.apply(this, args)            start = now        } else if (!timer){            timer = setTimeout(() => {                fn.apply(this, args)            }, delay)        }    }}
2.实现简略的EventEmiter,蕴含事件绑定,事件触发以及移除
class EventEmiter {    constructor() {        this.events = {}    }    emit(event, ...args) {        this.events[event].forEach(fn => {            fn.apply(this, args)        })    }    on(event, fn) {        if (this.events[event]) {            this.events[event].push(fn)        } else {            this.events[event] = [fn]        }    }    remove(event) {        delete this.events[event]    }}const eventHub = new EventEmiter()eventHub.on('test', data => {    console.log(data)})eventHub.emit('test', 1)console.log(2)
3.合并两个有序数组
力扣第88题:https://leetcode-cn.com/probl...,归并排序中的归并步骤拿来用就好了
function merge(left, right) {    let i = 0    let j = 0    const temp = []    while(i < left.length && j < right.length) {        if (left[i] < right[j]) {            temp.push(left[i])            i++        } else {            temp.push(right[j])            j++        }    }    while(i < left.length) {        temp.push(left[i])        i++    }    while(j < right.length) {        temp.push(right[j])        j++    }    return temp}
4.爬楼梯
力扣第70题: https://leetcode-cn.com/probl...,动静布局解题f(x)=f(x−1)+f(x−2)
var climbStairs = function(n) {    if (n <= 2) return n    let n1 = 1    let n2 = 2    let nn = 0    for (let i = 3; i <= n; i++) {        nn = n1 + n2        n1 = n2        n2 = nn    }    return nn};
5.猴子吃香蕉
力扣第875题:https://leetcode-cn.com/probl...
function minEatingSpeed(piles, H) {    let left = 1;    let right = Math.max(...piles);    const canEat = (piles, speed, H) => {        let sumTime = 0;        for (let pile of piles) {            sumTime += Math.ceil(pile / speed);        }        return sumTime <= H;    };    while (left < right) {        let mid = Math.floor((right + left) / 2);        if (canEat(piles, mid, H)) {            right = mid;        } else {            left = mid + 1;        }    }    return right;};
6.lru算法
力扣第146题目:https://leetcode-cn.com/probl...,考keep-alive算法的时候喜爱问
class LRU {    constructor(max) {        this.max = max        this.cache = new Map()    }    get(key) {        const { cache } = this        const value = cache.get(key)        if (!value) return -1        cache.delete(key)        cache.set(key, value)        return value    }    set(key, value) {        const { cache, max } = this        if (cache.has(key)) {            cache.delete(key)        }        if (cache.size === max) {            cache.delete(cache.keys().next().value)        }        cache.set(key, value)    }}
7.二叉树遍历
二叉树的遍历形式有很多种,前序、中序、后序以及档次遍历等,力扣下面都有原题,个别应用递归或者广度优先搜寻即可
// 前序遍历function preorderTraversal(root) {    const result = []    function preOrderTraverseNode(node) {        if (node) {            result.push(node.val)            preOrderTraverseNode(node.left)            preOrderTraverseNode(node.right)        }    }    preOrderTraverseNode(root)    return result};// 档次遍历function levelOrder(root) {    const res = []    function dfs(node, step) {        if (node) {            if (res[step]) {                res[step].push(node.val)            } else {                res[step] = [node.val]            }            dfs(node.left, step + 1)            dfs(node.right, step + 1)        }    }    dfs(root, 0)    return res}

8.回文子串
力扣第647题:https://leetcode-cn.com/probl...
function countSubstrings(s) {    const n = s.length;    let ans = 0;    for (let i = 0; i < 2 * n - 1; ++i) {        let l = i / 2, r = i / 2 + i % 2;        while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {            --l;            ++r;            ++ans;        }    }    return ans;};
9.股票买卖最佳时机
力扣第121题: https://leetcode-cn.com/probl...
function maxProfit(prices) {    const len = prices.length    if (len < 2) return 0    let min = prices[0]    let dis = 0    for (let i = 1; i < len; i++) {        if (prices[i] < min) {            min = prices[i]        }        const disc = prices[i] - min        if (disc > dis) {            dis = disc        }    }    return dis};
10.promiseAll和allSeleted
Promise.all = function(promises) {    const values = []    let count = 0    return new Promise((resolve, reject) => {        promises.forEach((promise, index) => {            Promise.resolve(promise).then(res => {                count++                values[index] = res                if (count === promises.length) {                    resolve(values)                }            }, err => {                reject(err)            })        })    })}Promise.allSeleted = function(promises) {    let count = 0    let result = []    return new Promise((resolve, reject) => {        promises.forEach((promise, index) => {            Promise.resolve(promise).then(res => {                result[index] = {                    value: res,                    reason: null,                }            }, err => {                result[index] = {                    value: null,                    reason: err,                }            }).finally(() => {                count++                if (count === promises.length) {                    resolve(result)                }            })        })    })}
11.实现maxRequest,胜利后resolve后果,失败后重试,尝试超过肯定次数才真正的reject
function maxRequest(fn, maxNum) {    return new Promise((resolve, reject) => {        if (maxNum === 0) {            reject('max request number')            return        }        Promise.resolve(fn()).then(value => {            resolve(value)        }).catch(() => {            return maxRequest(fn, maxNum - 1)        })    })}

欢送关注公众号:前端温习课,一起分享交换前端常识