2020春招前端面试准备及多家公司面经

1,718 阅读33分钟

这次春招投递了8个公司,两个公司缩招没投进去,有效参加了6家公司的招聘。mihoyo笔试阶段被拒;字节、美团杳无音讯;目前拿到了微软苏州STCA、腾讯WXG、阿里盒马三家Offer。本次经历学到很多,也记录了很多。把记录的内容发出来更多的是为了鞭策自己。

DOM

  1. 获取父亲节点:

    document.documentElement.parentNode; // W3C标准(一个节点可能不是Element Node,此时获取不到parentElement)
    document.documentElement.parentElement; // IE支持
    
  2. meta标签:

    1. name
      • keywords: 网页关键字,针对搜索引擎
      • description: 网页描述,针对搜索引擎
      • viewport: 移动端窗口
      • robots: 定义搜索引擎爬虫的搜索方式
      • author: 标注网页作者
      • copyright: 标注版权信息
      • revisit-after: 搜索引擎爬虫重访时间
      • renderer: 双核浏览器渲染方式(webkit/ ie-comp/ ie-stand)
    2. http-equiv(定义http头)
      • <meta http-equiv="Content-Security-Policy" content="策略">
CSP指令 描述 指令值 描述
default-src 默认加载策略 * 允许任何
script-src 对于JavaScript脚本的加载策略 'none' 不允许任何
style-src 对于样式的加载策略 'self'
img-src 图片的加载策略 data: 允许data:协议
object-src 显示插件来源,如flash URL 允许加载指定域名资源
frame-src unsafe-inline 允许inline资源
media-src unsafe-eval 允许动态js代码
report-uri 请求资源不被允许时,向该地址提交日志
  1. script和link标签 <script src="" type="application/javascript" defer async></script>
    <link href="" rel="stylesheet">rel是当前文档与被链接文档之间的关系
    script最好放在底部,link最好放在头部,为什么? - css加载不会阻塞DOM树的解析,但会阻塞DOM树渲染并且阻塞后面的js语句的执行。 - JS 阻塞 DOM 解析
  2. 移动端白屏问题和解决方法【问题原因(解决方法)】:
    • css加载需要时间,加载过程中是白屏(css代码前置或内联)
    • 首屏无实际内容,等待异步请求数据(首评同步渲染html,后续滚屏再采用异步请求数据)
    • 首屏内联js的执行会阻塞页面渲染(尽量不要在首屏html中放置内联脚本)
  3. SSR(服务端渲染)的优缺点:
    • 优点:首屏渲染快,SEO好
      • SEO好是因为服务端返回的HTML就是已经将数据都渲染好了,而客户端渲染没有数据
      • 首屏渲染快是因为客户端需要下载css js解析,渲染,而下载和解析的时候都是白屏
    • 缺点:
      • 例如Vue生命周期只有到挂载的阶段

DOM事件模型

  1. 基本事件模型

    • 只能注册一个handle事件处理函数
    • docmuent.querySelector('button').<event> = handler
  2. Level2事件模型

    • W3C标准
    • 用addEventListener绑定handler函数
    • 事件捕获 事件处理 事件冒泡
  3. IE事件模型

    • attachEvent detachEvent
  4. Level3事件模型

    • 在Level2上增加了更多的事件类型
    • UI事件,焦点事件,鼠标事件,滚轮事件,文本事件,键盘事件,合成事件,变动事件
  5. 自定义事件模型

    class Event {
    	constructor() {}
    	on(key, fn) {}
    	one(key, fn) {} // 绑定一次性事件
    	off(key, fn) {}
    	emit(key, ...args) {}
    }
    

