前端面试题总结

83 阅读45分钟

javaScript

//数据类型
	JavaScript共有八种数据类型,分别是 UndefinedNullBooleanNumberStringObjectSymbolBigInt
    Symbol:代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题
	BigInt:是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围
    
    
//原始值和引用值区别
    1.存储位置:
		原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储
		引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用
          数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,
          取得地址后从堆中获得实体
	2.数据结构中:
        栈中数据的存取方式为先进后出。
        堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定
    3.在操作系统中,内存被分为栈区和堆区:
        栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈
        堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收
//判断数据类型
   1.typeof:只能准确判断基本类型,nullobject(类型标签是000代表O)
   2.instanceof:只能判断引用数据类型,作用:用来判断左边对象是否是右边构造函数的实例对象
   3.constructor:创建对象改变原型就不能判断基本类型了,作用:1.判断类型 2.对象实例通过constructor对象访问它的构造函数(Person.prototype.constructor指向构造函数)
   4.Object.prototype.toString.call():返回[object Object]加上call(),改变this指向
//forEach、for in、for of区别
	forEach遍历数组,不能return
    for in 都可以,获取的是key
	for of 可以return,可以遍历数组、字符串、MapSet,不能遍历对象(遍历对象要搭配Object.keys()使用)
	
//跨域
   1.vue.config.js中配置proxy
   2.CORS跨域资源共享,后台跨域:res.setHeader('Access-Control-Allow-Origin', '*')
   3.jsonp:利用script标签的src属性可以连接到不同源的js脚本,来达到跨域的目的
        var url='http://www.baidu.com/jsonp_data'
       //1.创建script标签
        var script=document.creatElement('script')
       //2.设置src属性
        script.setAttribute('src',url)
       //3.插入到head标签内
        document.getElementsByTagName('head')[0].appendChild(script);
        function callback(data){
             console.log(data) //{name:1}
        }
        //jsonp_data.js文件
        callback({'name':1})
   

//localstorage、sessionstorage
   localstorage:除了主动删除数据,否则永远存在浏览器,关闭浏览器也存在
   使用:
       localStorage.setItem('data', JSON.stringify(item))
       JSON.parse(localStorage.getItem('data'))
       localstorage.removeItem('data')
   sessionstorage:临时保存,不能跨页面,关闭浏览器就会删除
   
//var、let、const
   1.块级作用域
       letconst具有块级作用域,var不存在块级作用域,块级作用域解决了ES5中的两个问题:
        1.内层变量可能覆盖外层变量
        2.用来计数的循环变量泄露为全局变量

   2. 变量提升
       var存在变量提升,letconst不存在变量提升,变量只能在声明之后使用,否则会报错

   3.重复声明
       var可以重复声明变量,后同名变量覆盖前面的变量,constlet不允许重复声明变量

   4.暂时性死区
       var声明变量不存在暂时性死区,letconst在未声明变量前不可使用 ,称为暂时性死区

   5.初始值设置
       varlet 声明时可不设置初始值,const声明时必设初始值

   6.指针指向
       varlet 声明的值可以修改,const声明常量不能修改
   
//this指向
   1普通函数中,this指向全局对象window
   2.作为对象的方法调用,this指向调用这个函数的对象
   3.作为事件的处理函数时,this指向触发事件的元素
   4.构造函数中,this指向new出来的新对象
   5.定时器中,this指向window
   6.箭头函数中,this指向父级中的this
   7.严格模式中,this指向undefined
//call、apply、bind
   call:函数名.call(调用者, 参数1, …) 作用:函数被借用时,会立即执行,并且函数体内的this会指向借用者或调用者
   apply:函数名.apply(调用者, [参数, …]) 作用:函数被借用时,会立即执行,并且函数体内的this会指向借用者或调用者
   bind:函数名.bind(调用者, 参数, …) 作用:函数被借用时,不会立即执行,而是返回一个新的函数。需要自己手动调用新的函数来改变this指向
   

//get、post
   长度限制:get请求在URL中传送的参数是有长度限制的,而post没有
   缓存:get会主动缓存,post不缓存
   参数:get参数通过URL传递,post放在Request body中
   参数类型:get只接受ASCII字符,而post没有限制
   安全性:get的参数在url中相对post不安全,post相对安全参数不会在浏览器历史中
//字符串首尾空格
   trim、replace+正则
//分割字符串
   split
   
//构造函数和普通函数区别
   首字母大写
   需要new一下

//浅拷贝/深拷贝,实现方式
   浅拷贝:浅拷贝共用一个引用地址
   深拷贝:深拷贝会创建新的内存地址
   
   浅拷贝:
         1....运算符
         2.Object.assign()
         3.Array.prototype.concat()
         4.Array.prototype.slice()
   深拷贝:
         1.递归函数
         	不足:1.时间和空间消耗比较大
				2.栈溢出:每个进程的栈容量是有限的,由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多
         2.JSON.parse(JSON.stringify())
			不足:1.如果对象有函数,函数无法被拷贝下来
				 2.无法拷贝对象原型链上的属性和方法
         
//闭包函数,优缺点
   函数嵌套,内部函数可以访问外部函数的变量
   优点:1.可以访问到函数内部的局部变量
        2.可以避免全局变量的污染
        3.变量的值始终保持在内存中,不会在外层函数调用后被自动清除
   缺点:会增大内存使用量,滥用闭包会影响性能,导致内存泄漏等问题
  
//继承的方式
   1.原型链继承
   2.构造函数继承
   3.构造函数+原型链继承
   4.寄生组合继承
   5.class继承

//事件循环机制、同步异步、宏任务、微任务
   eventlop:js是单线程的,一次只能执行一次任务,所有任务可以分为同步任务和异步任务
   			1.所有同步任务都在主线程上执行,形成一个执行栈
             2.主线程之外,还存在一个任务队列(task queue),只要异步任务有了运行结果,就在任务队列之中放置一个事件
			3.一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件,那些对应的异步任务,
            	于是结束等待状态,进入执行栈,开始执行
             4.主线程从任务队列中读取事件,这个过程是循环不断的
   事件循环机制:指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制(指js代码的执行顺序)
   宏任务:script、setTimeoutsetInterval、ajax、dom事件
   微任务:then、async/await、nextTick
   进程:进程可以有多个线程,是操作系统资源分配的基本单位
   线程:是进程的一部分,是CPU调度和分派的基本单位
   同步:主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
   异步:不进入主线程、而进入任务队列的任务,只有任务队列通知主线程,异步任务可以执行了,该任务才会进入主线程执行
   执行顺序:同步->微任务->宏任务
