HTML
html语义化
meta viewport
github head<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
用过什么html5标签
header footer main article
canvas video audio
搜索mdnH5是什么?
移动端页面1. 页面素材预加载,createJS的preloadJS 2. 音乐加载播放技术,createJS的soundJS或H5的audio 3. 可滑动页面,swiper.js 4. 可涂抹擦除,canvas叠层 5. 动态文字和图片,css3动画与js动画 6. 填报报名 html表单 7. 支持分享自定义的文案和图片 微信jssdk 炫酷效果:egret/cocos2d/
CSS
盒模型
content-box 内容区宽度
border-box content+padding+border实现垂直居中
table自带功能
<table> <tr> <td>内容</td> </tr> </table>
2 100%高度的after before 加上inline block
2.1 方案一
<div class="parent"> <span class="before"></span> <div class="child">内容</div> <span class="after"></span> </div> <style> .parent{ text-align:center;//水平居中 padding:10px 0;//让父元素有高度,但不必要 } .child{ display: inline-block; vertical-align: middle; } .before,.after{ display: inline-block; hegiht:100%; vertical-align: middle; } </style>
2.2 方案一优化版
<div class="parent"> <div class="child">内容</div> </div> <style> .parent{ text-align:center;//水平居中 padding:10px 0;//让父元素有高度,但不必要 } .child{ display: inline-block; vertical-align: middle; } parent::before,parent::after{ cotent:''; display: inline-block; hegiht:100%; vertical-align: middle; } </style>
3 postion+负margin子元素宽高的一半
<div class="parent"> <div class="child>内容</div> </div> <style> .parent { position: relative; } .child { position: absolute; width: 300px; height: 100px; top: 50%; left: 50%; margin-top: -150px; margin-left: -50px; } </style>
transform: translate(-50%,-50%)
flex
absolute top/bottom/left/right:0;margin:auto
flex属性
BFC是什么
块级格式化上下文,常见的例子有:- overflow:hidden
- 浮动元素
- 绝对定位元素
- inline-block
flex或者inline-flex
解决了什么问题:
- 清除浮动
- 防止margin合并
CSS选择器优先级
- 越具体优先级越高
- 写在后面的,覆盖写在前面的
- importan!最高 少用
清除浮动
.clearfix{content:''; display:block; clear:both;
}
加到容器上,里面子元素浮动被清除.重绘重排
ES6属性
Promise.all Promise.race
//Promise function xxx(){ return new Promise(function(resolve,reject){ setTimeout(()=>{ if(xxx){ resolve('data') }else{ reject(new Error('error')) } }) } } //Promise.all([fn,fn2,fn3]).then(res1,res2,res3) //Promise.race([fn,fn2,fn3]).then(res)
函数防抖,函数节流
防抖:事件触发,假如事件在一定时间内不再触发,则调用函数function 防抖(fn,time){ let timer = null; return ()=>{ if(timer){ clearTimeout() } timer = setTimeout(()=>{ fn() timer = null },time) } }
节流:一段时间内只能调用一次函数
function 节流(fn, time) { let doing = false; return () => { if (doing === false) { doing = true; fn() setTimeout(() => { doing = false; }, time) } } }
手写ajax
var request = new XMLHttpRequest(); request.open('GET','url') request.onreadystatechange = function(){ if(request.readyState === 4){ if(request.status >= 200 && request.status < 300 || request.status === 304){ console.log(request.responseText) }else{ console.log('error') } } } request.send()
用promise写ajax
function ajax(method,data,url){ return new Promise(function(resolve,reject){ let request = new XMLHttpRequest() request.open(method,url) request.onreadystatechange = function(){ if(request.readyState === 4){ if(request.status >= 200 && request.status < 300 || request.status === 304){ resolve(request.responseText) }else{ reject('error') } } } request.send(data) }) }
this
1. fn() this => window 2. obj.fn() this => obj 3. fn.call(x) 4. fn.apply(x) 5. fn.apply(x) this => x 6. new Fn() this => 新的对象 7. fn = ()=>{} this => 外面的this
闭包/立即执行函数
声名一个匿名函数,然后立即执行它。在Es6之前,只能通过它来[创建局部作用域]。
闭包:const add2 = function(){ var count return function add(){ count +1 = 1 //访问了外部变量的函数 } }()
闭包优点:
- 避免污染全局环境。
- 提供对局部变量的间接访问。
- 维持变量,使其不被垃圾回收。
jsonp/cors/跨域
jsonp,动态创建script标签,src指向请求地址,把callback函数名当做参数传给服务器,服务器把数据包装在callback内,传回来,然后script执行callback.
cors:跨域资源共享
- 对于简单请求,乙站点在响应头添加Access-Control-Allow-Origin:http://甲站点
- 对于复杂请求,如POST,乙站点需要:
- 响应OPTIONS请求,响应中添加如下的响应头
Access-Control-Allow-Origin:http://甲站点 Access-Control-Allow-Mthods:POST,GET,OPTIONS Access-Control-Allow-Headers:Contet-type
- 响应POST请求,在响应中添加Access-Control-Allow-Origin头
- 响应OPTIONS请求,响应中添加如下的响应头
- 如果需要附带Cookie,JS中需要在AJAX里设置xhr.withCredentials = true
async await 捕获异常
async function fn(){ try{ let a = await Promise.reject('error') }catch(error){ console.log(error) } }
深拷贝
- 递归
- 判断类型
- 检测循环引用(环)
不可能拷贝 proto
const cache = new Map()//缓存已拷贝部分 function clone(object){ if(cache.get(object)){//假如已缓存,直接返回 return cache.get(object) } let result if(! (object instanceof Object) ){//基础类型直接返回 return object }else if(object instanceof Array){ result = [] }else if(object instanceof Function){ result = function(){return object.apply(this,arguments)} }else if(object instanceof Date){ result = new Date(object-0) } else if(object instanceof RegExp){ result = new RegExp(a) }else{ result = {} } cache.set(object,result)//插入缓存 for(let key in object){ if(object.hasOwnProperty(key)){//非继承属性 result[key] = clone(object[key]) } } return result }
正则实现trim
function trim(string){ return string.replace(/^\s+|\s+$/g,'') }
继承
es5
function Animal(name){ this.name = name } Animal.prototype.move = function(){ console.log('move') } function Dog(){ Animal.apply(this,arguments) this.foot = 4 } let f = function(){} f.prototype = Animal.prototype; Dog.prototype = new f() Dog.prototype.constructor = Dog Dog.prototype.say = function(){ console.log('汪汪汪') } let a = new Dog('aaa') //{name:'aaa',foot:4} a.name a.move() a.foot a.say()
es6
class Animal{ constructor(name){ this.name = name } move(){ console.log('move') } } class Dog extends Animal { constructor(name){ super(name) this.foot = 4 } say(){ console.log('汪汪汪') } }
JS的new做了什么
- 创建临时对象/新对象
- 绑定原型
- 指定this = 临时对象
- 执行构造函数
- 返回临时对象
去重
hash(计数排序的思路)
var uniq = function(a){ var map = {} for(let i =0;i<a.length;i++){ let number = a[i] if(number === undefined){continue} if(number in map){//已重复 continue } map[number] = true //map里第一次出现 } const result = [] for(let key in map){ result.push(key) } return result }
缺点:数字只能是字符串,同时有数字跟字符串无法分出(’1’,1)
set
Array.form(new Set(a))
- Weekmap
缺点:兼容性差了一些var uniq = function(a){ var map = new Map() for(let i =0;i<a.length;i++){ let number = a[i] if(number === undefined){continue} if(map.has(number)){//已重复 continue } map.set(number,true) //map里第一次出现 } return [...map.keys()] }
手写Promise
class Promises2 { #status = 'pending' constructor(fn) { this.q = []//创建一个队列 const resolve = (data) => { this.#status = 'fulfilled' const f1f2 = this.q.shift()//出列,返回第一个 const x = f1f2[0].call(undefined, data) if (x instanceof Promise2) { x.then(data => { resolve(data) }, (reason) => { reject(reason) }) } else { resolve(x) } }; const reject = (reason) => { this.#status = 'rejected' const f1f2 = this.q.shift() const x = f1f2[1].call(undefined, data) if (x instanceof Promise2) { x.then(data => { resolve(data) }, (reason) => { reject(reason) }) } else { resolve(x) } } fn.call(undefined, resolve, reject) } then(f1, f2) { this.q.push([f1, f2])//入列 } }
手写Promise.all
- 知道Promise上写而不是在原型上写
- 知道all的参数(Promise数组)和返回值(新Promise对象)
- 知道用数组来记录结果
- 知道只要一个reject就整体reject
Promise.myAll = function (list) { const results = [] let count = 0 return new Promise((resolve,reject) => { list.map((promise,index) => { promise.then((r) => { results[index] = r count += 1 if (count === list.length) { resolve(results) } }, (reason) => { reject(reason) } ) }) }) }
JS垃圾回收机制
- 什么是垃圾
- 没有引用的就是垃圾
- 如果是对象互相引用,形成环也是垃圾
- 如何捡垃圾
遍历和计数,如有引用则进行标记,最后把没有标记的删除 - 前端又有其特殊性(JS进程和DOM进程)
- 什么是垃圾
DOM
事件委托
好处:- 节省监听器
- 动态监听
坏处: 调试比较复杂,不容易发现监听者。
ul.addEventListener('click', function(e){ if(e.target.tagName.toLowerCase() === 'li'){ fn() // 执行某个函数 } })
- mouse事件写一个可拖动的div
- 记录鼠标按下的坐标
- 记录当前拖动坐标
- 移动距离=拖动坐标-拖动坐标
- 元素的style.left/top+移动距离
var position = null var drag = false xxx.addEventListener('mousedown',function(e){ drag = true; position = [e.clientX,e.clientY] }) document.addEventListener('mousemove',function(e){ if(!drag) return //没有移动就别拖 let X = e.clientX let Y = e.clientY let left = parseInt(xxx.style.left || 0 ) let top = parseInt(xxx.style.top || 0 ) moveX = X - position[0] moveY = Y - position[1] xxx.style.left = left + moveX + 'px' xxx.style.top = top + moveY + 'px' position = [X,Y] }) document.addEventListener('mouseup',function(e){ drag = false })
HTTP
HTTP状态码
HTTP status cat
HTTP缓存有哪几种
http1.1:Cache-control(强缓存): max-age 多少秒内过期 是相对时间 无请求 在本地
Etag(协商缓存):MD5 在服务器 有请求 304
http1.0:服务器最后修改时间,只能存到秒 有请求 304
Expire(强缓存):日期 什么时候过期 Bug:本地时间用户可以调 无请求 在本地
Last-Modified(协商缓存):GET 和 POST
错:(背)
- POST安全 GET不安全
- GET URL有长度限制 POST没有
- GET 参数放在URL POST 放在消息体
- GET 只需要一个报文 POST 需要两个以上
- GET 幂等(不改变数据) POST 不幂等(改变数据库)
- GET结果会被缓存,POST结果不会被缓存
对: 只语义上的区别 get 获取数据 post 提交数据
Cookie Session Localstrage Sessionstrage 区别
- Cookie与Localstrage,cookie会被发送到服务器,4k,Localstrage不带请求,在本地,5M
- Localstrage与Sessionstrage,前者不会过期,后者会话结束后过期
- Cookie与Session,cookie存在浏览器,Session存在服务器,Session基于Cooike实现,具体做法就是把SessionId存在Cookie里
HTTP2 HTTP1区别
- HTTP/2使用了二进制传输,而且将head和body分成帧来传输;HTTP/1.1是字符串传输。
- HTTP/2使用多路复用,HTTP/1.1不支持。多路复用简单来说就是一个TCP连接从单车道(不是单行道)变成了几百个双向通行的车道。
- HTTP/2可以压缩header,但是HTTP/1.1不行。
- HTTP/2支持服务器推送,但是HTTP/1.1不行。
HTTP和HTTPS区别
- HTTP是明文传输的,不安全;HTTPS是加密传输的,非常安全。
- HTTP使用80端口,HTTPS使用443端口。
- HTTP较快,HTTPS较慢。
- HTPS的证书一般需要购买,HTTP不需要证书。
TCP三次握手和四次挥手
建立TCP连接时sever和client会经历三次握手- 浏览器向服务器发送TCP数据,SYN(X)//请求数据
- 服务器向浏览器发送TCP数据,ACK(X+1),SYN(y)//表示同意
- 浏览器向服务器发送TCP数据,ACK(y)//表示同意
关闭TCP连接时sever和client会经历四次挥手
- 浏览器向服务器发送TCP数据,FIN(X)//表示已完成
- 服务器向浏览器发送TCP数据,ACK(X+1)/表示同意
- 服务器向浏览器发送TCP数据,FIN(y)/表示已完成
浏览器向服务器发送TCP数据,ACK(y)//表示同意
为什么2,3步骤不合并?因为2,3中间服务器很可能还有数据要发送,不能提前发送FIN
Vue
watch computed 区别
watch是属性监听无缓存
computed是计算属性,有缓存生命周期
created:初始化
mouted:数据请求
updated:更新时做
destory:销毁时组件通信
- 父子 props $emit(‘事件’,data) $on(‘事件’,function(){})
- eventBus eventBus = new Vue();eventBus.$emit() eventBus.$on
- Vuex
Vuex
状态管理工具
state
getter
mutatiion
action…map
vue2如何实现双向绑定的?
- v-model是v-bind:value和v-on:input的语法糖
a: v-bind:value实现了data=>ui的单向绑定
b: v-on:input实现了ui=>data的单向绑定 - 如何实现
a: Object.defineProperty 给data创建getter/setter,用于监听data的改变,data一变就会安排改变ui
b:后者通过template compiler给DOM添加事件监听,DOM input的值改变了就会去修改data
- v-model是v-bind:value和v-on:input的语法糖
vue.set
vm.$set(‘目标对象’,key,value)
vue-router
vue的官方管理器
重定向
histroy模式
懒加载 improt(‘./文件路径’)
- 路由守卫
router.beforeEach((to, from, next) => {
// ...
})
next() //去to
next(false) //去from
next('/login') //去login
组件内
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
全局
router.beforeResolve
拦截
混用
`
bash
//登录成功后将token存到seesionStorage
seesionstorage.setItem(‘token’,data.token)
//路由守卫
router.beforeEach((to,from,next)=>{
if(to.patch === ‘/login’) return next()
if(!sessionStorage.getItem(‘token’)) return next(‘/login’)
next()
})
//请求拦截
axios.interceptors.request.use(function(config){
config.headers.Authorization = seesionStorage.getItem(‘token’)
return config
})
//响应拦截
axios.interceptors.response.ues(function(response){
if(response.data.meta.status === 401){
location.href = ‘#/login’
}else{
return response
}
})
### vue3
1. vue3为什么使用proxy?
1. 弥补Object.defineProperty的两个不足
a:动态创建的data属性需要Vue.set来赋值,vue3用了proxy就不需要了。
b:基于性能考虑,vue2篡改数组的7个API(push等),vue3用了proxy就不需要了。
2. defineProperty需要提前递归遍历data做到响应式,而proxy可以在真正用到深层数据的时候再做响应式(惰性)
2. vue3为什么使用composition API?
1. composition api比mixins、高阶组件、extends、Renderless Components等更好,原因有三:
a:模板中的数据来源不清晰。
b:命名空间冲突。
c:性能
2. 更适合TypeScript
3. vue3对比vue2做了哪些改动?
1. createApp()代替了new Vue()
2. v-model代替了以前的v-model和sync
3. 根元素可以不止一个元素了
4. 新增teleport传送门
5. destory被改名为unmounted了
6. ref属性支持函数了
### Webpack
1. 用过什么loader plugin
1. loader 转换器
1. babel-loader 把 JS/TS 变成 JS
2. ts-loader 把 TS 变成 JS,并提示类型错误
3. markdown-loader 把 markdown 变成 html
4. html-loader 把 html 变成 JS 字符串
5. sass-loader 把 SASS/SCSS 变成 CSS
6. css-loader 把 CSS 变成 JS 字符串
7. style-loader 把 JS 字符串变成 style 标签
8. postcss-loader 把 CSS 变成更优化的 CSS
9. vue-loader 把单文件组件(SFC)变成 JS 模块
10. thread-loader 用于多进程打包
2. plugin 扩展器
1. html-webpack-plugin 用于创建 HTML 页面并自动引入 JS 和 CSS
2. clean-webpack-plugin 用于清理之前打包的残余文件
3. mini-css-extract-plugin 用于将 JS 中的 CSS 抽离成单独的 CSS 文件
4. SplitChunksPlugin 用于代码分包(Code Split)
5. DllPlugin + DllReferencePlugin 用于避免大依赖被频繁重新打包,大幅降低打
包时间
6. eslint-webpack-plugin 用于检查代码中的错误
7. DefinePlugin 用于在 webpack config 里添加全局变量
8. copy-webpack-plugin 用于拷贝静态文件到 dist
二者的区别
3. loader 是文件加载器(这句废话很重要)
功能:能够对文件进行编译、优化、混淆(压缩)等,比如 babel-loader /
4. plugin 是 webpack 插件(这句废话也很重要)
功能:能实现更多功能,比如定义全局变量、Code Split、加速编译等
运行时机:在整个打包过程(以及前后)都能运行
2. webpack 如何解决开发时的跨域问题?
在开发时,我们的页面在 localhost:8080 ,JS 直接访问后端接口(如
https://xiedaimala.com 或 http://localhost:3000 )会报跨域错误。
为了解决这个问题,可以在 webpack.config.js 中添加如下配置:
```bash
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://xiedaimala.com',
changeOrigin: true,
},
},
},
};
此时,在 JS 中请求 /api/users 就会自动被代理到
http://xiedaimala.com/api/users 。
如果希望请求中的 Origin 从 8080 修改为 xiedaimala.com,可以添加 changeOrigin:
true 。
如果要访问的是 HTTPS API,那么就需要配置 HTTPS 证书,否则会报错。
不过,如果在 target 下面添加 secure: false ,就可以不配置证书且忽略 HTTPS 报
错。
总之,记住常用选项就行了。
如何实现 tree-shaking?
是什么
tree-shaking 就是让没有用到的 JS 代码不打包,以减小包的体积。
怎么做
背下文档说的这几点:- 怎么删
a. 使用 ES Modules 语法(即 ES6 的 import 和 export 关键字)
b. CommonJS 语法无法 tree-shaking(即 require 和 exports 语法)
c. 引入的时候只引用需要的模块i. 要写 import {cloneDeep} from 'lodash-es' 因为方便 tree-shaking ii. 不要写 import _ from 'lodash' 因为会导致无法 tree-shaking 无用模块
- 怎么不删:在 package.json 中配置 sideEffects,防止某些文件被删掉
a. 比如我 import 了 x.js,而 x.js 只是添加了 window.x 属性,那么 x.js 就要放到
sideEffects 里
b. 比如所有被 import 的 CSS 都要放在 sideEffects 里 - 怎么开启:在 webpack config 中将 mode 设置为 production(开发环境没必要tree-shaking)
a. mode: production 给 webpack 加了非常多优化
- 怎么删
如何提高 webpack 构建速度?
- 使用 DllPlugin 将不常变化的代码提前打包,并复用,如 vue、react
- 使用 thread-loader 或 HappyPack(过时)进行多线程打包
- 处于开发环境时,在 webpack config 中将 cache 设为 true,也可用 cacheloader(过时)
- 处于生产环境时,关闭不必要的环节,比如可以关闭 source map
- 网传的 HardSourceWebpackPlugin 已经一年多没更新了,谨慎使用
webpack 与 vite 的区别是什么?
- 开发环境区别
a. vite 自己实现 server,不对代码打包,充分利用浏览器对
- 开发环境区别
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 Roxas Deng的博客!