JavaScript

  1. js的6种数据类型:undefined、null、Boolean、String、Number、Object

    • es6多一个symbol
    • 基本数据类型包括undefined、null、Boolean、String、Number、Symbol
    • 基本数据类型保存在栈内存中,因为基本数据类型占用空间小、大小固定,通过按值来访问,属于被频繁使用的数据。
    • 闭包中的基本数据类型变量不保存在栈内存中,而是保存在堆内存中
  2. 展开与解构:数组解构/对象结构 剩余符... ; 解构符...

  3. 原型链:__proto__.__proto__.___proto___...
    object instanceof constructor (检查object的原型链里有没有constructor)

  4. 箭头函数能保存函数创建时的 this 值,而不是调用时的值

  5. Symbol类型

    let sym = Symbol();
    let obj = {
        [sym]: "value"
    };
    console.log(obj[sym]); // "value"
    
  6. for...of遍历值 for...in遍历健

  7. Polyfill一个Promise:

    class Promise {
       callbacks = [];
       constructor(fn) {
           fn(this._resolve.bind(this));
       }
       then(onFulfilledFunction) {
           this.callbacks.push(onFulfilledFunction);
           return this;
       }
       _resolve(value) {
       		// 宏任务
           setTimeout(() => {
               this.callbacks.forEach(fn => fn(value));
           },0);
       }
    }
    
  8. 数组拍平

  9. 点击穿透:移动端执行顺序 touchstart > touchend > click, click有300ms延迟,如果touchstart绑定callback函数让顶层元素消失,底层元素就会被点到。用tap.js/fastClick.js可以解决。

  10. 事件捕获/事件冒泡: addEventListener(event, func, bool)
    bool是useCaptrue
    bool: true 事件捕获
    bool: false 事件冒泡
    先捕获后冒泡,冒泡兼容性高一点
    阻止: event.stopPropagation() / return false; / preventDefault

    • 三种阻止方式的区别:
      • stopPropagation不会触发传播链
      • preventDefault阻止元素的默认特性
      • return false两者均有(jQuery中)
  11. Object.defineProperty(obj,'name',{}) 为对象obj定义/修改属性

  12. this 永远指向最后调用它的那个对象; 箭头函数它没有自己的this值,它继承外围作用域的this call: 指定函数运行时的this:call(thisArg, args1, args2... ) apply: 和call一样,但是两个参数(thisArg, [args]) bind: 创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,所以说要去手动调用这个函数

  13. 块级变量作用域: 网页 使用var时会有变量提升:变量可以在声明之前使用,值为undefined(let下报错)

  14. Event Loop: 网页 同步 -> 微任务(Promise await后面的代码 process.nextTick[这个直接插入到队列首,而不是尾]) -> 宏任务(setTimeout/setInterval script标签)

  15. 浅拷贝深拷贝:

    • 浅拷贝:
      • obj2 = Object.assign({},obj1)
      • arr2 = arr1.concat()
      • arr2 = arr1.slice()
    • 深拷贝:
      • JSON.parse(JSON.stringify())
      • 递归
  16. Promise:resolve/reject之后不直接执行then/catch,先执行剩下的。

  17. 闭包:

    1.函数嵌套函数; 2.内部函数使用外部函数的参数和变量; 3.参数和变量不会被垃圾回收机制回收。

    好处: 1.希望一个变量长期保存内存中; 2.避免全局变量污染; 3.私有成员的存在。

    坏处: 1.常驻内存,增加内存使用量; 2.使用不当造成内存泄漏。

    (funtion() {
    	let data = {
    		// some data
    	}
    	
    	function funcName(args) {
    		// do something
    	}
    	
    	return {
    		setName: () => {},
    		func: funcName,
    		something: data.something
    	}
    })()
    
  18. 虚拟DOM

  19. Generator:function* func() {let i; while(true){yeild i++;}}

  20. 跨域:设置CORS(跨域资源共享)
    在服务端设置header:

    • Access-Control-Allow-Origin: url,不能写'*'
    • Access-Control-Allow-Methods: GET,PUT,POST,DELETE
    • Access-Control-Allow-Headers: Content-Type 或者jsonp:
    • 利用script标签的src属性实现跨域(只支持get)
    • 通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信
    • 请求一个服务端API,API需要param callback,return的是callback(content)
  21. 事件委托:例如有一个<ul>列表,里面很多<li>,如果每一条li都绑定一个函数则会有很大的内存消耗,可以将事件监听设置在<ul>上,判定点击位置来确定点击的是哪一个<li>。或者事件冒泡,event.target就是最里面的元素。

  22. polyfill es6的class, 包括继承

    function class(props1) {
    	this.props1 = props1;
    }
    
    const _extend = function(sub, sup) {
    	Object.setPrototypeOf(sub, sup); // 设定指定对象的原型
    	sub.prototype = Object.create(sup.prototype); // 拷贝prototype
    	sub.prototype.constructor = sub; // 修改上一步拷贝原型的constructor
    	sub.super = sup.prototype; // super指向父级
    	if(sup.prototype.constructor === Obejct.prototype.constructor) {
    		// 如果原型是Object(继承自Object) sup的constructor就是自己
    		sup.prototype.constructor = sup;
    	}
    }
    
  23. 防抖、节流:

    1. 防抖: 指定时间后触发,在时间内就重新计时。例如双击按钮,监听input去请求ajax
    function debounce(fn, delay) {
    	clearTimeout(fn.id);
    	fn.id = setTimeout( () => {
    		fn();
    	},delay);
    }
    
    1. 节流: 指定时间内触发,只有一次生效
    function throttle(fn, delay) {
    	let last = 0;
    	function work() {
    		let now = +new Date(); // = valueOf(Date());
    		if(last+delay<now) {
    			fn();
    		}
    	}
    	work()
    }
    
  24. currentTarget和target区别:
    currentTarger指向被绑定的元素,target指向触发事件的元素。

Vue

  1. computed缓存答案,依赖不改变就返回缓存

  2. 双向数据绑定:网页
    重写object访问器属性里面的get set方法。

  3. 生命周期:

    # new Vue()
    1. beforeCreate
    # create
    2. created
    
    3. beforeMount
    # Mount
    4. mounted
    ( 
    	beforeUpdate
    	updated
    )
    5. beforeDestory
    6. destroyed
    
  4. 自定义事件: $emit('name',{props}) 事件名不存在任何自动化的大小写转换

  5. VNode: 用虚拟DOM实现

    createEmptyVNode();
    createTextVNode();
    createComponent();
    cloneVNode(vnode);
    createElement(context: Component,
    				tag: any,
    			  	data: any,
    				children: any,
    				normalizationType: any,
    				alwaysNormalize: boolean);
    
  6. MVC和MVVM的区别
    MVC是单向数据流,只有从数据到视图,视图回到数据要靠控制器中转。
    MVVM则是靠一个双向的VM层进行UI和数据的双向同步。将后端传输的数据转化为所看到的页面是通过数据绑定。

  7. 看过源码吗?介绍一下Vue底层。 使用了装饰器模式、观察者模式、策略模式的设计模式。新建一个Vue实例的时候会用装饰器模式,把Mixins挂载到Vue原型上。在initState时对props,methods,data,computed,watch进行初始化。在此之前之后分别调用beforeCreate和created生命周期钩子。然后每个组件都会对应一个observer,如果数据变动了就会通知observer,使用vdom-diff、patch算法更新渲染dom节点。Vue其中还有双向数据绑定,是通过Object.definePropety改写obj访问器属性的get set方法实现的。

