关于前端:上海莉莉丝米哈游B站小红书得物等互联网公司前端面试总结

1次阅读

共计 10711 个字符,预计需要花费 27 分钟才能阅读完成。

前言

目前在杭州工作,很多敌人都转战上海了,金九银十在敌人的怂恿下,投了上海的几家互联网公司,面试的根本都是中高级前端岗位,面试运气不错根本都拿到 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)
        })
    })
}

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

正文完
 0