//js为什么是单线程
    js主要实现浏览器与用户的交互以及dom的操作,如果js是多线程,如果一个线程要删除这个dom,另一个线程要修改
    这个dom,这是浏览器就没法操作了,为了避免复杂的操作,所以js是单线程的

//事件冒泡、捕获
   事件三个阶段:捕获阶段、目标阶段、冒泡阶段
   冒泡:事件从内向外传播
   捕获:事件从外向内捕获
   阻止冒泡:
      1.event.stopPropagation();
      2.event.cancelBubble=true
   阻止默认行为:
      1.e.preventDefault()
      2.e.returnValue=falseIE3.return false (函数末尾)
//事件委托
   把原本需要绑定在子元素上的事件委托给父元素,让父元素担当事件监听的职务,事件委托的原理是DOM元素的事件冒泡
   优点:
        1.可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件
        2.可以实现当新增子元素时无需再次绑定

    
//字符串的方法
    concat():连接
    replace():替换
    split()
    indexOf()
    toLowerCase():转小写
    toUpperCase():转大写
    substring(start,end)
    slice(start,end)
    substr(start,length)
//数组的方法
    push():末尾添加
    pop():末尾删除
    unshift():首位添加
    shift():首位删除
    join()
	split():用指定分隔符将字符串分割成数组,返回新数组
    concat():连接两个或多个数组,返回新数组
    includes()
    splice(index,len,[item])
    sort(a,b):数组排序
    reverse:翻转数组
    
//正则的方法
    test():reg.test(str)
    exec()
    search()

//ne操作符做了什么
	1. 创建一个新的对象obj
    2. 设置原型,将对象的原型设置为函数的 prototype对象
    3. 将构造函数中的this绑定到新建的对象obj上
    4. 判断函数的返回值类型,是值类型返回创建的对象,是引用类型就返回这个引用类型的对象


//ajax
	ajax指异步JavaScriptXML,是一种创建交互式网页应用的技术。Ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。传统的网页(不使用Ajax)如果需要更新内容,需要重载整个网页
//ajax工作原理
    Ajax的工作原理相当于在用户和服务器之间加了一个中间层(Ajax引擎),使用户操作与服务器响应异步化。并不是所有用户请求都提交服务器。像一些数据验证和数据处理等都交给Ajax引擎自己来做,只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求
//ajax执行流程
    1.创建XMLHttpRequest对象,也就是创建一个异步调用对象
    2.创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
    3.设置响应HTTP请求状态变化的函数(打开链接open())
    4.发送HTTP请求(发送send())
    5.数据接收完成,判断http响应状态(status) 200~300之间或304(缓存)执行回调函数
    6.使用JavaScriptDOM实现局部刷新

//ajax优点
    1.局部刷新页面,减少用户心理和实际的等待时间,带来更好的用户体验
    2.按需取数据,减轻服务器的负担,最大程度减少冗余请求
    3.异步方式与服务器通信,不需要打断用户的操作,具有更加迅速地响应能力
    4.基于xml标准化,并被广泛支持,不需要安装插件等,进一步促进页面和数据的分离

//ajax缺点
    1.本身是针对MVC编程,不符合前端MVVM的浪潮
    2.基于原生XHR开发,XHR本身的架构不清晰
    3.不符合关注分离(Separation of Concerns)的原则
    4.配置和调用方式非常混乱,而且基于事件的异步模型不友好


//Fetch
	Fetch是基于promise设计,不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象
//fetch的优点:
    1.语法简洁,更加语义化
    2.基于标准 Promise 实现,支持 async/await
    3.更加底层,提供的API丰富(request, response)
    4.脱离了XHR,是ES规范里新的实现方式

//fetch的缺点:
    1.fetch只对网络请求报错,对400500都当做成功的请求,服务器返回 400500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
    2.fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: 'include'})
    3.fetch不支持abort,不支持超时控制,使用setTimeoutPromise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
    4.fetch没有办法原生监测请求的进度,而XHR可以

//axios
    在浏览器中创建XMLHttpRequest请求
    在node.js中发送http请求
    支持Promise API
    拦截请求和响应
    转换请求和响应数据
    取消要求
    自动转换JSON数据
    客户端支持防止CSRF/XSRF(跨域请求伪造)


//图片懒加载
	https://blog.csdn.net/qq_44947815/article/details/125286969
	目的:避免页面一次性向服务器发送大量请求,导致服务器响应变慢,最终导致页面卡顿、崩溃等现象
	原理:先将img标签的src链接设为同一张图片,然后给img标签设置自定义属性(比如 data-url),然后将真正的图片地址存储在data-url中,当JS监听到该图片元素进入可视窗口时,将自定义属性中的地址存储到src属性中,达到懒加载的效果
	方法:
    	1.滚动监听+scrollTop+offsetTop+innerHeight
		2.滚动监听+getBoundingClientRect()
		3.intersectionObserve()
//垃圾回收机制

vue

//虚拟dom
	用一个js对象去描述一个dom节点,是对真实dom的抽象,当状态变更时,去对比新树和旧树的差异,最后把差异更新到真正的dom中,相当于在js和真实dom之间做个缓存,利用patch(diff算法)对比新旧虚拟dom记录到一个对象中按需更新,最后创建真实的dom
    优点:
    	1.减少dom操作,降低浏览器性能消耗
        2.跨平台,虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM ,可以进行更方便地跨平台操作
    缺点:首次渲染慢
    
//原生dom慢的原因
    更新页面,只能通过首先查找dom对象,再进行修改dom的方式来达到目的。 但这种方式相当消耗计算资源, 因为每次查询 dom ,都需要遍历整颗 dom 树