Vue-router

<keep-alive>
	<router-view :key="$route.fullPath+localUserId"/>
	<!-- key 可以让keep-alive更新的时候根据“key不同就更新”来更新或避免更新-->
</keep-alive>
<routre-link :to="" />
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const routes = [{
	path: '',
	redirect: '/main'
},{
   path: '/status',
   component: submitdetail,
   props: (route) => ({
       pid: route.query.p,
       sid: route.query.s
   }),
   meta: {
       isLogin: true
   }
},{
   	path: '/problem'
   	children: [
   		{
   			path: '/123',
   			component: ''
  		}
   	]
},{
   path: '*',
   component: page404,
   meta: {
       isLogin: false
   }
}];
  
   var router = new VueRouter({
   		mode: 'history',
    	routes: routes
	});
	export default router;
	$router.path // 路径
	$router.fullPath // 全写路径

	$router.push('home')
	$router.push({ path: 'home' })
	$router.push({ name: 'user', params: { userId: '123' }})
	$router.push({ path: 'register', query: { plan: 'private' }})
	
	$router.replace() // 不会向history添加记录
	
	$router.go(<number>) // 倒退,前进
	
	router.beforeEach( (to, from, naxt) => {
		// do something
		to.mate.??? // 检测标签
		next() // 继续
	})
	
	router.afterEach( route => {
		// do something
	});
  • hash路由和history路由的区别:

    • hash模式用window.onhashchange去监听改变页面,参考的是url #后面的字段
    • history是在HTML5 history API出现以后
    • history模式下要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
  • abstract路由是使用一个不依赖于浏览器的浏览历史虚拟管理后端

实现路径

Vuex

使用单一状态树

  1. State:

    • 储存数据
    • mapState: 可以帮助生成计算属性computed: mapState({func: () => {}})
  2. Getter:

    • 从State里面组织数据返回,类似于MySQL的视图、还有Computed
    • getter的返回值会根据它的依赖被缓存起来,只有当它的依赖值发生了改变才会被重新计算
    • ...mapGetters('<module>',{})将getters映射出来使用
  3. Mutation:

    • 更改Vuex中state的唯一方法是commit mutation,mutation就是变更状态的方法:mutations: { func(state,args...) {} }
    • 提交载荷(Payload),即提交Mutation所传入的参数:store.commit('func',payload)
  4. Action:

    • 类似于mutation
    • Action提交的是mutation,而不是直接改变状态
    • Action可以包含异步操作
    • 通过dispatch触发
    • 在组件中分发actions: ...mapActions([])可以映射为store.dispatch使用
    actions: {
        func(context) {
        	context.commit('<mutation>')
        }
    }
    
    store.dispatch('func', args...)
    
  5. Module

单向数据流

plugin

  1. install方法:
install(Vue, options) {
	// 使用基础 Vue.extend 构造器,创建一个“子类”
	const plugin = Vue.extend(pluginComponent)
	// 创建一个 plugin 的实例 profile 挂载到一个HTMLElement实例上
	const profile = new plugin({el: document.createElement('div')})
	
	appendchild(profile.$el) // mount
	// 处理options...
	
	// 定义plugin方法
	Vue.prototype.$plugin = plugin方法 // 挂在vue原型上面
}

React

  1. 生命周期
    • componentWillMount
    • componentDidMount
    • componentWillUnmount
    • componentWillUpdate(可以用来解决props改变而带来的副作用)
  2. 为什么用setState而不直接更改state?在Vue里面监听值来实现双向绑定,但是对引用类型支持的不好,为了解决这个问题而使用setState。setState是异步的,用队列机制更新state,来创建/修改虚拟DOM。

Webpack

  • 入口entry、loader、plugin、出口output
  • webpack由node编写,只识别js。通过loader可以加载识别别的文件。text指定文件后缀regex,还可以指定用的加载器。
  • 常用plujin:
    • UglifyJsPlugin: sourceMap要关上, compress参数指定是否忽略console和//
    • CompressPlugin: 静态资源压缩,还可以指定是否删除原文件

