JS篇
h5新特性
- 语义化标签,比如header、footer、nav、aside、article、section、main;作用:有利于SEO优化,代码可读性更强
- 音视频标签,audio、video
- 画布canvas、矢量图svg
- 本地存储localStorage、sessionStorage
- web worker,作用:开启一个子线程,且子线程的操作不受线程的影响 应用场景: 1.大数据处理; 2.耗费时间较长的操作;
localStorage与sessionStorage的区别?
- 生命周期不同:localStorage会一直存在浏览器,sessionStorage在页面关闭时清除
cookie
- 页面关闭清除,存在于http请求头中
rem与em的区别是什么呢?
- rem:相对于html标签的font-size去决定大小,例如:html标签font-size为14px,则2rem === 28px
- em:相对于自身的font-size去决定大小,自身没有font-size则继承祖先级元素的font-size
promise的作用?
- promise的then方法返回一个新的promise对象,保证了then方法可以进行链式调用
- 解决链式调用的回调地域,让代码更加优雅
- 它有padding(等待)、resolved(成功)、reject(失败)三种状态,有状态不可逆的效果
async和await的作用
- 用同步的方式执行异步操作,实现排队效果
- async:async函数指向返回一个promise
- await:await后接promise则会等待promise返回结果,接普通函数执行则会接收返回结果
- await只能在async中使用,但在浏览器调试中可单独使用
什么是跨域?解决跨域有几种方式?
- 同源策略,域名、协议、端口其中一个不相同会造成跨域问题 解决:
- 1.CORS(跨域资源共享)
- 2.proxy本地代理
- 3.jsonp(通过script标签,只能get请求)
- 4.后端加上请求头进行跨域
数据类型有哪些?
基本数据类型:
- number、array、string、null、undefined、symbol、bigInt 复杂数据类型:
- array、object、function
ES6新特性有哪些?
- 模板字符串
- 箭头函数
- 数据结构
- 扩展运算符
- set和map
- class声明类
- find和findIndex
- promise
- let和const
- 函数参数默认值
- import和export ES7
- includes ES8
- async和await
- object.values
数组的方法有哪些?
- find和findIndex
- map、filter、every(遍历数组中所有元素是否满足条件,返回true和false)、foreach、some(跟findIndex用法一样,但返回的是布尔值)
- join(数组拼接字符串)
- push(返回数组长度)、pop(返回删除元素的下标)
- shift(删除元素)和unshift(在数据开头加入多个元素并返回数组长度)
- reverse(数组反转)和sort(数组排序)
- slice(不改变原数组)和splice(改变原数组)
- concat
- includes和indexOf
字符串的方法有哪些?
- length、indexOf、split(字符串分割为数组)
- 字符串截取:substr(开始,结束)、substring、slice
- 符串转换:toLowerCase(小写)、toUpperCase(大写)
- 字符串匹配:replace、match和search
- trim、toString、parseInt、parseFloat
判断数据类型有几种方法?
- typeOf(不能精确判断null、array、object、因为都返回object)
- instanceOf
- Object.prototype.toString.call()
call、apply、bind的区别?
- call与apply的区别在于传参,前者直接传参,后者传一个数组
- bind传参后不立即执行,而是返回一个函数,这个函数可以继续传参,且执行(bind函数可以分两次传参)
什么是闭包?它有什么优缺点?应用场景有哪些?
- 一个函数中返回一个函数就是闭包
- 优点:有独立的作用域,防止外部污染
- 缺点:占内存,容易造成内存泄漏
- 应用场景:防抖与节流
什么是数据长列表?原理是什么?
- 概念:
长列表其实是按需显示的一种实现,即只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能。文章
什么是原型?什么是原型链?原型继承有哪些?
- 先从原型说起,在定义函数的时候,函数就会生成一个原型prototype,每个原型会生成一个实例,实例里面有个属性叫
__proto__和构造函数,根据__proto__属性可以追述到它的原型,从而形成一种三角关系,这样组成一个原型一个实例下去就是原型链,直到最上层object最终会指向null - 原型继承有6种继承方式:
- 1.原型链继承:通过prototype继承,将原型的prototype指向person达到继承效果,优点:继承了父级原型方法,缺点:实例化多个相同函数都必须共用相同的属性名
- 2.构造函数继承:在子类构造函数中调用父类构造函数,可以在子类构造函数中使用
call()和apply()方法 - 3.组合继承:将原型链继承和借调构造函数的技术组合到一块,从而发挥两者的优点的一种继承方式,优点:只继承属性,值不同,可以继承父原型中的方法
- 4.原型式继承:借助原型可以基于已有的对象创建对象,类似复制了一个对象
- 5.寄生式继承:就是给原型式继承外面套个壳子,没用到原型
- 6.寄生组合式继承:通过借调函数来继承属性,通过原型链的混成形式来继承方法(常用)
什么是bfc机制?
- 块级格式化上下文,它是指一个独立的块级渲染区域,一般用来解决margin塌陷 形成方法:
-
- float:left
-
- position: absolute或fixed
-
- display: inline-block
-
- flex: inline-flex
-
- overflow: hidden(最佳方法)
什么是重绘和回流?
- 概念:浏览器采用的是流式布局,浏览器会将html解析为Dom节点,把css解析为cssom,最后把dom和cssom结合产生render树,再把render树绘制到页面上,回流一定引起重绘,但重绘不一定引起回流
- 引起回流:当rebder树的结构或者尺寸发生改变的时候,浏览器重新渲染就会引起回流,比如说页面窗口大小发生变化,内容的变更,添加或删除DOM节点这些都会发生回流
- 引起重绘:当页面中元素样式的改变不影响它在文档流中的位置,这个过程就是重绘 优化:少用table,避免频繁操作dom
赋值、深拷贝和浅拷贝?
- 赋值:赋值指针指向,还是用的同一个内存空间
- 浅拷贝:只拷贝第一层
- 深拷贝:所有层都会进行拷贝
有哪几种作用域?
- 全局作用域
- 1.全局作用域:全局作用域为程序的最外层作用域,一直存在
- 2.函数作用域:函数作用域只有函数被定义时才会创建,包含在父级函数作用域 / 全局作用域内。
- 块级作用域
- 花括号内{...}的就是块级作用域,比如:if判断也是一个块级作用域
- 作用域链
- 函数内部打印一个不存在的变量,如果内部没有就会去外部寻找,直到全局作用域停止
箭头函数的作用?
- 1.语法更加简洁清晰
- 2.箭头函数没有prototype,所以箭头函数本身没有this
- 3.call | apply | bind 无法改变箭头函数中this的指向
- 4.箭头函数不能作为构造函数使用
- 5.箭头函数没有
arguments
谈谈EventLoop?
- 概念:
EventLoop即事件循环,是浏览器解决js单线程运行时不会阻塞的一种机制,在js执行过程中会将异步分为宏任务于微任务,因为宏任务执行较久会将微任务排在前面执行完毕再执行宏任务,会形成一个先进先出的效果
浏览器的垃圾回收机制?
- 概念:在代码执行过程中使用的内存,垃圾收集器会定期找出那些不再继续使用的变量,然后释放内存,现在各大浏览器所采用的垃圾回收机制有两种:一种是标记清除,一种是引用计数;
- 标记清除:
- 当声明一个变量时,会将变量标记为‘进入环境’,从逻辑上讲,永远不能释放标记为‘进入环境’变量所占的内存,因为只要执行流进入相应的环境,就可能会用到它们,而当变量离开环境时,则将变量标记为‘离开环境’,从而垃圾回收机制就会释放这些离开环境变量的内存,回收它们所占用的空间
- 引用计数:
- 跟踪记录每个值被引用的次数,当声明变量并赋值的时候,这个值的引入次数就是1,如果这个值赋值给另一个变量,则引用次数加1,相反,如果变量脱离了该值的引用,则该值引入次数就减1,当次数为0时,就会等待垃圾收集器回收,这个方式存在一个比较大的问题就是循环引用,就是说A对象包含一个指向B的指针,对象B也包含一个指向A的引用,这就会造成大量内存得不到回收,造成内存泄漏,因为它们得引用次数永远不等于0,早期ie9采用的就是这种计数回收机制,闭包导致内存泄漏的一个原因就是这个算法的一个缺陷,解决办法就是把循环引用中的变量设置为null即可
HTTP状态码有哪些?
- 200(请求成功)
- 201(请求成功,并创建了新的资源)
- 204(请求成功,但没有资源可返回)
- 206(范围请求)
- 301(永久重定向)
- 302(临时重定向)
- 303(请求资源存在另一个url,应用get请求定向获取请求的资源)
- 304(资源已找到,但没符合条件请求)
- 307(临时重定向)
- 400(客户端错误)
- 401(http认证失败)
- 403(没权限访问)
- 404(服务器没有找到资源)
- 405(服务器禁止使用该方法)
- 500(服务器错误)
- 502(服务器关闭,无响应)
- 503(服务器繁忙)
防抖和节流的区别?
- 防抖:
- 概念:多次执行,只以最后一次为准
- 原理:将若干个函数调用合成为一次,并在设定时间过去之后仅被调用一次
- 应用场景:商品搜索
function debounce(fn, delay) { let timer = null; return function () { let arg = arguments; clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, arg); // 若不改变this指向,则会指向fn定义环境 }, delay) } }
- 节流:
- 概念:多次执行,执行完一次才能再次执行
- 原理:节流函数不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数
- 应用场景:滚动加载更多
//时间戳+定时器版: 实现第一次触发可以立即响应,结束触发后也能有响应 (该版才是最符合实际工作需求) //该版主体思路还是时间戳版,定时器的作用仅仅是执行最后一次回调 function throttle(fun, delay = 500) { let timer = null; let previous = 0; return function(args) { let now = Date.now(); let remaining = delay - (now - previous); //距离规定时间,还剩多少时间 let that = this; let _args = args; clearTimeout(timer); //清除之前设置的定时器 if (remaining <= 0) { fun.apply(that, _args); previous = Date.now(); } else { timer = setTimeout(function(){ fun.apply(that, _args) }, remaining); //因为上面添加的clearTimeout.实际这个定时器只有最后一次才会执行 } } }
web有哪些安全问题?
- 防止sql注入,xss攻击
web如何做性能优化?
- 使用雪碧图
- 使用webp代替其他格式,图片一定要压缩
- 图片懒加载、路由懒加载
- button加loading效果
- 注意避免页面回流操作
- 第三方库按需引入
- 打包使用CDN加载
- css放在头部,js放在底部
- CSS 执行会阻塞渲染,阻止 JS 执行
- JS 加载和执行会阻塞 HTML 解析,阻止 CSSOM 构建
- 如果这些 CSS、JS 标签放在 HEAD 标签里,并且需要加载和解析很久的话,那么页面就空白了。所以 JS 文件要放在底部(不阻止 DOM 解析,但会阻塞渲染),等 HTML 解析完了再加载 JS 文件,尽早向用户呈现页面的内容。
- 那为什么 CSS 文件还要放在头部呢?
- 因为先加载 HTML 再加载 CSS,会让用户第一时间看到的页面是没有样式的、“丑陋”的,为了避免这种情况发生,就要将 CSS 文件放在头部了。
- 另外,JS 文件也不是不可以放在头部,只要给 script 标签加上 defer 属性就可以了,异步下载,延迟执行。
- 使用字体图标 iconfont 代替图片图标
- 减少http请求
- 使用webpack打包压缩文件
- 借助性能优化辅助工具,比如:Lighthouse
VUE篇
vue的生命周期
- 更新
- beforeCreate()
- 概念:初始化事件和生命周期,初始化数据,不能获取data数据
- created()
- 概念:created向vue添加了data和methods配置项,可以获取data数据,但不能获取到真实DOM
- 应用场景:通常可以在这个阶段发起ajax请求,初始化数据
- beforeCreate()
- 挂载
- beforeMount()
- 概念:虚拟DOM和数据挂载到真实DOM的过程,DOM挂载之前触发,获取不到真实DOM
- mounted()
- 概念:挂载结束,可以拿到真实DOM
- 应用场景:一般可以在这个钩子函数中进行DOM操作,也可以进行ajax操作
- beforeMount()
- 更新
- beforeUpdate()
- 概念:DOM更新前触发
- updated()
- 概念:DOM更新后触发,能够获取最新的DOM元素
- 应用场景:当数据更新并更新DOM的时候才会触发更新钩子函数
- beforeUpdate()
- 销毁
- beforeDestroy()
- 概念:销毁前触发
- destroyed()
- 概念:销毁后触发
- 应用场景:一般用于移除全局事件的操作,比如;定时器和window事件
- beforeDestroy()
vue的组件传值有哪些?
- 父传子,在组件中绑定变量,子组件通过props接收变量
- 子传父,通过$emit进行传值,父组件通过事件接收值
- 兄弟组件通过EventBus作为中间件,用on进行通信
- $ref获取实例
- parent,children获取当前组件的父组件和当前组件的子组件
什么是MVVM?说一下和MVC的区别?
- 映射关系简化,隐藏controller MVVM在MVC的基础上,把控制层隐藏掉了。
- Vue不是一个MVVM框架,它是一个视图层框架。
- ViewModal是一个桥梁,将数据和视图进行关联。
v-model的底层原理?
- vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发响应的监听回调。
- 单项绑定过程:变量变了,由Object.defineProperty()的set发通知给watcher,watcher告知虚拟DOM树,叫它该比较了,我这有值变了,于是生成新的dom树进行一个比较,比较出哪个元素发生变化就把这个元素更新到页面,这就是单项数据绑定原理
- v-model原理其实就是给input事件绑定oninput事件 就会立刻调用底层对象对应的setter方法 改变data里的属性的值 从而实现双向数据绑定
vue的虚拟DOM和diff算法
- vue中虚拟dom是template生成的js对象文件,作用,减少dom生成次数,将多次生成dom改为一次
- Vue的diff算法是平级比较,不考虑跨级比较的情况。节点层层比对,递归比较子节点,不同替换,相同则复用旧节点,优点:减少dom的生成次数,缺点,需要每层去比对,如果数据量极大的情况下,真实dom加载比较快
v-for为什么比v-if优先级高?
- v-for比v-if优先级高,不能在同一个标签中使用,影响性能,应该先处理v-for,再处理v-if。
nixtTick的原理?
nextTick是一个微任务。
- nextTick中的回调是在下次Dom更新循环结束之后执行的延迟回调
- 可以用于获取更新后的Dom
- Vue中的数据更新是异步的,使用nextTick可以保证用户定义的逻辑在更新之后执行
vuex的理解?
- vuex做数据共享管理的,vuex中只能通过mutation修改state
- 如果修改vuex中的state,通过display去调用store文件中的
action(异步)中的方法,再通过commit操作mutation(同步)的方法修改state,
keep-alive组件的理解?
- 因为组件切换会导致组件被频繁销毁和重新创建, 性能不高,keep-alive可以将组件进行缓存,被缓存的组件不再创建和销毁, 而是会生成激活和非激活两个钩子函数
computed和watch?
- 前者一对一,后者一对多
- computed计算属性:
- 作用:它的依赖结果会被缓存,当computed中所依赖的值没有发生改变的时候,那么调用当前函数的结果就会从缓存中读取,computed中的函数必须用return返回结果,computed比watch更高效,优先使用
- 应用场景:当一个变量需要依赖另一个值的时候使用,比如:购物车商品结算功能
- watch监听属性:
- 作用:watch是用来监听一个值的变化,可以拿到旧值和最新值,deep开启深度监听,可以监听到对象里的值的变化,需要在数据变化时执行异步或开销较大的操作时使用
- 应用场景:当一条数据影响多条数据的时候使用,比如:搜索数据
v-for中key的作用?
- 唯一标识的作用
路由中hash模式和history模式原理是什么?它们的区别是什么?
- hash模式:监听url中hash的变化来实现不同页面的展示,链接带#
- history模式:url中不带#,利用html5的history.pushState方法进行无刷新页面跳转,但需要后端配合404时的重定向
Vue的组件data为什么必须是一个函数
- vue中data采用的是闭包的模式,作用就是每个组件的数据都有自己独立的作用域,防止组件之间的污染
导航守卫
- 全局守卫
- 1.前置守卫:beforeEach,全局配置路由
- 2.全局解析守卫:beforeResolve,这个钩子和beforeEach类似,也是路由跳转前触发,区别:它是在 beforeEach 和 组件内beforeRouteEnter 之后,afterEach之前调用
- 3.全局后置钩子:afterEach,和beforeEach相反,他是在路由跳转完成后触发,参数包括to,from没有了next,他发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件内守卫)之前。
- 路由独享守卫
- 1.路由独享守卫:beforeEnter,在路由里面配置
- 组件守卫
- 1.进入路由:beforeRouteEnter,进入路由的钩子
- 2.更新路由:beforeRouteUpdate,更新路由的钩子
- 3.离开路由:beforeRouteLeave,离开路由的钩子
- 它们的参数有:
- to:即将进入的目标路由对象
- from:当前导航正要离开的路由
- next:一定要用这个函数才能到达下一个路由,如果不用就会遭到拦截
Vue2与React的区别在哪?
相同点:
- 1.都使用了虚拟dom
- 2.组件化开发
- 3.都是单向数据流(父子组件之间,不建议子修改父传下来的数据)
- 4.都支持服务端渲染 不同点:
- 1.React的JSX,Vue的template
- 2.数据变化,React手动(setState),Vue自动(初始化已响应式处理,Object.defineProperty,Proxy)
- 3.React单向绑定,Vue双向绑定
- 4.React的Redux,Vue的Vuex
React篇
React.memo
React.memo为高阶组件 作用:提高性能,如果props,state和context没有变化React将跳过渲染组件的操作直接复用最近一次渲染的结果,默认情况下只会对复杂对象做浅层对比,防止重复渲染。
使用示例:
const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
});
React.useMemo
作用:提高性能,当依赖的值不变则不会重复渲染,如果依赖值变则再次渲染。
使用场景:
1 缓存一些值,避免重新执行上下文
const number = useMemo(()=>{
/** ....大量的逻辑运算 **/
return number
},[ props.number ]) // 只有 props.number 改变的时候,重新计算number的值。
2.减少不必要的dom循环
/* 用 useMemo包裹的list可以限定当且仅当list改变的时候才更新此list,这样就可以避免selectList重新循环 */
{useMemo(() => (
<div>{
selectList.map((i, v) => (
<span
className={style.listSpan}
key={v} >
{i.patentName}
</span>
))}
</div>
), [selectList])}
3 减少子组件渲染
/* 只有当props中,list列表改变的时候,子组件才渲染 */
const goodListChild = useMemo(()=> <GoodList list={ props.list } /> ,[ props.list ])
React.useReducer
作用:合并多个state
使用示例:
const DemoUseReducer = ()=>{
/* number为更新后的state值, dispatchNumbner 为当前的派发函数 */
const [ number , dispatchNumbner ] = useReducer((state,action)=>{
const { payload , name } = action
/* return的值为新的state */
switch(name){
case 'add':
return state + 1
case 'sub':
return state - 1
case 'reset':
return payload
}
return state
},0)
return <div>
当前值:{ number }
{ /* 派发更新 */ }
<button onClick={()=>dispatchNumbner({ name:'add' })} >增加</button>
<button onClick={()=>dispatchNumbner({ name:'sub' })} >减少</button>
<button onClick={()=>dispatchNumbner({ name:'reset' ,payload:666 })} >赋值</button>
{ /* 把dispatch 和 state 传递给子组件 */ }
<MyChildren dispatch={ dispatchNumbner } State={{ number }} />
</div>
}
React.useContext
作用:跨组件传值。
使用示例:
/* 用useContext方式 */
const DemoContext = ()=> {
const value:any = useContext(Context)
/* my name is alien */
return <div> my name is { value.name }</div>
}
/* 用Context.Consumer 方式 */
const DemoContext1 = ()=>{
return <Context.Consumer>
{/* my name is alien */}
{ (value)=> <div> my name is { value.name }</div> }
</Context.Consumer>
}
export default ()=>{
return <div>
<Context.Provider value={{ name:'alien' , age:18 }} >
<DemoContext />
<DemoContext1 />
</Context.Provider>
</div>
}
React.createRef
作用:
React.createRef创建一个能够通过 ref 属性附加到 React 元素的ref。
使用示例:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
render() {
return <input type="text" ref={this.inputRef} />;
}
componentDidMount() {
this.inputRef.current.focus();
}
}
React.forwardRef
作用:
React.forwardRef会创建一个React组件,这个组件能够将其接受的ref属性转发到其组件树下的另一个组件中,通常配合useImperativeHandle使用
使用示例:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton"> {props.children}
</button>
));
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
React.useImperativeHandle
配合
forwardRef使用,共用ref的值
- 第一个参数:接受
forWardRef传递过来的ref。 - 第二个参数:处理函数,返回值作为暴露给父组件的
ref对象。 - 第三个参数:依赖项
deps,依赖项更改形成新的ref对象。
使用示例:
function Son (props,ref) {
const inputRef = useRef(null)
const [ inputValue , setInputValue ] = useState('')
useImperativeHandle(ref,()=>{
const handleRefs = {
/* 声明方法用于聚焦input框 */
onFocus(){
inputRef.current.focus()
},
/* 声明方法用于改变input的值 */
onChangeValue(value){
setInputValue(value)
}
}
return handleRefs
},[])
return <div>
<input
placeholder="请输入内容"
ref={inputRef}
value={inputValue}
/>
</div>
}
const ForwarSon = forwardRef(Son)
React.useCallBack
作用:提高性能,用于函数,防止函数重复渲染,用法跟
useMemo一样,区别在于useMemo返回的是函数运行的结果,useCallback返回的是函数
React.useLayoutEffect
原理:
useLayoutEffect的监听函数和clear的清除函数都是同步执行的,是在真实DOM发生改变之后,浏览器绘制前执行注意:尽量用
useLayoutEffect去操作Dom
React.useEffect
原理:
useEffect的监听函数和clear的清除函数都是异步执行的,是在真实DOM发生改变并且浏览器绘制完成后异步执行注意:在
useEffect中操作Dom会引起重绘和回流
React.useTransition
作用:在
useTransition的回调函数中的内容执行完毕,ispedding会为true,没执行完毕为false
const [isPedding, useTransition] = useTransition()
const [count,setCount] = useState();
// isPedding = false //默认为false
// setCount 设值完毕 isPedding = true
useTransition(()=>{
setCount(1)
})