//MVVM
    1.是什么 2.两者同步 
    View:视图层,Model 数据模型,而 ViewModel 是把两者建立通信的桥梁,实现了dom监听和双向绑定
    在 MVVM 框架下,ViewModel 之间没有直接的联系,而是通过 ViewModel 进行交互。ViewViewModel 之间以及 ModelViewModel 之间的交互都是双向的,因此 view 数据的变化会同步到 Model 中,而 Model 数据的变化也会立即反映到 View 上。可以说它们两者是实时更新的,互相影响。 ViewModel 通过双向数据绑定把 View 层和Model 层连接了起来,而 ViewModel 之间的同步工作完全是自动的,因此开发者只需要关注业务逻辑,不需要手动操作 DOM,也不需要关注数据状态的同步问题,这些都由 MVVM 统一管理
	优点
        1. 分离视图和模型,降低代码耦合
        2. 独立开发,可以专注于业务逻辑和数据的开发(ViewModel3. 可复用性,可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑
        4. 提可测试性: ViewModel的存在可以帮助开发者更好地编写测试代码
    缺点
        1.Bug很难被调试: 因为使⽤双向绑定的模式,当界⾯异常,有可能是View的代码有Bug,也可能是Model的代码有问题
        2.虽然使用Model方便了保证数据一致性,但是大的模块中长期不释放内存就会造成花费更多的内存
        3.对于⼤型的图形应⽤程序,视图状态较多,ViewModel的构建和维护的成本都会⽐较⾼
//MVC
	MVCModel-View-Controller,代表模型-视图-控制器
    model:用于处理数据逻辑部分
    view:用于显示视图部分
    controller:用于处理用户交互部分,
    MVC核心:controller负责将model的数据用view显示出来  
        
        
//MVVM、MVC区别
	1.主要就是mvc中Controller演变成mvvm中的viewModel。 mvvm主要解决了mvc中大量DOM操作使页面渲染性能降低,加载速度变慢的问题
	2.MVVMMVC最大区别是实现了model与view的自动同步,当model的属性改变时,不用在手动操作dom元素,来改变view的显示,而是view层显示会自动修改
	3.简化了业务与视图的依赖,还解决了数据频繁更新操作dom的问题
    
//双向绑定
    双向数据绑定是采用数据劫持结合发布者订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的getter和setter,在数据变动时发布消息给订阅者,触发相应的监听回调,getter函数里面执行的任务是watcher订阅者,而setter函数执行的任务是发布者

   1.实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,当对象属性有变化时可拿到最新值并通知订阅者
   2.实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
   3.实现一个Watcher,作为连接ObserverCompile的中间桥梁,能够订阅并收到每个数据对象属性变动的通知,执行指令绑定的相应回调函数,从而达到更新视图的目的
   4.mvvm入口函数,整合以上三者

//通信方式
    1.props、$emit
    2.ref
    3.$parent、$children
    4.eventBus中间栈
    	原理:订阅发布者模式
        1.挂载全局上
        2.新建evnetBus.js引入vue
    	eventBus.$emit('handClick','111')
		eventBus.$on('handClick',(val)=>{
            console.log(val)
        })
		eventBus.$off()销毁
    5.provice、inject:祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量
    6.vuex
    7.缓存
//data为什么是函数
    组件中的data写成函数,数据会以函数返回值的形式定义,每复用一次组件都会返回一个新的data,类似于给每个组件实例创建	一个私有数据空间,每个组件实例维护各自的数据,如果写成对象形式,每个组件会共用一个data,如果要修改一个属性,都会	  随着改变

//watch、computed、methods、filter、自定义指令及优先级
    优先级:props>methods>data>components>watch
	watch:支持异步监听,不支持缓存,监听数据是data、props里的数据,数据变化会触发immediate、deep
    	场景:需要在数据变化时执行异步或开销较大的操作
    computed:不支持异步,支持缓存,依赖于其他属性的变化,默认使用get方法,数据变化触发set方法,传参return一个函数
	methods:不会缓存、函数调用
	filter:
		用来过滤模型数据,在显示之前进行数据处理和筛选
         单位转换、数字打点、文本格式化、时间格式化之类,比如要实现将30000 => 30,000
		全局过滤器:Vue.filter(过滤器ID,过滤器函数)
		    <h3>{{8|addZero}}</h3>
            Vue.filter('addZero',function(data){
                 return data<10?'0'+data:data  
            });
		局部过滤器:
        	<h3>{{12.3456789|number(3)}}</h3>
            filters:{
                 number:(data,n)=>{
                   return data.toFixed(n)
                 }
             }
	自定义指令:
//nextTick
    原理:
        vue是异步更新dom的,一旦观察到数据变化,vue就会开启一个队列,然后把在同一事件循环当中观察到的数据变化			watcher推送进这个队列,如果这个watcher被触发多次,只会被推送到队列一次,这种缓冲行为可以有效去掉重复数据			造成的不必要的计算和dom操作,可以提高渲染效率
        如果要获取更新后的dom,可使用vue内置的$nextTick方法,参数是一个函数	
    应用:
    	用于处理数据动态变化,dom还未及时更新的问题,可以获取更新后的dom
//mixins
    vue提供的一种混合机制,能够更好的实现组件功能复用,混合对象(mixins)可以包含任意组件选项(data、created、mounted、methods、filters等),组件引入后相关选项会进行合并,相当于引入后,父组件各属性进行扩充;
    合并
        1. 对于data定义属性,组件中定义属性覆盖mixins中同名字段
        2. 对于created、mounted等生命周期函数,mixins中生命周期函数优先执行(执行顺序按mixins中顺序),再执行组			件中生命周期函数
        3. 对于methods中的同名方法,组件内的方法覆盖mixins中的方法
        4. 对于相同的computed属性,组件的computed属性覆盖mixins内的computed属性
        5. 而对于相同的watch监听,mixins中的watch监听先执行
        生命周期遵从“从外到内,再从内到外,mixins先于组件”的原则
        
//路由懒加载
    1.箭头函数+require
        {      
            path: '/problem',
            name: 'problem',
            component: resolve => require(['../pages/home/problemList'], resolve)    
        }
    2.箭头函数+import
        const Foo = () => import('../components/Foo')
        {
            path: '/Foo',
            name: 'Foo',
            component: Foo
        }
//路由模式
    1.hash:
		1.url中带#,请求时hash部分不会被发送
         2.刷新页面不会发生请求,页面不会有任何问题
         原理:通过 hashchange 事件监听 URL 的变化,location.hash()拿到url的值
         
    2.history
    	1.url没有#
        2.刷新页面会发送请求导致404,需要后端配合解决
        原理:主要由historyApi的pushState()和replaceState()来实现的
        	pushState可以改变url地址且不会发生请求
        	replaceState可以读取历史记录栈,可以对浏览器记录进行修改
            popstate 事件来监听 url 的变化,从而对页面进行跳转
    3.abstract
    		支持所有JavaScript运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式
//路由传参
    1.声明式路由router-link标签跳转
	2.编程式路由this.$router.push 
     1.path: `/describe/${id}`,获取:this.$route.params.id
         {
             path: '/describe/:id',
             name: 'Describe',
             component: Describe
         }
     2.params: {id: id},获取:this.$route.params.id
	3.query: {id: id},获取:this.$route.query.id    (url拼接)
       

//路由导航钩子
    全局钩子函数:
         beforeEach(to,from,next)前置守卫
		afterEach(to,from)后置钩子
     路由独享钩子:
      	beforeEnter(to,from,next)
     组件内导航钩子:
  	    beforeRouteEnter(to,from,next)不能获取组件实例this,因为组件还未创建
        beforeRouteUpdate(to,from,next)可以获取this,导航改变,组件被复用时调用
        beforeRouteLeave(to,from,next)可以获取this,导航离开组件时调用
//生命周期
   钩子函数: 8+2
   第一次页面加载会触发哪几个钩子
		beforeCreate, created, beforeMount, mounted
   父子执行顺序:
        加载阶段:父beforeCreate、父created、父beforeMount、子beforeCreate、子created、子beforeMount、子					mounted、父mounted
        父组件更新阶段:父beforeUpdate、父updated
        子组件更新阶段:父beforeUpdate、子beforeUpdate、子updated、父updated
        销毁阶段:父beforeDestroy、子beforeDestroy、子destroyed、父destroyed
    在哪个阶段有$el,$data
        beforeCreate   el无   data无
        created        el无   data有
        beforeMount    el无   data有
        mounted        el有   data有
   每个周期具体适合哪些场景
        beforecreate : 可以在这加个loading事件,页面加载完成之后将loading移除
        created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
        mounted : 挂载元素,获取到DOM节点
        updated : 如果对数据统一处理,在这里写上相应函数
        beforeDestroy : 可以做一个确认停止事件的确认框 nextTick : 更新数据后立即操作dom
        destroyed:事件的解绑,监听的移除,定时器的清除等
//keep-alive
       包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
		原理:在 created钩子函数调用时将需要缓存的 VNode 节点保存在 this.cache 中/在 render(页面渲染时,如果 			   VNode 的 name 符合缓存条件(可以用 include 以及 exclude 控制),则会从 this.cache 中取出之前缓			      存的 VNode实例进行渲染
        参数:
            include - 字符串或正则表达式,只有名称匹配的组件会被缓存。
            exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存,优先级比 include 高
            max - 数字,最多可以缓存多少组件实例,超出上限使用LRU的策略置换缓存数据
	    生命周期变化:
            1.activated
                - 在 keep-alive 组件激活时调用
                - 该钩子函数在服务器端渲染期间不被调用
            2.deactivated
                - 在 keep-alive 组件停用时调用
                - 该钩子在服务器端渲染期间不被调用
                - 被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated
                - 使用 keep-alive 会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要activated 					阶段获取数据,承担原来 created 钩子函数中获取数据的任务

//vuex
  state 、mutation、action、getter、module
  优点
       1.数据存储是响应式的方便集中管理,利于后期维护
  缺点:
       1.刷新丢失数据
  使用场景
        登录状态、用户名称、头像、商品的收藏、购物车等
  
  state
       使用:this.$store.state.name
  mutation
       只能同步操作
  action
      异步操作,类似于mutation,不同的是action提交的是mutation,不是直接变更状态
        
  getter
       读取操作,类似computed
  module
       模块化
// v-model 实现原理
    v-model在内部为不同的输入元素使用不同的 property 并抛出不同的事件
    text 和 textarea 元素使用 value property 和 input 事件;
    checkbox 和 radio 使用 checked property 和 change 事件;
    select 字段将 value 作为 prop 并将 change 作为事件。
    简单点来说就是表单 input 加 value的语法糖
   
//权限
   1.菜单权限:vuex+缓存
   2.界面权限:路由导航钩子防止跳过登录页面
   3.按钮权限:使用自定义指令
   4.请求(请求头添加token)、响应拦截(响应码400401...)
//elm怎么做表单验证
   form表单中提供的rules使用正则或自定义校验规则
//input循环校验
   
//v-if、v-show
   1.渲染条件:v-if条件不成立删除dom,v-show控制显示隐藏
   2.性能区别:v-if更高的切换开销,v-show更高的初始化开销
   3.生命周期:v-if每次切换会走一次生命周期,v-show只有初始化走生命周期
   4.使用场景:频繁切换用v-show,条件很少改变时用v-if
   v-show不支持<template> 语法:因为v-show是通过display来控制标签进行渲染的,但是template 标签在vue解析后是不会显示在页面上的 ,是虚拟Dom ,所以不可以,v-if是条件渲染,只要满足v-if后的条件就可以完成渲染

//v-for、v-if优先级
   一起使用会带来性能消耗问题
   vue2:v-for优先级高于v-if
   vue3:v-if优先级高于v-for
   可以在计算属性中进行过滤、再遍历渲染
//单向、双向数据流
   单向:一个组件单方向将数据流向内部组件,也就是父组件流向子组件,但子组件不能修改这个数据,可以在父组件中修改重新流向子组件,从而达到更新数据的原理
   双向:双向绑定
//new Vue()做了什么
    1.创建$options
        合并Vue.options
            一个是Vue的构造函数(vm.constructor)预先定义的
            一个是new Vue时传入的入参对象
    2.initLifecycle(vm)
    	初始化实例对象的生命周期状态,如:$parent、$children、$refs、$root、
    3.initEvents(vm)
    	创建实例对象的_events成员,包含父组件绑定在当前组件的事件
    4.initRender(vm)
    	设置实例对象的$slots和$scopedSlots、$createElement、$attrs、$listeners
    5.beforeCreate()
    	触发beforeCreate 函数
    6.initInjections(vm)
    	初始化组件的inject;通过逐级查找,从父级provide中获取子级组件inject定义的属性值,并增加对该属性的监听
    7.initState(vm)
    	初始化组件内的props、methods、data、computed、watch
    8.initProvide
    	初始化组件的provide
    9.created()
    	触发created 函数
    10.mount(el)
    	进入挂载阶段
//export 与export default 区别
    1.exportexport default均可用于导出常量、函数、文件、模块等
    2.在一个文件或模块中,exportimport可以有多个,export default仅有一个
    3.通过export方式导出,在导入时要加{ },export default则不需要
    4.输出单个值,使用export default;输出多个值,使用export export default与普通的export不要同时使用
//数组怎么监听
    1. 数组考虑性能原因没有用 defineProperty 对数组的每一项进行拦截,
    2. 而是选择对7种数组(push,shift,pop,splice,unshift,sort,reverse)方法进行重写(AOP切片思想)
    3. 所以在 Vue 中修改数组的索引和长度无法监控到
//vue中为什么必须加上key
    原理:key 的作用主要是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确,更快的找到对应的vnode节点判断两个节点是否是同一个,从而避免频繁的更新元素,使得整个patch过程更加高效,减少DOM操作量,提高性能
	必要性:当我们对数据进行更新的时候,譬如在数组中插入、移除数据时,设置的key值能让vue底层高效的对新旧vnode进行diff,然后将比对出的结果用来更新真实的DOM
// 涉及视图更新,你会用什么方式来变更数组
    1.Vue.set()
    2.数组splice方法   Array.prototype.splice
    3.this.$forceUpdate()强制刷新
    4.es6 "…"扩展运算符
//为什么 Object.defineProperty 明明能监听到数组值的变化,而 Vue 却没有实现
    因为 Vue 是对数组元素进行了监听,而没有对数组本身的变化进行监听
    - 性能原因的考量,给每一个数组元素绑定上监听,实际消耗很大而受益并不大
    - 对数据的操作更常用的操作数组的方法是使用数组原型上的一些方法如 push、shift 等来操作数组。
    - Object.defineProperty是对象上的方法,用来对数组的下标进行检测,会改变数据本来的性质
//订阅者和发布者模式
	它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察者对象。它是由两类对象组成,主题和观察者,主题负责发布事件,同时观察者通过订阅这些事件来观察该主题,发布者和订阅者是完全解耦,彼此不知道对方的存在,两者仅仅共享一个自定义事件的名称
    Dep类:负责依赖收集,所有订阅信息会保存在subs数组中
    Watcher类:负责订阅事件,订阅者调用add向subs中存入回调
	class Dep{
		constructor(){
            this.subs=[]
        }
        add(sub){
            if(sub && sub.update){
                this.subs.push(sub)
            }
        }
        removeSub(){
            if(this.subs.length){
                let index=this.indexOf(sub)
                if(index > -1){
                    this.subs.splice(index,1)
			   }
            }
        }
        notify(){
            this.subs.forEach(item=>{
                item.update()
            })
        }
    }



	class Watcher{
        updata(){
            console.log(22)
        }
    }
	let watcher1=new Watch()
	let dep=new Dep()
    dep.add(watcher1) //添加观察者
	dep.notify()      //发布
//Vue、React区别
	1.监听数据变化的实现原理不同监听数据变化的实现原理不同
    2.数据流不同
    3.HoC 和 mixins
    4.组件通信的区别
    5.模板渲染方式的不同
    6.VuexRedux 的区别
//项目优化
    1.编码阶段
        避免同时使用v-if,v-for,使用v-for时必须加上key,元素绑定事件时使用事件代理
        图片懒加载
        路由懒加载
        防抖,节流
        使用keep-alive
        UI框架按需加载
        长列表滚动到可视区域动态加载
    2.SEO优化
        预渲染
        服务端渲染SSR
    3.打包优化
        图片资源的压缩
        压缩代码
        使用cdn加载第三方模块

css

//布局方式
弹性盒子、%、rem、rpx、@media、grid网格布局
//盒模型
	标准(W3C)盒模型:margin 、padding、border、 content,content 部分不包括其他部分
	IE盒模型:margin、content(border + padding + content) ,content 部分包含padding+border +content
	css转换盒模型:box-sizing:content-box //标准盒模型(默认)
                  box-sizing:border-box //IE盒模型

//z-index什么情况下会失效
    z-index值越大就越是在上层,z-index元素的position属性需要是relative,absolute或是fixed
    1.父元素position为relative时,子元素的z-index失效
    	解决:父元素position改为absolute或static
    2.元素没有设置position属性为非static属性
    	解决:设置该元素的position属性为relative,absolute或是fixed中的一种
    3.元素在设置z-index的同时还设置了float浮动
    	解决:float去除,改为display:inline-block

//BFC
	BFC块级格式化上下文(Block Formatting Context),就是页面上一个隔离的独立容器,容器内的子元素不会影响外面的元素
	作用:
        1.解决margin的重叠问题:由于BFC是一个独立的区域,内部的元素和外部的元素互不影响,将两个元素变为两个BFC,就		解决了margin重叠的问题
        2.解决高度塌陷的问题:子元素设置浮动,父元素会发生高度塌陷,高度变为0 解决:把父元素变成一个BFC,给父元素		设置overflow:hidden
        3.创建自适应两栏布局:可以用来创建自适应两栏布局:左边的宽度固定,右边的宽度自适应
	形成条件:
    	1.float的值不是none
        2.position 值是 absolute、fixed,不是static或者relative
        3.display值是 inline-block,table-cell,table-caption,flex,inline-flex
        4.overflow值是 hidden、auto、scroll,不是visible

       
        
//清除浮动
    1. 父级div定义height
    2. 浮动元素的父标签添加 overflow 为 hidden 或 auto,触发BFC
    3. 新加一个标签,并添加样式 clear:both
    4. 用after伪元素清除浮动(用于非IE浏览器)
    5. 父级 div 定义 zoom(空标签元素清除浮动而不得不增长无心义代码的弊端,使用zoom:1用于兼容IE//垂直居中
	水平居中
        1. 行内元素: text-align:center
        2. 块级元素: margin:0 auto
        3. 绝对定位和移动: absolute + transform
        4. 绝对定位和负边距: absolute + margin
        5. flex布局: flex + justify-content:center
     垂直居中
        1.子元素为单行文本: line-height:height
        2.absolute + transform
        3.flex + align-items:center
        4.table: display:table-cell; vertical-align: middle
        5.利用position和top和负margin
	水平垂直居中
    	已知宽高:
             1.absolute+margin:auto
             2.absolute+margin-top+margin-left
             3.absolute+transform
             4.flex + justify-content + align-items
        未知宽高:
             1.absolute+top:50%+left50% + translate(-50%,-50%)
             2.flex+ justify-content + align-items
             3.父元素display: table-cell
			
    	

//避免样式冲突
    scoped、css模块化
//样式穿透
    /deep/
    ::v-deep
  	>>>
//css权重
    标签,class,id,属性,伪元素,伪类,兄弟选择器,子选择器,后代选择器,通配符
    !important>内联>id>class>tag     @layer
	内联               1000
	id                 100
	class、属性、伪类   10
	tag、伪元素         1
	通配符              0
//回流和重绘
    回流必将引起重绘,重绘不一定引起回流
    回流:当渲染树中元素的尺寸、布局发生改变时会重新构建,称为回流
    width、height、border、margin、padding、float、position、top、bottom、left、right、text-align、font-size
    重绘:渲染树中元素外观属性发生改变,不影响布局的称为重绘
    color、background、border-style、border-radius、box-shadow
//箭头向上三角形
    width:0;
    height:0;
    border-bottom:50px solid red;
    border-top:50px solid transparent;
    border-left:50px solid transparent;
    border-right:50px solid transparent;
//css新特性
	1.选择器
    	伪类、伪元素、属性
    2.圆角、阴影
    	圆角:4个值 border-radius:左上 右上 右下 左下
              3个值 border-radius:左上 (右上和左下) 右下
              2个值 border-radius:左上和右下 右上和左下
        阴影:box-shadow: 水平偏移量 垂直偏移量 模糊距离 阴影尺寸 阴影颜色 内/外阴影
    3.背景、渐变
    	背景:background-cilp裁剪区域
			 background-origin背景图像原始起始位置
			 background:color position size repeat origin clip attachment url1,url2
		渐变:background:linear-gradient(方向,开始颜色,结束颜色)——线性渐变
			 background:radial-gradient(形状尺寸,开始颜色,结束颜色)——径向渐变

    4.过渡
    5.变换
    	translate(x,y):位移
		scale(x,y):缩放
		rotate(deg):旋转
		skew(deg):倾斜
    6.动画      
		animation : name(名称) duration(持续时间) timing-function(过渡类型) delay(动画延迟时间) interation-count(运行次数) direction(动画是否反向播放) playstate(动画运行或者暂停)
    
//css变量
//屏幕三等分
//两栏布局

h5

一、canvas元素
	<canvas>元素负责在页面中设定一个区域,然后就可以通过 JavaScript 动态地在这个区域中绘制图形
二、表单元素
	表单元素:
    	header、footer、nav、section、article、main(语义化标签)
        datalist、progress、meter、keygen、output(增强型标签)
    表单属性:placeholder、reqired、pattern、max、min、step、autofocus、width、height
三、媒体元素
	音频:audio
    视频:video
四、地理定位
	使用getCurrentPosition()方法来获取用户的位置,从而实现队地理位置的定位
五、h5推拽
	通过给标签元素设置属性draggable值为true,能够实现对目标元素的拖动
六、web存储
	localStorage、sessionStorage
七、应用程序缓存
	可以在没有网络连接的情况下进行访问
八、h5 web workers
	在主线程之外运行,用于解决JS单线程中,持续较长的计算,而影响用户的交互
九、h5 服务器发送事件
	
十、h5 webSocket
	Web Worker通过加载一个脚本文件,进而创建一个独立工作的线程,在主线程之外运行,worker线程运行结束之后会把结果返回给主线程,worker线程可以处理一些计算密集型的任务,这样主线程就会变得相对轻松,这并不是说JS具备了多线程的能力,而实浏览器作为宿主环境提供了一个JS多线程运行的环境

http

//http协议
	http((HyperText Transfer Protocol)即超文本传输协议。是一个简单的请求-响应协议,它通常运行在TCP之上。运行于应用层。明文传输(无加密),它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式

//HTTP工作原理
    HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据

//http特点
    1.简单快速:客户向服务器请求服务时,只需要传送请求方法和路径。请求方法规定了客户与服务器联系的类型不
    同。由于http服务器的程序规模小,因而通信速度很快。
    2.灵活:http允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
    3.无连接:限制每一次连接只处理一个请求。服务器处理完客户的请求,并受到客户的应答后,即断开连接,可以
    节省传输时间
    4.无状态:协议对于事务处理没有记忆能力,如果后续需要处理前面的信息,必须重传,可能导致每次连接传送的
    数据量增大。
    5.支持B/S及C/S模式。
//http请求/响应步骤
	1.客户端连接到Web服务器
    一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://
    www.luffycity.com2.发送HTTP请求
    通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求
    数据4部分组成。
    3.服务器接受请求并返回HTTP响应
    Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响
    应头部、空行和响应数据4部分组成。
    4.释放连接TCP连接
    若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为
    keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
    5.客户端浏览器解析HTML内容
    客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若
    干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并
    在浏览器窗口中显示。
//HTTP请求消息
    分为4个部分
    1.请求行:用来说明请求类型,以一个方法符号开头,以空格分开,后面跟着请求的url和协议的版本
    2.请求头部:用来说明服务器要使用的附加信息
    3.空行:请求头部后面的空行是必须的
    4.请求数据:可以是任意类型
//HTTP响应
    分为4个部分:
    1.状态行:由http协议版本号,状态码,状态消息组成
    2.消息报头:用来说明客户端要使用的一些附加信息
    3.空行:消息报头后面的空行是必须的
    4.响应正文:服务器返回给客户端的文本信息

//响应码
  	1xx消息——请求已被服务器接收,继续处理
    2xx成功——请求已成功被服务器接收、理解、并接受
    3xx重定向——需要后续操作才能完成这一请求
    4xx请求错误——请求含有词法错误或者无法被执行
    5xx服务器错误——服务器在处理某个正确请求时发生错误
    200:请求成功。
    400:客户端请求有语法错误,不能被服务器理解。
    401:请求未经授权,这个状态码必须和WWW-Authenticate报头域一起使用。
    403:服务器收到请求,但拒绝提供服务。
    404:请求资源不存在。
    500:服务器发生不可预期的错误。
    503:服务器当前不能处理客户端的请求,一段时间后可能恢复正常
//http版本
    截止到现在,IETF已经发布了5HTTP协议了,包括HTTP0.9HTTP1.0HTTP1.1HTTP2HTTP3.
    HTTP0.9
		1991年发布, 没有header,功能非常简单,只支持GET
    HTTP1.0
        1996年发布,明文传输安全性差,header特别大。它相对0.9有以下增强:
            1.增加了header(使用元数据与数据解耦)
            2.增加了status code,用于声明请求的结果
            3.content-type可以传输其它文件
            4.支持get、head、post请求
            5.支持长连接(默认短连接),缓存机制以及身份认证
        缺点:每请求一次资源就新建一次tcp连接
    HTTP1.1
        1997发布,是现在使用最广泛的版本。它相对1.0有以下增强:
            1.可以设置keepalive让http重用tcp连接(请求必需串行发送)
            2.支持pipeline传输,请求发出后可以继续发送请求
            3.增加了HOST头,让服务端知道用户请求的是哪个域名
            4.增加了type、language、encoding等header
        2014年更新了内容:
            1.增加了TLS支持,即https传输
            2.支持四种模型:短连接,可重用tcp的长链接,服务端push模型(服务端主动将数据推送到客户端cache中),
            websocket模型
        缺点:还是文本协议,客户端服务端都需要利用cpu解压缩
    HTTP2
        2015年发布,主要是提升安全性与性能。它相对1.1的增强有:
            1.头部压缩(合并同时发出请求的相同部分)
            2.二进制分帧传输,更方便头部只传输差异部分
            3.多路复用,同一服务下只需要用一个连接,节省了连接
            4.服务器推送,一次客户端请求服务端可以多次响应。
        缺点:基于tcp传输,会有队头阻塞问题(丢包停止窗口滑动),tcp会丢包重传。tcp握手延时长,协议僵化问题。
     HTTP3
         2018年发布,基于谷歌的QUIC,底层使用udp代码tcp协议,
            这样解决了队头阻塞问题,同样无需握手,性能大大地提升,默认使用tls加密

//http的长轮询、短轮询、短连接、长连接
    短连接:客户端和服务端建立连接,发送完数据后立马断开连接。下次要取数据,需要再次建立连接。
	短连接的操作步骤是:建立连接——数据传输——关闭连接…建立连接——数据传输——关闭连接
	长连接:客户端和服务端建立连接后不进行断开,之后客户端再次访问这个服务器上的内容时,继续使用这一条连接通道
//https
    以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版。即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL

//http、https区别
    1.HTTP 是明文传输,HTTPS 通过 SSLTLS 进行了加密
    2.HTTP 的端口号是 80HTTPS443
    3.HTTPS 需要到 CA 申请证书,一般免费证书很少,需要交费
    4.HTTPS 的连接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络
    协议,比 HTTP 协议安全
//tcp协议
    主要解决数据如何在网络中传输
    TCPTransmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接
    
    
    
//tcp三次握手
    ①客户端请求建立连接发送syn包到服务器,并进入SYN_SENT状态,等待服务器确认
    ②服务端收到syn包,确认客户的SYN,同时也发送一个SYN+ACK包,进入SYN_RECV状态
    ③客户端收到SYN+ACK包,向服务端发送确认包ACK,发送完毕TCP连接成功,完成三次握手
//tcp四次挥手
	第一次挥手:客户端发送一个FIN报文,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态
    第二次挥手:服务端收到FIN后,发送一个ACK给客户端,服务端进入CLOSE_WAIT状态
    第三次挥手: 服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态
    第四次挥手:客户端收到FIN后,客户端进入TIME_WAIT状态,发送ACK给服务端,服务端进入CLOSED状态,完
    成四次握手
//在页面输入url到渲染完成发生了什么
	1.DNS 解析:浏览器向 DNS 服务器请求解析 URL 中的域名所对应的 IP 地址
    2.TCP 连接:TCP 三次握手
    3.发送 HTTP 请求
    4.服务器处理请求并返回 HTTP 报文
    5.浏览器解析渲染页面
    6.断开连接:TCP 四次挥手
//token认证 
	1.前端登录(传递uesrname和password参数给服务器)
    2.服务器到数据库查询用户信息是否存在
    3.数据库校验成功,生成token信息,返回给前端
    4.api请求header中携带token
    5.验证token是否有效,有效返回请求数据,无效返回错误状态码
//token优势
    1.服务端不需要存储和用户鉴权有关的信息,鉴权信息会被加密到Token中,服务端只需要读取Token中包含的鉴权信息即可
    2.避免了共享Session导致的不易扩展的问题。
    3.不需要依赖Cookie,有效的避免Cookie带来的CSRF攻击问题
    4.使用CORS可以快速解决跨域问题

浏览器缓存


缓存:浏览器在本地磁盘上将用户之前请求的数据存储起来,当需要修改数据时无需再次发生请求,直接从浏览器本地获取数据
缓存分为:强缓存、协商缓存

//强缓存
   1.不会向服务器发生请求,直接从本地缓存中获取数据
   2.请求资源状态码为200 ok
//协商缓存
   1.向服务器发送请求,服务器会根据请求头的资源判断是否命中协商缓存
   2.如果命中,则返回304状态码通知浏览器从缓存中读取资源
//共同点
   都是从浏览器读取资源

 //区别
   强缓存不发请求给服务器,协商缓存发送请求,根据返回信息决定是否使用缓存
   
//强缓存的header参数
   1.expires
   2.cache-control
//协商缓存的header参数
   1.Last-Modified
   2.ETag+If-None-Match

es6

//Symbol
let s1=Symbol() 
let s2=Symbol()
s1===s2       //false
let s1=Symbol('foo') 
let s2=Symbol('foo')
s1===s2       //false
typeof s1     //symbol

Symbol可以显式转换字符串,可以转换布尔值,但不能转换数值,不能与其他类型运算
let s1=Symbol() 
String(s1)
s1.toString()
Boolean(s1)
Symbol前不能使用new,否则会报错,因为Symbol是一个原始类型的值,不是对象,所以不能使用new关键字来调用
Symbol可以接受一个字符串作为参数,表示对Symbol实例的描述


方法
Symbol.for()
Symbol.keyFor()


//模板字符串
	1.可以折行
    2.${变量、表达式}
//解构赋值
	数组解构:
    对象解构:
    	1.对象属性没有顺序,但变量必须与属性同名,否则undefined
		

//promise理解
	一种特性:异步  两种结果:resolve、reject  三种状态:pending、fullfiled、rejected
   解决回调地狱的问题(多个串联的异步操作)
   一、特点
      1. 对象的状态不受外界影响:只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
      2. 一旦状态改变,就不会再变:只有两种可能:从pending变为fulfilled和从pending变为rejected
  二、用法
  	  Promise是一个构造函数,用来生成Promise实例
      Promise构造函数接受一个函数作为参数,这个函数有两个参数resolve,reject
	  resolve函数:将Promise对象的状态从未完成变成成功,在异步操作成功时调用,返回异步操作的结果
      reject函数:将Promise对象的状态从未完成变成失败,在异步操作时失败用
  三、Promise实例的方法
  	  then():当实例状态发生改变时候的回调函数,返回的是一个新的Promise实例,也就是Promise可以链式调用的原因
  	  catch():用于指定发生错误的回调函数
      finally():用来指定不管Promise对象状态如何,都会执行的结果
  
  缺点
       1.一旦新建会立即执行,无法取消
       2.不设置回调函数,Promise内部抛出的错误,不会返回到外部
       
  (三)、race、all和any的区别
         all:所有Promise的结果都返回resolve才会执行then,返回结果为一个存放所有结果的数组里,如果有任何一个返回reject,则执行catch,如果第一个Promise是有延迟执行的 则会等待执行完才继续,可实现发送多个请求,参数不一定是数组,只要有iterable接口就行,函数返回的是一个数组

        race:方法执行结果取决于第一个Promise的返回结果,reject则执行catch,resolve则执行then,不会等待定时器的执行,会将定时器时间执行时间短的结果返回
 
        any:有一个成功就算成功,全部失败才算失败
        
//async、await
    async :用来定义异步函数,会返回promise,可以使用  函数名.then(),当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句
	await :一般使用promise表达式,等待promise执行完,成功:拿到promise.resolve()的值,失败:拿到promise.reject的值
    promise:中包含catch  async需要自己定义  
    
//箭头函数
    1.this是静态的,指向不会改变,始终指向函数声明时所在作用域下的this的值
    2.call()、apply()、bind()等方法不能改变箭头函数中this的指向
    3.不能作为构造函数实例化对象(不能new),否则会抛出一个错误
    4.不能使用arguments变量
//new一个箭头函数会怎样
    箭头函数没有prototype,也没有自己的this指向,更不可以使用arguments参数,所以不能New一个箭头函数
//proxy代理
   在目标对象前架设拦截,外界对改对象的访问都必须通过这层拦截,因此提供一种机制,可以对外界的访问进行过滤和改写,Proxy可以代理某些操作,可称为代理器
   -get(targe,propKey,recevier):拦截对象属性的读取
   -set(targe,propKey,value,receiver) :拦截对象属性的设置
   -has(targe,propKey):拦截propKey in proxy的操作,返回一个布尔值
   -deleteProperty(target, propKey):拦截对象属性删除,返回布尔
        var person = {
          name: "张三"
        };
        var proxy = new Proxy(person, {
          get: function(target, propKey) {
            if (propKey in target) {
              return target[propKey];
            } else {
              throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");
            }
          }
        });
        console.log(proxy.name)

//class
    1.类的方法间不使用逗号隔开
    2.类内部定义的方法都是不可枚举的
    3.类必须使用new调用否则会报错
    4.属性、方法显式定义在this上,否则都在原型上
    5.类的所有实例共享一个原型对象
    6.新写法,实例属性可以放在类的最顶层
    class Point{}
    let p=new Point()
    p.constructor===Point.prototype.constructor   --true
    p.constructor===Point                         --true
    Point==Point.prototype.constructor            --true
	
	constructor:是类的默认方法,通过new生成对象实例时,自动调用,一个类必须有constructor方法,如果没有显式定义,				会默认添加一个空的constructor方法
	静态方法: 1.static使类中的方法不会被实例继承,而是直接通过类来调用
			2.静态方法和非静态方法可以重名
             3.父类静态方法,子类可以继承
              class Foo{
                static classMethod(){
                    console.log(this)  --thisFoo构造函数
                    return 'hello'
                }
              }
              Foo.classMethod()  --'hello'
              let foo=new Foo()
              foo.classMethod()  --实例上没有这个方法会报错
	静态属性:1.定义在类本身的属性
			class Foo{
                static prop=1
             }
	私有:只能在类的内部访问的方法和属性,外部不能访问
    私有属性、方法:在属性名、方法名之前使用#表示

//原型、原型链
   per.__proto__==Person.prototype
   Person.prototype.constructor==Person
   Person.prototype.__proto__==Object.prototype
   Object.prototype.constructor=Object
   Object.prototype.__proto__==null

   原型对象:每一个函数都有一个prototype的属性,默认对应一个空对象,这个空对象就是原型对象
   显式原型:利用prototype属性查找原型
   隐式原型:利用__proto__属性查找原型
   原型链:当访问对象的某个属性时会在对象本身属性上查找,如果没有会去它的__proto__隐式原型上去找,如果还没有就会在构造函数的prototype的__proto__中找,这样一层层向上查找形成一个链式结构,称为原型链

//set、map区别
    Set:成员不能重复;只有键值没有键名,类似数组;可以遍历,方法有add, delete,has,没有get
    Map:本质上是健值对的集合,类似集合;可以遍历,可以跟各种数据格式转换,可以使用get
		遍历方法:
        	const map = new Map([
                 ["foo",1],
                 ["bar",2],
            ])
        map.keys():foo、bar 
        map.values():12
        map.entries():["foo":1]、["bar":2]
        forEach():item:foo 、bar   value:12
//Object、Map、WeakMap
   Object:key为string或symbol(key无序)
   Map:key任意,可以使函数,对象,基本类型(key有序)
   WeakMap:key必须是对象(null除外),值任意

web安全

CSRF

//CSRF
CSRFCross-site request forgery):跨站请求伪造

// 2、CSRF的攻击原理
用户是网站A的注册用户,且登录进去,于是网站A就给用户下发cookie
完成一次CSRF攻击,受害者必须满足两个必要的条件:
(1)登录受信任网站A,并在本地生成Cookie。(如果用户没有登录网站A,那么网站B在诱导的时候,请求网站A的api接口时,会提示你登录)
(2)在不登出A的情况下,访问危险网站B(其实是利用了网站A的漏洞)。
温馨提示一下,cookie保证了用户可以处于登录状态,但网站B其实拿不到 cookie。


// 3、CSRF如何防御

方法一、Token 验证(用的最多)
(1)服务器发送给客户端一个token;
(2)客户端提交的表单中带着这个token。
(3)如果这个 token 不合法,那么服务器拒绝这个请求。


方法二:加入自定义header
把 token 隐藏在 http 的 head头中。
方法二和方法一有点像,本质上没有太大区别,只是使用方式上有区别。


方法三、Referer 验证:
Referer 指的是页面请求来源。意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截

方法四、加入验证码

方法五、尽量使用post
XSS攻击
//1.概念
XSS(Cross Site Scripting):跨域脚本攻击

//2.XSS攻击原理
不需做任何登录认证,会通过合法操作(比如在url中输入、评论框中输入),向页面注入脚本

//3.XSS攻击条件
1.需要向web页面注入恶意代码
2.这些恶意代码能够被浏览器成功的执行

//4.XSS攻击后果
盗用cookie破坏页面的正常结构,插入广告等恶意内容D-doss攻击

//5.XSS攻击方式
1.反射型
2.存储型

//6.XSS防范措施
1.编码
2.过滤
3.校正

webpack

将模块化依赖的文件打包成浏览器可以识别的静态资源文件

npm init -y              生成package.json
npm install webpack webpack-cli --save-dev   生成node_modules

npm install webpack-dev-server -g


webpack用于js的静态模块打包工具
//入口
entry:可以是字符串、数组、对象

//输出
output

//打包优化
	压缩代码
    cdn加速
    提取公共代码
//plugin和loader区别
	loader:把非js文件解析成webpack可以识别的文件
	plugin:插件,可以扩展webpack的功能,使webpack更加灵活
//webpack构建流程


同异步问题

 题目一   
async function async1() {
    console.log(1)
    await async2()
    console.log(2)
}
async function async2() {
    console.log(3)
}

console.log(4)

setTimeout(function () {
    console.log(5)
}, 0)

async1()

new Promise(function (resolve) {
    console.log(6)
    resolve()
}).then(function () {
    console.log(7)
})

console.log(8)
//  4 1 3 6 8 2 7 5
题目二
async function async1() {
    console.log('1')
    await async2()
    console.log('2')
}
async function async2() {
    console.log('3')
}
console.log('4')
setTimeout(function () {
    console.log('5')
}, 0)
async1()
console.log('6')
//4  1  3  2  6  5
题目三
function app() {
    setTimeout(() => {
        console.log('1')
        Promise.resolve().then(() => {
            console.log('2')
        })
    })

    console.log('3')
    Promise.resolve().then(() => {
        console.log('4')
        setTimeout(() => {
            console.log('5')
        })
    })
}
app()
// 3  4  1  2  5