一、JS
数据类型
JS数据类型分为两大类:基本类型、对象类型
-
有哪些基本类型(7种)?
- null
- undeined
- number
- string
- boolean
- symbol
- biginit
-
有哪些对象类型(2种)?
- Object
- Function
作用域和闭包
理解困难先看这里:彻底理解js作用域和闭包
-
全局对象是什么?
浏览器环境下是window、node环境下是global(js引擎会把所有<script>标签整合到一起,生成一个GO对象)。
-
讲讲你对闭包的理解(概念和作用)?
概念:当内部函数使用外部函数的变量,就会形成闭包。闭包是当前作用域的延伸。
作用:在函数外部访问私有变量、实现封装、防止污染全局变量
-
this的规则(要求能理解)
一共有四种指向情况:
- 默认绑定:指向全局对象(window);
- 隐式绑定:函数被对象调用时,指向该对象;
- 显式绑定:通过调用call()、apply()、bind()方法,使this指向新对象;
- new绑定:通过构造函数调用,使this指向构造出的新对象。
目的:区别这四种情况下的this指向。
-
有哪些改变this指向的方法?
apply、call和bind
-
apply、call和bind的用法和区别?
作用:方法重用,一个对象可以使用另一个对象的方法。
区别(重要!):call多个参数用逗号分隔,apply多个参数使用数组接收、bind同call,但是返回的是函数。
详细说明:
-
箭头函数和普通函数的区别?
- 箭头函数里的this永远指向父级作用域;
- 无法使用显式、隐式绑定改变this指向;
- 不可以作为构造函数使用,即不能使用箭头函数实例化;
-
以下代码的执行结果(掌握以上内容即可理解答案)
var name = 'window' var obj1 = { name: '1', fn1: function() { console.log(this.name) }, fn2: () => console.log(this.name), fn3: function() { return function() { console.log(this.name) } }, fn4: function() { return () => console.log(this.name) } } var obj2 = { name: '2' }; obj1.fn1(); obj1.fn1.call(obj2); obj1.fn2(); obj1.fn2.call(obj2); obj1.fn3()(); obj1.fn3().call(obj2); obj1.fn3.call(obj2)(); obj1.fn4()(); obj1.fn4().call(obj2); obj1.fn4.call(obj2)(); // "1" // "2" // "window" // "window" // "window" // "2" // "window" // "1" // "1" // "2"
事件循环
理解困难先看这里:2分钟了解 JavaScript Event Loop、 事件循环(Event Loop)
-
简单描述一下事件循环?
JavaScript是一种单线程的编程语言,为了解决单线程运行阻塞问题,JavaScript用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop)
-
执行顺序
- 先执行同步代码,
- 遇到异步宏任务则将异步宏任务放入宏任务队列中,
- 遇到异步微任务则将异步微任务放入微任务队列中,
- 当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,
- 微任务执行完毕后再将异步宏任务从队列中调入主线程执行,
- 一直循环直至所有任务执行完毕。
-
有哪些你知道的宏任务?
- setInterval()
- setTimeout()
- script
- setImmediate
- I/O
- UI rendering
-
有哪些你知道的微任务?
- Promise.then()
- new MutaionObserver()
- MutationObserver
-
以下代码的执行结果
console.log('1'); setTimeout(function() { console.log('2'); new Promise(function(resolve) { console.log('3'); resolve(); }).then(function() { console.log('4'); }) }) new Promise(function(resolve) { console.log('5'); resolve(); }).then(function() { console.log('6'); }) setTimeout(function() { console.log('7'); }) setTimeout(function() { console.log('8'); new Promise(function(resolve) { console.log('9'); resolve(); }).then(function() { console.log('10'); }) }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12'); }) console.log('13'); // "1" // "5" // "11" // "13" // "6" // "12" // "2" // "3" // "4" // "7" // "8" // "9" // "10"
类、对象和原型
-
描述一下原型链
其实就是描述实例、构造函数、原型之间的关系
-
手写任意一种原型继承
// 寄生组合式继承: function Parent() {} // 父类 function Child() { // 子类 Parent.call(this) // 继承实例上的属性 } Child.prototype = Object.create(Parent.prototype, { constructor: { value: Child } }) -
你知道哪些判断数据类型的方式?
- Object.prototype.toString.call()(最优)
- instanceof(无法判断原始数据)
- typeOf(无法判断null、array等Object类型)
-
instanceof的原理和缺点?
从原型链上判断一个值是否是一个原型的实例
缺点:无法判断原始数据、所有对象的instanceof Object都是true
其他
-
简述并实现节流和防抖
防抖
说明:一段时间内,函数被触发多次,但是只执行一次并执行最新的(将多次执行变为最后一次执行)
实现:每次触发重新开始计时。
function debounce(fn) { let timeout = null; // 创建一个标记用来存放定时器的返回值 return function () { clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉 timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数 fn.apply(this, arguments); }, 500); }; } function sayHi() { console.log('防抖成功'); } var inp = document.getElementById('inp'); inp.addEventListener('input', debounce(sayHi)); // 防抖节流
说明:当持续触发某个事件时,会有规律的每隔一段时间就执行一次函数(将多次执行变成每隔一段时间执行)
实现:每次触发,设置一个开关标记,第一次触发将开关关闭,并延时执行目标函数,目标函数执行完后再次打开开关。
function throttle(fn) { let canRun = true; // 通过闭包保存一个标记 return function () { if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return canRun = false; // 立即设置为false setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中 fn.apply(this, arguments); // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉 canRun = true; }, 500); }; } function sayHi(e) { console.log(e.target.innerWidth, e.target.innerHeight); } window.addEventListener('resize', throttle(sayHi)); -
列举深拷贝和浅拷贝的方法
浅拷贝:Object.assign、扩展运算符(
b = {...a})深拷贝:JSON.parsInt(JSON.stringify(obj)、递归
-
数组去重有哪些方法?
- ...new Set(arr)
- arr.filter((item, index) => arr.Indexof(item, 0) === index)
- 先排序再比较相邻元素
-
数组有哪些遍历方法,区别是什么?
-
简单的实现一个promise
ES6
-
es6你知道的有哪些?
-
var、let和const的区别
var:可以重复定义,可以修改;
let:
- 不可以重复定义;
- 可以修改;
- 块级作用域
- 不影响作用域链
const:
- 不可以重复定义;
- 不可以修改;
- 块级作用域;
- 一定要赋初始值;
- 常量的值不能修改;
-
CommenJs的模块化导入导出是怎样的?
导出:module.exports={}
导入:var xxx=require('/xxx.js')
-
es6模块导入导出是怎样的?
使用export导出
使用import导入
二、HTML、CSS
-
列举实现水平居中的方法
/* 1. margin: 0 auto */ .class { width: 100px; margin: 0 auto } /* 2. text-align: center */ .father-class { text-align: center; .son-class { display: inline-blick; // 行内元素 } } /* 3. float&position */ .page-div { float: left; width: 100%; overflow: hidden; position: relative; ul { clear: left; float: left; position: relative; left: 50%; /*整个分页向右移动宽度的50%*/ text-align: center; li { line-height: 25px; margin: 0 5px; display: block; float: left; position: relative; right: 50%; /*将整个分页项向左边移动宽度的50%*/ } } } /* 4. positon: absolute */ .class { positon: absolute; width: 200px; left: 50%; margin-left: -100px; } /* 5. display: flex */ .class { display: flex; justify-content: center; } /* 6. width: fit-content */ .pagination ul { width: -moz-fit-content; width:-webkit-fit-content; width: fit-content; margin-left: auto; margin-right: auto; } .pagination li { line-height: 25px; margin: 0 5px; float: left; } -
列举实现垂直居中的方法
-
html5有哪些新特性
- 语义化标签
- 增强型表单
- 新增视频 <video> 和音频 <audio> 标签
- Canvas绘图
- SVG绘图
- 地理定位
- 拖放API
- Web Worker
- Web Storage
- WebSocket
-
css3有哪些新特性
-
简述盒模型
-
css权重规则
三、HTTP和浏览器
-
http是什么?
超文本传输协议(HTTP,HyperText Transfer Protocol)
-
http和https的区别
- https是http的安全版本
- 端口不同:http是80,https是443。
-
http状态码有哪些,代表什么意思
说出代表性的几个:200、401、403、404、500
-
什么是跨域?
域名、协议、端口号不同
-
怎么解决跨域?
- 使用script标签
- 使用jsonp(原理是动态创建scrip标签)
-
cookie、seesionStorage、localStorage的区别
特性 Cookie LocalStorage sessionStorage 声明周期 一般由服务器产生,可设置生效时间,如果在浏览器生产,默认事关闭浏览器后失效 除非被清除,否则永久保存 仅在当前会话有效,关闭浏览器或页面后被清除 存放数据大小 最大4kB 一般5M 同LocalStorage 与服务器通信 每次都会携带在HTTP中,如果使用cookie保存过多数据会带来性能问题 仅在客户端中保存,不参与服务器通信 同LocalStorage 用途 一般由服务器端生成,用于标识用户身份 用于浏览器端缓存数据 同LocalStorage -
简述浏览器从输入url到渲染页面的过程
- DNS解析(将域名转换成ip地址(从DNS服务器和本地host文件获取解析))。
- TCP三次握手(三个报文)建立连接。
- 发送请求,分析url,设置请求报文。
- 服务器返回请求的文件(html)。
- 浏览器渲染:
- 构建dom树
- 生成style树
- dom树+style树 = 渲染树
- layout布局
- GPU painting 像素绘制页面
-
什么是回流、重绘
回流一定会引起重绘,重绘不一定引起回流回流:当渲染树中的元素结构或尺寸等发生改变,浏览器重新渲染部分或全部文档的过程。
- 页面首页渲染
- 浏览器窗口大小发生变化
- 内容变化
- 添加或者删除节点
- 激活CSS伪类
- clinentWidth
重绘:当页面中元素样式的改变不影响它在文档流中的位置,浏览器会将新样式赋予给元素的过程。
- background
- visibility
性能:回流的性能消耗大于重绘性能
优化-CSS:
- 避免使用table布局
- 避免设置多层内联样式
- 使用transform代替top,left,margin等位移属性
- 使用opacity代替visible
优化-Javascript:
- 避免频繁操作DOM
- 对于大量插入DOM的操作,建议使用文档片段,也就是documentFragment
四、Vue
-
简述MVVM
Model-View-ViewModel 使用ViewModel将Model和View关联起来、即使用ViewModel将数据和视图层分离,数据绑定到ViewModel再渲染到页面,视图变化后再由ViewModel更新数据。
-
简述spa
概念:single-page-application 因为所有的页面都是挂载在id为app的根节点下,每次用户进行页面跳转都是利用路由在app下重新挂载、销毁。不用刷新整个页面。
优点:不需要加载重载整个页面、服务压力小、前端架构清晰。
缺点:初次加载耗时多、seo难度大、不能使用浏览器的前进后退功能。
-
简述vue的双向绑定原理
数据改变视图、视图改变后再通过监听事件改变数据,利用Object.defineProperty()对数据进行劫持。
-
伴随v-for使用的key有什么作用?
相当于身份id,相比没有key能更准确、更快的更新虚拟DOM,更好的让DOM-Diff识别。
作用:准确(没有复用组件)、更快(利用key生成map对象,比遍历更快)
- 使用index:key相同还是会复用组件,
- 不加key默认使用index就地复用;
- 同一组件内,key相同的情况下,标签也相同的话会产生复用;
-
为什么组件中只能有一个根元素?
- vue只能指定一个spa入口;
- 虚拟dom是树形结构,多个元素无法生成树形;
-
简述虚拟DOM和作用
Virtual-DOM:模拟真实DOM的机构,通过数据追踪和**状态对比(DOM-Diff)**来减少对真实DOM的操作,提高效率。
作用:浏览器直接操作dom很浪费性能,可以把dom元素标示成一个树形对象,再把树形对象渲染成真实dom
- 先实现虚拟dom:用一个对象来描述dom节点(使用jsx语法、render函数);
- 将虚拟节点转化成真是的dom节点,最后插入到app元素中;
-
组件中的data为什么是一个函数?
组件被复用时,会创建多个实例,如果是对象,那么这些实例则共享一个对象,为了保证独立性使用函数返回一个对象。
-
有哪些生命周期函数
- beforeCreate:组件实例被创建前,el,data,data中的message都为undefined
- created:组件实例创建完成,el还是undefined
- beforeMount:dom挂载之前
- mounted:dom挂载完成
- beforeUpdate:组件数据更新之前调用
- update
- activited、deactivated、beforeDestory、destoryed
-
ajax请求放在哪个生命周期中?
- 可以放在created、beforMounte和mounted中,生命周期是同步,ajax是异步。
- 服务端渲染不支持mounted方法
-
何时使用beforeDestroy
- 使用$on方法,需要在组件销毁前解绑;
- 清除定时器
- 解绑原生的dom操作scroll事件、mousemove事件...
-
有哪些你熟悉的指令
常用:v-if、v-show、v-for、v-bind、v-on、v-model
-
v-if和v-show的区别
v-if:判断是否渲染节点,在编译阶段做处理;
v-show:控制dom的visible,在编译render函数阶段,编译成指令;
-
为什么v-for和v-if不能连用
v-for会比v-if的优先级更高,连用的话会把v-if给每个元素都添加,造成性能问题
-
v-model的原理和自定义
原理:在元素上创建双向绑定,绑定不同的属性,再通过不同的事件来改变值
-
组件通信有哪些方法?
- props
- vuex
- sessionStorage
- ref
- bus
-
computed和watch的作用和特性
五、项目/应用
-
你对项目做过哪些优化?
-
基础优化
-
开启Gzip压缩
-
图片使用链接(上传到CDN)
-
图片压缩
-
第三方插件按需引入
-
路由懒加载
-
图片资源预加载(使用Preload.js)
-
图片资源懒加载(可视区域不加载,使用vue-lazyload)
-
使用keep-alive缓存路由:
在路由路由对象的mata对象中加入keepAlive属性;
每次路由刷新都往vuex里存放路由name
不需要缓存时,清除vuex里存放的name
-
-
其他优化
- 模块化:
-
-
你的项目有哪些亮点/难点?
七、人事
-
你有什么优点/缺点?
-
近3/5年有什么规划?
-
你觉得你有哪些优势?
-
为什么从上一家公司离职?
-
你有什么想要问我的?
技术:
公司使用什么技术栈? 公司技术部(前端)人员构成?福利:
福利、年终奖 公积金 加班、加班补贴 上班时间