Canvas元素有什么用
HTML5的canvas元素使用javascript在网页上绘制图形
前端模块化规范
①说说自己对前端模块化开发的认识
(1)异步模块定义(AMD)规范是require.js推广的对模块定义的规范。
(2)通用模块定义(CMD)规范是SeaJS推广的对模块定义的规范。
(3)AMD提前执行,CMD延迟执行
②为什么需要前端模块化
高内聚低耦合,有利于团队开发,方便维护以及代码块复用。
③EMAScript 6模块规范
(1)对比于Commonjs,语法更简洁,可以更好地支持循环依赖
(2)对比于AMD,直接支持异步加载和配置模块加载
(3)对于结构可以做静态分析、静态检测
④模块化Javascript开发的优势是什么
(1)将功能分离出来
(2)具有更好的代码组织方式
(3)可以按需加载
(4)避免了命名冲突
(5)解决了依赖问题
⑤require.js解决了什么问题
(1)实现了javascript文件的异步加载
(2)有助于管理模块之间的依赖性
(3)便于代码的编写和维护
⑥说说对CommonJS和AMD的理解
CommonJS是服务器端模块的规范,规范同步加载模块,也就是说,只有加载完成,才能执行后面的操作,Node.js采用了这个规范,CommonJS的风格是通过对module.exports或exports的属性赋值来达到暴露模块接口的目的。
AMD规范则非同步加载模块,允许指定回调函数,AMD推荐的风格是通过module transport规范暴露接口,即通过返回一个对象暴露模块接口。
CSS
css的盒模型
元素实际宽度尺寸=width+padding+border
em与rem的区别
em相对于父元素,rem相对于根元素
BFC的形成和作用
BFC属于常规流,它是页面上的一个隔离的独立容器,容器里的子元素不会影响到外面的元素。
作用:①解决外部边距重叠;②解决父元素因子元素浮动带来的塌陷问题
移动端自适应的方式
1.媒体查询:通过查询设备的宽度来执行不同的css代码
2.Flex弹性布局:高度定死,宽度自适应,元素都采用px做单位
3.rem+viewport缩放:根据屏幕宽度设定rem值,需要适配的元素都使用rem为单位,不需要适配的元素还是使用px为单位。
4.rem实现:通过代码来控制rem基准值
JS的数据类型
①基本数据类型:number\string\boolean\undefined\null\symbol
②引用数据类型:object\array\function
注意:基本数据类型保存在栈中,复制的是值本身,修改时都会发生变化;引用数据类型保存在堆里,复制的是地址
let const var的区别
var存在变量提升,let和const不存在
var没有块级作用域,let和const具有
var允许重复声明,let和const在同一作用域不允许重复声明
var和let声明的变量可以修改,而const是常量,不能修改
如何阻止冒泡和默认行为
e.stopPropagation()
e.preventDefault()
setInterval和setTimeout的区别
setInterval():可循环执行多次,一般用于刷新表单
setTimeout():只执行一次,用于延迟执行某方法或功能
获取DOM元素有哪些方法
document.getElementById()
document.getElementByTagName()
document.getElementByClassName()
document.getElementByName()
document.querySelector()
document.querySelectorAll()
事件机制有几个阶段
三个阶段:事件捕获、事件触发、事件冒泡。
事件循环
浏览器中js代码是单线程执行,不存在并发,异步是通过维护一个队列来执行的,这样的机制叫事件循环
事件委托
事件委托也叫事件代理,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
JS阻塞问题
指当浏览器在解析文档或者渲染页面时,遇见了JS代码,需要渲染引擎中断,而运行js引擎,从而阻塞浏览器原本的工作状态。
解决方法:将script标签放在头部,加上async或defer属性,两者都可以让浏览器进行异步加载js代码或者利用DOM动态创建script标签
New操作符的原理
创建一个空对象作为将要返回的对象实例,将这个空对象的原型指向构造函数的prototype属性,将这个空对象赋值给函数内部的this关键字,开始执行内部的代码。
闭包的作用和原理
闭包就是能够读取其他函数内部变量的函数,作用是将函数内部和函数外部连接起来的桥梁。
ES5、ES6如何实现继承
ES5的继承通过prototype或构造函数机制来实现,ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上。
ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错,因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工,如果不调用super方法,子类得不到this对象。
Javascript异步编程
四种方法:①回调函数②事件监听③发布/订阅④Promise对象
数据类型的检测方式
①typeof-->console.log(typeof 1)-->number
②instanceof-->console.log(1 instanceof Number)-->false 只能判断引用数据类型
③constructor-->console.log((1).constructor===number)-->true
④Object.prototype.toString.call()
var a=Object.prototype.toString;
console.log(a.call(1))-->[object Number]
判断数组的方法
let arr=[]
①instanceof-->console.log(arr instanceof Array)
②constructor-->console.log(arr.constructor===Array)
③isPrototypeOf-->console.log(Array.prototype.isPrototypeOf(arr))
④Object.getPrototypeOf-->
console.log(Object.getPrototypeOf(arr)===Array.prototype)
⑤Object.prototype.toString-->
console.log(Object.prototype.toString.call(arr)==='[Array type]')
⑥Array.isArray-->console.log(Array.isArray(arr))
遍历数组的方法
1.for循环
2.for...in
3.for...of
4.foreach方法
5.map方法
6.filter方法
for in与for of的区别:for in 遍历数组时,得到的是元素下标,for of 遍历数组时,得到的是数组元素
for与foreach的区别:for循环可以使用break跳出循环,但foreach不能;for循环可以控制循环的起点,foreach只能默认从索引0开始
undefined和null的区别
null和undefined的值相等,但类型不等;null会隐式转换为0,undefined会隐式转换为NaN
为什么0.1+0.2 != 0.3
因为发生了精度丢失,在JS内部所有的计算都是以二进制方式计算的,在0.1和0.2转换双精度二进制浮点数时,由于二进制浮点数的小数位只能存储52位,导致小数点后第53位的数要进行舍弃操作,从而造成精度丢失,最终导致0.1+0.2!=0.3
解决方案:可以先转换为整数,运算后再转换为小数。-->(0.1*10+0.2*10)/10===0.3
箭头函数和普通函数的区别
1.箭头函数是匿名函数,不能作为构造函数,不能使用new
2.箭头函数不绑定arguments,取而代之的是rest参数
3.箭头函数没有原型属性且this的作用域不同
splice(开始的位置,截取的个数,添加的元素)
返回值为由被删除的元素组成的一个数组,如果只删除了一个元素,则返回只包含一个元素的数组,如果没有删除元素,则返回空数组,这个方法会改变原数组,数组的长度会发生变化
this的指向有哪些情况
①全局作用域的this指向window
②对象内部的this指向它本身
③构造函数指向它的实例
④apply(),bind(),call()指向函数的第一个参数
⑤箭头函数没有自己的this,要向上层作用域找,若找到全局则指向window
定义及作用
Promise是ES6中进行异步编程的新解决方案,支持链式调用,可以解决回调地狱问题,指定回调方式更灵活,具有三种状态pending\rejected\resolved
async和await
async用于声明一个函数是异步的,await则是等待一个异步函数执行完成的。async函数一定会返回一个promise对象,await只能在async中使用,await命令后面是一个Promise对象,返回该对象的结果,如果不是promise对象,则直接返回对应的值。
什么是Vue的生命周期
Vue实例从创建到销毁的过程,也就是从开始创建、初始化数据、编译模板、挂载DOM、渲染更新等一系列操作过程,即为Vue的生命周期。
Vue生命周期的作用是什么
帮助我们在控制整个Vue实例的过程中形成更好的逻辑
Vue生命周期共有几个阶段
八个,分别是:创建前/后、挂载前/后、更新前/后、销毁前/后
beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestory,destoryed
v-if和v-show
相同点:都是控制元素在页面是否显示
不同点:v-show是将元素的display设置为none控制元素的隐藏,DOM元素依旧存在;v-if则是将DOM元素进行添加或删除
Vue的双向数据绑定原理
采用数据监听,解析结合订阅者模式的方式,通过Object.defineProperty()来监听各个属性的getter和setter,在数据变化时发布消息给订阅者,触发相应的监听回调,从而实现数据的双向绑定。
mvc和mvvm的区别
①mvc是单向的,mvvm是双向的,并且是自动的,也就是数据发生变化自动同步视图,视图发生变化自动同步数据②解决了MVC中大量的DOM操作,在数据频繁更新的时候,采用了虚拟DOM,减少过度渲染,提高性能
computed 和 watch
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值
watch: 更多的是监听的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
Vuex有几种属性
有五种,分别是 State、 Getter、Mutation 、Action、 Module
SPA单页面的理解
①什么是SPA
SPA(single-page-application)仅在WEB页面初始化时加载相应的HTML、Javascript和css一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转,取而代之的是利用路由机制实现HTML内容的变换,UI与用户的交互,避免页面的重新加载
②SPA单页面有什么优缺点
优点:A.用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;B.SPA相对于服务器压力更小;C.前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理
缺点:A.初次加载耗时多,为实现单页Web应用功能及显示效果,需要在加载页面的时候将javascript、css统一加载,部分页面按需加载;B.前进后退路由管理,由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;C.SEO难度较大,所有的内容都在一个页面中动态替换显示。
组件通信的几种方法
tcp的三次握手
第一次握手是客户端向服务器发起的,是用来申请建立连接的,报文中的SYN标志会标记为1
第二次握手是服务器回复客户端的,用来确认并接受连接请求,报文中的SYN和ACK标志都会标记为1
第三次握手是客户端发送给服务器的,用来确认服务器的回复消息,报文中的ACK标志标记为1
http和https的基本概念、区别
http:是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的超文本传输协议
https:是以安全为目标的HTTP通道,即HTTP下加入SSL层进行加密。其作用是建立一个信息安全通道来确保数据的传输以及网站的真实性
https的工作原理
客户端使用https url访问服务器,要求web服务器建立SSL链接,web服务器接收到客户端的请求之后,会将网站的证书传输给客户端,然后web服务器和客户端开始协商SSL链接的安全等级,客户端通过双方协商的安全等级建立会话密钥并传送给网站,web服务器则通过自己的私钥解密出会话密钥,并通过会话密钥加密与客户端之间的通信
http的缓存机制(强缓存与协商缓存)
浏览器第一次请求时,服务器返回资源,浏览器缓存在本地,并且服务器会通知浏览器一个缓存时间,下次请求如果在缓存时间内,直接使用缓存,否则进入协商缓存。
http与https的区别及优缺点
①http是超文本协议传输协议,信息是明文传输,https协议要比http协议安全,https是具有安全性的ssl加密传输协议,可防止数据在传输过程中被窃取、改变,确保数据的完整性②http协议默认端口为80,https协议默认端口为443③http的连接很简单,是无状态的,https握手阶段比较费时,会使页面加载时间延长50%,增加10%~20%的耗电④https缓存不如http高效,会增加数据开销⑤https协议需要ca证书,费用较高,功能越强大的证书费越高⑥SSL证书需要绑定IP,不能在同一个IP绑定多个域名,IPV4资源支持不了这种消耗
tcp三次握手为什么不能是两次或四次
两次握手无法保证服务端和客户端的接发功能都是ok的,四次握手会降低连接的速度和效率。
400、401、403、404、500、502状态码
400状态码:请求无效-->产生原因:前端提交数据的字段名称和字段类型与后台的实体没有保持一致或者是前端提交到后台的数据应该是JSON字符串类型,但是前端没有将对象JSON.stringify转化成字符串-->解决方法:对照字段的名称保持一致性或者将对象通过JSON.stringify实现序列化
401状态码:当前请求需要用户验证
403状态码:服务器已经得到请求,但是拒绝执行
404 请求错误,因发送的请求语法错误,服务器无法正常读取。
500 内部服务器错误,服务器遇到未知无法解决的问题
502 无效网关,服务器作为网关且从上游服务器获取到了一个无效的HTTP响应
tcp和udp的区别
①TCP是面向链接的,UDP是面向无连接的②TCP仅支持单播传输,UDP提供了单播,多播,广播的功能③TCP的三次握手保证了连接的可靠性,UDP是面向无连接的、不可靠的一种数据传输协议,首先不可靠性体现在无连接上,通信都不需要建立连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会被正确接收④UDP的头部开销比TCP小,数据传输速率更高,实时性更好
Cookie、sessionStorage、localStorage的比较
相同点:存储在客户端
不同点:①Cookie数据大小不能超过4K,sessionStorage、localStorage的存储相比而言大得多,可以达到5M+;②Cookie在设置的过期时间之前一直有效,sessionStorage数据在当前浏览器窗口关闭后自动删除,localStorage数据永久保存,浏览器关闭后数据不丢失,除非主动删除数据;
DOCTYPE的作用
告诉浏览器解析器用什么文档标准解析此文档。
一个页面从输入url到渲染完成都发生了什么
包括三个部分,首先是DNS解析URL,然后是浏览器发送请求与服务器进行交互,最后浏览器对接收到的html页面进行渲染
浏览器在生成页面的时候会生成哪两棵树
DOM树和CSSOM规则树,当浏览器接收到服务器传来的 HTML 文档后,会遍历文档节点,生成DOM 树, CSSOM 规则树由浏览器解析CSS 文件生成
浏览器引擎
渲染引擎:主要负责解析html和css相关文件
JS引擎:负责JS代码运行与解析
浏览器渲染机制
①浏览器根据服务器响应返回的html,进行解析后构建一棵DOM节点树;②根据css文件,构建得到CSSOM树;③将DOM树和CSSOM树结合,精确计算每个节点的位置、尺寸等属性,构建出渲染树;④渲染至用户页面
浏览器跨域问题
①为什么浏览器会禁止跨域:为了防止网站被恶意攻击,导致用户信息被泄露,所以浏览器使用了同源策略,防止CSRF攻击
②什么是同源策略:同源策略是一种约定,同源是指协议、域名、端口三者相同。
③什么是跨域:跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。
④解决跨域的方案:
浏览器事件循环
主线程不断从任务队列中读取事件,这个过程是循环不断的,这种运行机制就叫做事件循环(Event Loop),事件循环包含宏任务和微任务
浏览器重排重绘
重排更加耗费性能,重绘不一定重排,重排一定会重绘。
重绘:一个元素是外观改变,但是没有改变布局。浏览器会根据元素的新属性重新绘制,元素外观重新展示,重绘不会重新布局。
重排:DOM的变化影响到了元素的几何属性,DOM树会重新计算,节点的增删也会改变DOM树,发生重排。
babel的原理
babel是一个js代码编译器,通过插件将高版本的js转换为需要的低版本js
webpack的原理
通过一些loader和plugin把项目源代码打包成浏览器可以识别的代码同时做一些优化
Webpack构建流程
初始化参数-->开始编译-->确定入口-->编译模块-->完成模块编译-->输出资源-->输出完成
Webpack loader/plugin
谈谈你对webpack的理解
webpack是一个模块化打包JS的工具,在webpack中一切文件都是模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合而成的文件。
bundle\chunk\Loader\Plugin是什么
bundle:由webpack打包出来的文件
chunk:是一个代码块一个chunk由多个模块组合而成
Loader:因为webpack本身只理解javascript,所以loader用来解析js以外的东西,主要用于告诉webpack如何处理某一类型的文件,并引入到打包出来的文件中。
常用Loader:
file-Loader:把文件输出到一个文件夹中,在代码中通过相对URL去引用输出的文件
babel-Loader:把ES6转换为ES5,加载css,支持模块化、压缩、文件导入等特性
style-Loader:把css代码注入到javascript中,通过DOM操作去加载css
eslint-loader:通过eslint检查javascript代码
plugin:是一个扩展器,针对于在loader结束之后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,监听webpack打包过程中的某些节点,在合适的机会通过webpack提供的API改变输出结果。
常用plugin:
define-plugin:定义环境变量
commons-chunk-plugin:提取公共代码
uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码
防抖和节流
作用:都是在高频事件中防止函数被多次调用,是一种性能优化的方案
区别:防抖函数只会在高频事件结束后n秒调用1次函数,节流函数在高频事件触发过程中每隔n秒调用一次函数
function debounce(fn,wait){
let timer=null
return function () {
let _this=this
let args=arguments
clearTimeout(timer)
timer=setTimeout(()=>{
fn.apply(_this.args)
}),wait
}
}
function throttle(fn,delay){
let timer=null
return function () {
let _this=this
let args=arguments
if(!timer){
timer=setTimeout(()=>{
timer=null
fn.apply(_this.args)
},delay)
}
}
}
手写Promise
Promise.all()是只有当所有promise对象都返回resolved,才会返回所有resolved的结果,
只要有一个返回rejected,那它就会返回rejected的结果
Promise.prototype.myAll=function(_promises){
return new Promise((resolve,reject)=>{
const promises=[..._prmises]
const res=[]
const len=promises.length
for(let i=0;i{
res[i]=o
if(++count===len){
return resolve(res)
}
}).catch((e)=>{
reject(e)
})
}
})
}
手写深拷贝
function deepClone(source) {
// 需要一个判断是否为基本数据类型的函数
const isPrimitive=()=>{
return /Number|Strinng|Boolean|Null|Function|Undefined|Symbol/.test(Object.prototype.toString.call(source))
}
// 返回数据类型
const check=()=>{
return Object.prototype.toString.call(source)
}
let res=null
// 如果为基本数据类型,直接赋值
if (isPrimitive(source)) {
res=source
}else if(check(source)=='[object Date]'){
res=new Date(source)
}else if (check(source)=='[object RegExp]') {
res=new RegExp(source)
}else if(check(source)=='[object Set]'){
res=new Set()
for(let v of source){
res.add(deepClone(v))
}
}else if(check(source)=='[object Map]'){
res=new Map()
for(let [key,val] of source.entries()){
res.set(key,deepClone(val))
}
}else if (check(source)=='[object Array]') {
res=[]
for(let v of source){
res.push(deepClone(v))
}
}else if (check(source)=='[object Object]') {
res={}
for(let i in source){
res[i]=deepClone(source[i])
}
}
return res
}
盒子水平垂直居中排列的方法
(1).inner{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
(2).outer{
display:table-cell;
vertical-align:middle;
text-align:center;
}
.inner{display:inline-block}
(3).outer{
display:flex;
justify-content:center;
align-item:center;
}
(4).outer{
display:grid;
place-content:center;
}
(5).inner{
position: absolute;
top: 50%;
left: 50%;
margin-top:-高度的一半;
margin-left:-宽度的一半;
}