CSS

  1. translate3d?

  2. 虽然margin可以应用到所有元素,但display属性不同时,表现也不同

    1. block元素可以使用四个方向的margin值
    2. inline元素使用上下方向的margin值无效
    3. inline-block使用上下方向的margin负值看上去无效

    inline-block使用上下方向的margin负值只是看上去无效,这与其默认的vertical-align:baseline有关系,当垂直对齐的属性值为其他值时,则会显示不同的视觉效果 参考链接

  3. filter:drop-shadow()

  4. 盒子模型:从外到内是:margin->border->padding->content

  5. 竖着排列文字:write-mode: vertical-lr (IE下tb-lr)

    • 字体横行竖列呢? transform: rotate(90deg)
  6. ~运算符,从哪到哪 第二个参数只能是同级或者子级,不能回到父级

  7. direction: rtl(right to left) ltr

  8. css兼容:-ms- -moz- -webkit- -o-

  9. px, em(font-size), rem(相当于根元素的em), %(相对于父元素), vw(视窗宽度%), vh(视窗高度%), vm(视窗min(width,height)%)。除此之外还有in,cm,mm,t:point,pc:pcia

  10. 为什么给body设置font-size是62.5%:16px*62.5%=10px,这样1em是10px,2em是20px方便计算。

  11. 优先级:ID选择器(100) > 类选择器,属性选择器,伪类(:hover)(10) > 类型选择器,伪元素(::before)(1); 通配选择符,关系选择符,否定伪类对优先级没有影响。内联样式有最高优先级(1000)。!import比内联还高。 网址 css权重计算

Flex

  1. flex可选择1~3个参数

    flex: flex-grow<number> | flex-shrink<number> | flex-basis<width>;
    flex: 2 2 30px;
    flex: auto;    /* flex: 1 1 auto; */
    flex: initial; /* flex: 0 1 auto; 根据自身宽高设置尺寸,缩小但不伸长 */
    flex: none;    /* flex: 0 0 auto; */
    

    Ps. 是无单位数,是带单位宽度 双值语法

    • 无单位number:
    • 有效宽度值width:
  2. 默认情况下,元素不会缩短至小于内容框尺寸,若想改变这一状况,要设置元素的 min-width 与 min-height属性

  3. flex-flow: <flex-direction> | <flex-wrap>

  4. flex-direction: row | row-reverse | column | column-reverse

  5. flex-wrap: nowrap | wrap | wrap-reverse

  6. order: <integer> /*表示此可伸缩项目所在的次序组*/

Grid

  1. grid语法:
grid: <'grid-template'> |
<'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>? |
[ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>
  1. grid-template: 其包含 grid-template-columns,grid-template-rows 和 grid-template-areas
  2. grid-template-column:
  3. grid-template-row:

BFC

  1. BFC(block formatting context)(块级格式化上下文)

  2. 元素内形成BFC环境的条件(关系:或):

    • 根元素
    • float不是none
    • overflow不是visible
    • display是inline-block/table-cell/table-caption
    • position是absolute/fixed
  3. 在块格式化上下文中,从包含块的顶部开始,垂直地一个接一个地排列block

  4. 垂直方向上的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠

    • 上下相邻的两个元素;父元素与子元素的margin发生重叠
    • 上下相邻的情况下用加float属性来消除重叠
    • 如果父元素的margin-top为0,padding-top为0,没有border,而子元素的margin-top不为0,那么父元素距离上方的距离就会是子元素margin-top的值,margin-bottom同理
    • 消除父子margin重叠:给父元素加border,设置父元素的padding或者margin,给父元素添加overflow:hidden
  5. overflow: hidden下bfc的区域不会与float的元素区域重叠

  6. 计算bfc的高度时,浮动元素也参与计算

    <div class="main">
    	<div></div>
    	<div></div>
    </div>
    <style>
    .main {
      background: deepskyblue;
      /*position: absolute; 加上这句才会形成BFC才会撑开父级元素*/
    }
    .main div {
      height: 100px;
      width: 100px;
      float: left;
    }
    </style>
    
  7. BFC的可利用点:清除浮动的影响;清除margin重叠

算法

  1. 手写快排(为什么要把第一个作为基准值):网页 应该用random的位置作为基准值,防止被特殊数据卡。选择第一个或者最后一个会被已经排好序的数据卡掉。随机选取三个元素,并用它们的中值作为整个数据中值的估计值。或者选择最左端,最右端和中间位置的三个元素的中值作为基准。
  2. 红黑树:自平衡二叉查找树
    • 根节点黑色
    • 叶子节点都是黑的
    • 如果一个节点是红的,那么他的两个子节点都是黑的
    • 对任意节点来说,到叶子节点的每个路径黑节点数量相同 这五个性质使一棵n个结点的红黑树始终保持了logn的高度

SaSS

  • @mixins @include

TypeScript

  1. 指示类型符:

  2. 接口interface(可选属性?;readonly只读属性)(Array<>,ReadonlyArray<>,any)

  3. function:never必须有不可达终点 or Error

  4. enum color {black=1,yellow,green=4}

  5. 当作属使用则用readonly,当作变量使用则用const

  6. 断言<>/as

  7. interface额外属性:

    interface SquareConfig {
        color?: string;
        width?: number;
        [propName: string]: any;
    }
    
  8. 枚举的反向映射

    enum Enum {
        A
    }
    let a = Enum.A;
    let nameOfA = Enum[a]; // "A"
    
  9. 为了支持CommonJS和AMD的exports, TypeScript提供了export =语法。export =语法定义一个模块的导出对象。 这里的对象一词指的是类,接口,命名空间,函数或枚举。若使用export =导出一个模块,则必须使用TypeScript的特定语法import module = require("module")来导入此模块。

  10. 三斜线指令。/// <reference path="..." />指令是三斜线指令中最常见的一种。它用于声明文件间的依赖。三斜线引用告诉编译器在编译过程中要引入的额外的文件。

网络/安全

  1. XSS(跨站脚本攻击),避免:敏感字符替换,包括javascript:标签
  2. http缓存:cache-control:
    • private(default)客户端缓存

    • public 缓存服务器缓存

    • max-age=xxx xxx秒后过期

    • no-cache 对比缓存

    • no-stroe 不缓存,强制缓存和对比缓存都无效。

    • 脚本缓存在memory cache,静态资源在diskcache

    • 首次请求没有缓存,会根据参数设置,向服务器请求缓存,与服务器协商缓存。

    • 再次请求如下图:

    1. 强缓存
      • max-age=xxx
      • public(客户端和代理服务器均缓存)
      • immutable(刷新的时候不要去请求服务器)
    2. 协商缓存
      • etag 文件hash 用来对比文件师是否改变
      • last-modified 文件修改时间,精确到s
  3. http2和http1的区别:
    • 二进制传输:将请求和相应数据分割为更小的帧,用二进制编码。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装
    • header压缩:HPACK压缩。首部表,每次更新差异数据。
    • 服务端推送:在浏览器刚请求html时就把JS、CSS推送到客户端,减少延迟。
    • 多路复用:同域名下所有通信可以在单个连接上完成,单个链接可以承载任意数量的双向数据流。
    • 安全性加强:跑在TLS上面
  4. TCP拥塞控制:
    拥塞控制是防止过多的数据注入网络,使得网络中的路由器或者链路过载。流量控制是点对点的通信量控制,拥塞控制是全局网络流量的整体控制。发送双方都有一个拥塞窗口cwnd
    • 慢开始:最开始发送方cwnd=1,由小到大逐渐增大发送窗口和拥塞窗口。每经过一个传输轮次,拥塞窗口cwnd加倍。当cwnd超过慢开始门限,则使用拥塞避免算法,避免cwnd增长过大。
    • 拥塞避免:每经过一个往返时间RTT,cwnd就增长1。 在慢开始和拥塞避免的过程,一旦发现网络拥塞,就把慢开始门限设为当前值一半,重新设置cwnd为1,重新慢启动。(这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕)
    • 快重传:接收方每次收到一个失序的报文段后就立即发出重复确认,发送方只要连续收到三个重复确认就立即重传。
    • 快恢复:当发送方连续收到了三个重复确认,就乘法减半(慢开始⻔限减半),将当前的cwnd设置为慢开始⻔限,并且采用拥塞避免算法(连续收到了三个重复请求,说明当前网络可能没有拥塞)。
  5. RESTful
    1. 协议。经常使用https。
    2. 域名。部署在专用域名之下api.example.com或者example.com/api/
    3. 版本。api.example.com/v1/
    4. 路径(终点)。表示API的具体网址
    5. HTTP动词。GET POST DELETE PUT PATCH
    6. 过滤信息。
    7. 状态码。
    8. 错误处理。如果状态码是4xx就返回错误信息。
    9. 返回结果。
    10. Hypermedia API
    11. API身份认证应该使用OAuth 2.0框架
    12. 数据格式尽量使用json
  6. CSRF(Cross-site request forgery, 跨站请求伪造)
    • XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任
    • 防御
      • 关键操作(例如非幂等操作)使用POST方法
      • 关键操作上加验证码增加和用户的交互
      • 验证referer
      • token验证(服务端渲染),如果是前后端分离式,那么就在每一次请求的时候发放下一次的token,第一次请求来鉴权

通常提问

  1. 项目中遇到的困难,如何解决的
  2. 介绍一下项目核心内容

“你还有什么问题问我们吗?”

  1. 通过这次面试,在您看我还有什么可以提高的地方,不足是什么?(面试情况有没有达到您的期望)(少问,有的面试官不喜欢听到这个问题)
  2. 平常公司前端岗位的技术栈/常用框架是什么呢?

面经

阿里盒马

内推提前批,投递简历第二天就收到了一面面试电话。

一面电话面

问的问题比较多,涉及到的知识面也比较宽泛。可能和我的简历有关吧,阿里教我做人。面试官很和善,面试了30min。

  1. 自我介绍一下吧

  2. 先说一下你在大学里做过哪些项目

  3. HTTP2和HTTP1的区别是什么?

  4. 设计一个登陆页,应该用HTTP的什么Method去提交请求?除了用Post,在传输的过程中还要注意什么?

  5. 如果用户没有登录就去访问一个有登录限制的网页,应该返回什么状态码?(应该是401,403是登录但没有权限拒绝服务)

  6. 了解restful吗?介绍一下

  7. HTTPS为什么比HTTP安全?

  8. 在写html时script和link标签的位置会刻意放在开头或结尾,这是为什么?

  9. 设计一个三栏式页面,左边栏和右边栏固定200px,中间可以缩放,你怎么实现?

  10. 实现一个旋转的loading动画

  11. 在使用promise时如何处理错误?(.catch)除了.catch呢?

  12. 如何串行的调用a(),b(),c()三个function,用Promise怎么写?并行呢?

  13. 介绍一下后端开发中常用的框架

  14. 解释一下MVC?MVC和MVVM的区别?

  15. Vue中更改了一个数据,到更改渲染到页面上,经历了哪些步骤(回答的双向绑定和虚拟DOM-diff的相关内容)

  16. 假设有一个树形Object,存储着好几层、不同的数据内容。设计一个搜索Object的算法,在尽可能快的情况下找出所有和关键字有关的内容(吐血,好难,这啥,不会)

  17. Polyfill一个class(用es5的内容实现es6的class,包括继承之类的)(回答的闭包+原型链,但是忘了如何用原型链实现继承了)

  18. 看如下代码,输出

    new Promise( resolve => {
    	resolve();
    }).then( message => {
    	console.log("hello");
    	setTimeout(() => {
    		console.log("world");
    	}, 0)
    })
    

笔试

笔试是一面完当天做的,一共两道题,2hours,到最后第二道题差一点调试完。

  1. (基础版)给你一段xml,xml标签中没有attribute,结构单一,不存在标签不匹配。把它解析成json(json格式已经给定),用js实现。

    <list>
      <item>content1</item>
      <item>content2</item>
      <item>content3</item>
      <item>
        <name>hema</name>
        <value>frontend</value>
      </item>
    </list>
    
    {
      tag: 'list',
      children: [
        {
          tag: 'item',
          children: 'hello world'
        },
        {
          tag: 'item',
          children: 'content2'
        },
        {
          tag: 'item',
          children: 'content3'
        },
        {
          tag: 'item',
          children: [
            {
              tag: 'name',
              children: 'hema'
            },
            {
              tag: 'value',
              children: 'frontend'
            }
          ]
        }
      ]
    }
    
  2. (增强版)xml中携带attr,时间复杂度要求O(n),异常处理:针对标签未闭合情况, 能报出异常信息

二面电话面

一面完成后的第三天晚上收到面试通知,第四天下午两点面试。

  1. 为什么选择了前端这个岗位
  2. 你刚才提到了前端的新技术的产生是比较快的,从你开始学到现在,你接触了哪些新的东西
  3. 讲一下你笔试的时候的思路吧,你的代码为什么这样写
  4. 介绍一下你印象最深的项目吧,为什么对这个项目印象深刻
  5. 你提到了Vue的一些原理性的东西,你能具体介绍一下吗?
  6. 能详细说明一下computed计算属性缓存是怎么设计的吗?为什么要这样设计? 然后就开始从这个项目出发问了一系列的问题:你现在写到的xx系统,前端后端数据库都是怎么设计的?如果让你设计某一个系统,在前端、后端、数据库方面,你怎么来设计?
  7. 你还有什么问题问我们吗?(部门的常用技术栈有哪些?)
    答:阿里是React的天下,Vue用的比较少,平常会用weex之类的写pc、app给中后端使用,前端消费者使用的是另一个部门开发的。

三面电话面

二面完成之后的第三天下午,24min

就是大致讲一下OnlineJudge项目的核心部分,不一定是前端,后端之类的都可以。然后让我好好准备后面的四面、交叉面和hr面

四面电话面

短信预约的,在提前批面了三面之后终于入了系统,做了素质测试后一星期收到四面面试短信

还是聊项目,每个功能可能问的比较深,会问到一些关于上线之后生产环境的隐患问题有没有考虑。再就是问了感兴趣的方向,对于团队的技术栈有没有什么期望。一共45min左右。

五面交叉面 电话面

音质有点不好,听起来比较费劲

感觉从三面开始,或者说从二面开始的内容就差不多一样了,没有什么特别问题,就是一直在聊项目,询问技术栈之类的。时常30min左右。

美团点评

内推提前批,投递简历两天后面试官联系,一周后开始一面。

一面电话面

面试官很好,没有问的很紧,每个问题之间会有一定的缓和时间,一共持续了20min。上来表明希望招到的都是能留下来工作的,问了大四能不能在那里实习。这次面试就是提前了解一下情况,因为是提前批,后面招聘正式开始后会按照正常的流程再走一遍。

  1. 基础的了解情况,介绍自己项目,实习时间,Vue、ts、node、webpack以及后端语言的掌握情况
  2. css布局去实现一个九宫格布局(每行最多三列,wrap的向下排)
  3. 介绍一下DOM事件模型
  4. 考察事件委托,为什么使用事件委托
  5. es6的map类型使用过吗?那你平常用es6的哪些语法?
  6. 你还有什么问我们的问题吗?(部门用到的技术栈是什么?Node是必需的吗?)
    答:vue和react都用到,自己的部门用react比较多,平常我们还会用js的相关内容去开发移动端app之类的。自己的部门全员node,但是对于实习来说不是必须的。

笔试

笔试开始前五天收到通知,说要五天后晚上7:00笔试,笔试是统一的在赛码(好像是叫这个网站)上,要开摄像头什么的。

不允许泄题,那就不说题目是什么了,总之算法题型,然后做得也不好最后估计只有36分左右(满分100)。 整体难度的话:ACM铜及以上吧。

二面视频面

笔试之后大概一个星期

就是一些开放性问题,聊项目啊之类的,个人性格之类的。比较特别的问题有以下几个:

  1. js的垃圾回收机制了解过吗?没了解过的话你类比c++的垃圾回收机制,你猜测以下他是什么样一个机制,或者说让你去设计一个js的垃圾回收机制的话你怎么去设计
  2. 前端一直使用js,但是为什么最近开始ts了呢?你认为公司为什么会去倾向使用js
  3. 你在项目里用sass的场景是什么,用到了哪些内容
  4. 关于oj ranklist页面的开发聊了比较多,比如vue生命周期,轮询,在beforeMount处理数据的时候用户会看到一个白屏,你怎么去提升用户的体验。
  5. 值得一提的是我最后问部门是一个什么样的技术栈,除了常用的前端技术栈外,居然还有java、mysql、redis的技术栈

腾讯微信公众号

内推,投递简历第二天联系了笔试。我投的腾讯音乐,结果是WXG的人来找我

笔试

腾讯文档上面一个word上面写,4个题,一个小时

  1. leetcode原题第二题
  2. 给一棵不完全二叉树,每个节点都有一个值。不能拿相邻节点的值,问在这棵树上最大能拿多少
  3. 树的diff,html解析能否用上述算法,优化方案是什么
  4. leetcode原题,两个有序序列二分找中位数

一面电话面

笔试完了接着打电话过来一面了,1hour,面试官感觉还可以,会引导你去想一些问题,每个问题刨根问底也问的比较深

  1. 回顾一下刚才笔试的四个题,为什么这样做,你写的算法缺点在哪里,怎么改进
  2. 自我介绍一下
  3. 什么时候接触前端的?你前端是怎么学的,有没有系统的听过课或者看过书来学?
  4. 你简历上写了很多东西,你最常用的是什么?(Vue)
  5. Vue的双向绑定,如果for i in range(0,100)改变a,那么{{a}}里面是怎么渲染的。
    答:可能只看到99
    如果让你来写你怎么让他只看到99
    答:防抖
    那么如果你是框架设计者,我是框架使用者,我就是想让用户看到0-99变化的这个过程,你该怎么改变你的框架?你这里掌握的不太好,你回去再看一下
    (后面看了一下,这是“异步更新队列”。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。用宏任务可以让页面出现变化的过程。因为宏任务不会接着执行下一个宏任务,中间穿插了对页面的渲染。)
  6. Vue-router是怎么实现的?
  7. 假设两个组件a和b,我从a->b,这个时候我又点了一下回退,返回到了a,这里需要注意什么?
  8. 针对上个问题,给个业务场景,这个页面很长,用户滚动条拖的很下面,你怎么保证返回的时候能重新定位在这里?(把scrollTop存下来,返回的时候卡看有没有相关的存储,有的时候设置一下scrollTop为存储值)那你存储用什么样的数据结构去存储?Vue-router你还需要再了解学习一下
  9. 你有没有看过Vue源码,讲一下你看过的部分
  10. SaSS和TypeScript,React掌握的怎么样?
  11. 问一个CSS,用一个div和css画一个等腰直角三角形
  12. 再问一下浏览器相关,从在浏览器里面输入一个URL到看到界面,发生了什么?(网址
  13. 针对上个问题,详细说一下DNS?DNS服务器在哪里?
  14. 一个html页面,head里面有10个css,页面底部10个js,每个下载都需要10s。下载完css多长时间?下载完js多长时间?
  15. 从服务器返回到浏览器解析这一部分,详细说一下。服务器怎么保证返回的是浏览器想要的?(nginx)那么假设nginx出了bug,返回了一个视频/图片,浏览器是否能解析它?浏览器怎么检测这个文件是什么类型的?
  16. 上面说的20个文件,在http1.1下简历了多少个tcp链接?你http这一块不太好回去好好学
  17. 安全问题接触过吗?XSS和CSRF?(了解过XSS)
  18. 详细说一下XSS,为什么会出现XSS问题,怎么防范?
  19. 你的项目里是如何请求内容的?XHR用过吗?Ajax用过吗?jQuery用过吗?你怎么避免你用的fetch的兼容性问题?
  20. es6里面的module用过吗,如果让你生成一个依赖关系,你怎么写?
  21. 学校里都学了什么课程?英语怎么样?数学怎么样?说一下操作系统的段存储和页存储?
  22. 编译原理说一下什么是词法解析什么是语法解析?说一下你写过的XML解析器是怎么写的
  23. 你linux和类linux的操作系统的命令掌握的怎么样?
  24. 我看你博客大多都是算法竞赛内容,为什么?说一下常用的排序有哪些?介绍一下希尔排序?
  25. 我看你博客里面写了想考研?(不不不,现在不想)
  26. 说一下你觉得你的优势在哪里
  27. 说一下你的兴趣爱好?

第二次笔试

好神奇,也没有换部门,一面笔试完了二面又带个笔试。一面完之后两天给通知,约第三天下午笔试+面试。

  1. 将字符串解析一个成一个整数(32位,保证输入合法),如果溢出返回0
  2. 快速排序,讲一下复杂度
  3. 两个二叉树合并为新的二叉树
  4. 给一个数组,将数组向右移动k个位置,用尽可能多的解法
  5. leetcode原题,一段字符串,求最长不重复子序列,只要长度。

二面电话面

面试之前还进行了第二次笔试

  1. 看了一下笔试内容,讲一下笔试。针对第2题讲一下怎么去避免最差时间复杂度(没答上来),针对第4题引导了一个新的解法
  2. 介绍一下自己
  3. 你有过acm经历是吧,你说一下你acm获奖情况,在队伍里都承担什么任务?
  4. 那你说一下图论的相关内容吧
  5. 讲一下Vue的特性
  6. Vue的双向绑定以及观察者模式
  7. Vue的异步更新队列(我说上个面试官问了,没答上来,下去看了一下,把下来看的内容给他讲了一下
  8. 那你说一下上个面试官还问了什么问题你没答上来下去又看了的
    (答:一个页面十个css十个js那个
  9. 上个问题涉及到了计算机网络的http,深究了一些http的东西。
  10. 介绍http2和http1的区别
  11. tcp的拥塞控制
  12. http1下,有多个小图片,你怎么去优化(雪碧图
  13. 说一下你在学校里学了什么课程,什么最有把握,我说操作系统和编译原理
  14. 问了一些操作系统的问题(一个都没答上来
  15. 那这样吧你自己讲一个操作系统的点(讲了个页面储存替换算法
  16. 你还有什么问题问我吗?
    (部门技术栈是什么?
    答:你通过了的话让后面的面试官给你讲吧,我不是前端组的,不是很了解

HR视频面

二面当天十几分钟后系统就显示通过了,三天后接到HR面试邀请,第四天下午进行视频面试,平台是腾讯会议。

就聊了一下性格、爱好、学校内做的一些事情,现在的状况,实习的安排,没有什么特别值得说的。然后说下周会有offer的沟通,保持电话畅通。

字节跳动

投的前端开发实习-教育业务,从暑期实习被调到日常实习,但是不知道区别是什么,影响不大

一面视频面

投递简历一星期后收到电话,约第三天下午视频面试,平台是牛客网。

总体来说,一共接近一个小时,体验很好,但是觉得自己回答的不太行,猜测是一面挂。期间牛客网评测出现了一次问题,调了半天代码没动静,还以为是我写的问题。

  1. 介绍自己,为什么选择前端,写过什么项目?
  2. 说一下tcp,udp的区别和分别的使用场景
  3. 从输入url到展示页面有哪些过程用了udp
  4. https有了解吗?介绍一下如何交换密钥
  5. 说一下get和post的区别
  6. 介绍一下tcp的三次握手四次挥手,为什么要三次握手、四次挥手?
  7. http的keep-alive见到过吗?(见到过,但不会)那http状态码有哪几种?
  8. 301,302的区别?304是什么?
  9. 说一下协商缓存
  10. 说一下es6的数据类型(一紧张忘记了一个Boolean)
  11. 实现一个判断是不是Array的function
  12. 实现一个判断是不是空Object的function
  13. 实现一个数组拍平(这里牛客网评测机坏掉了)
  14. 实现一个regex风格替换function(<%= 123 %>替换为{{ 123 }},不太会regex没写出来)
  15. 实现一个debounce(突然就忘记怎么写了,干)
  16. 闭包接触过吗?介绍一下闭包的特点和缺点?有什么使用场景?介绍一下你自己写过的闭包
  17. 你平常http请求用什么?(fetch)
  18. 能自己实现一个fetch吗?(???完全不会)
  19. 那你能给fetch加一个abort函数吗,终止请求(???)
  20. 那你了解Promise的all和race嘛?你能自己实现一个Promise.race嘛?
  21. 介绍一下css盒模型
  22. 说一下box-sizing各个参数和含义
  23. 说一下html有哪些语义化标签(nav,footer之类的,没用过)
  24. 实现一个add(leetcode第二题原题)
  25. 序列化一个json,序列化为数组,每个数组元素要携带层级
  26. 你实习能实习多长时间?从什么时候开始?
  27. 你还有什么问题问我吗?(技术栈:react,有的业务部门用node)

米哈游

笔试

第一批笔试,依旧不允许外传题目。做的不理想有点崩溃。

微软苏州STCA

内推,没有笔试 面试流程据说是IC1、IC2任何一轮通过都会进入到Lead面,然后Offer

IC1面视频面

视频面,平台是Ms Teams,但是面试官不开视频。然后就聊了几个问题,就开始写题,题目是在线平台上写的,只能用plain text,没有高亮不能编译,但是要尽可能的去保证能编译通过并运行。面试官说话中英混杂,据说因为很多同事不说中文。

  1. 自我介绍
  2. 你在大学里做了什么项目,项目的难点是什么,怎么克服
  3. 洛谷P1434滑雪 dfs+记忆化,要求一次性实现最优解
  4. 滑雪·改,改成一维,要求时间O(n),但不允许用额外空间
  5. 你有什么问题吗?
    问:实习的内容,技术栈
    答:(含义查不多,具体怎么说的记不清了)Intern期间大概率给一个额外的Project,这个Project也会很有challenge。不会去触碰业务线上的项目,因为出一个错误就损失几个亿...技术栈的话很多,做什么的都有。

Lead面视频面

收到面试邀请邮件,邮件上写的Philippines, Manila,不是China就很恐怖,很怕是英文面. 结果是English的introduce yourself,其他都是中文

  1. introduce yourself
  2. 随机向BST中插入N个random数,返回根节点
  3. checkBalance函数
  4. 写个函数让他平衡,可以使用额外空间
  5. 如果不使用额外空间怎么做?有几种情况?
  6. 有什么要问我的吗?