那些重要的知识点

120 阅读26分钟

说一说cookie sessionStorage localStorage 区别?

需要答出:数据存储位置、生命周期、存储大小、写入方式、数据共享、发送请求时是否携带、应用场景

Cookie、SessionStorage、 LocalStorage都是浏览器的本地存储。 它们的共同点:都是存储在浏览器本地的 它们的区别:cookie是由服务器端写入的,而SessionStorage、 LocalStorage都是由前端写入的。

cookie的生命周期是由服务器端在写入的时候就设置好的,LocalStorage是写入就一直存在,除非手动清除,SessionStorage是页面关闭的时候就会自动清除。

cookie的存储空间比较小大概4KB,SessionStorage、 LocalStorage存储空间比较大,大概5M。

Cookie、SessionStorage、 LocalStorage数据共享都遵循同源原则,SessionStorage还限制必须是同一个页面。

在前端给后端发送请求的时候会自动携带Cookie中的数据,但是SessionStorage、 LocalStorage不会

由于它们的以上区别,所以它们的应用场景也不同,Cookie一般用于存储登录验证信息SessionID或者token,LocalStorage常用于存储不易变动的数据,减轻服务器的压力,SessionStorage可以用来检测用户是否是刷新进入页面,如音乐播放器恢复播放进度条的功能。

说一说JS数据类型有哪些,区别是什么?

JS数据类型分为两类:

一类是基本数据类型,也叫简单数据类型,包含7种类型,分别是Number 、String、Boolean、BigInt、Symbol、Null、Undefined。

另一类是引用数据类型也叫复杂数据类型,通常用Object代表,普通对象,数组,正则,日期,Math数学函数都属于Object。

数据分成两大类的本质区别:基本数据类型引用数据类型它们在内存中的存储方式不同。
基本数据类型是直接存储在栈中的简单数据段,占据空间小,属于被频繁使用的数据。
引用数据类型是存储在堆内存中,占据空间大。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。

说一说你对闭包的理解?

一般就是一个函数A,return其内部的函数B,被return出去的B函数能够在外部访问A函数内部的变量,这时候就形成了一个B函数的变量背包,A函数执行结束后这个变量背包也不会被销毁,并且这个变量背包在A函数外部只能通过B函数访问。

闭包形成的原理:作用域链,当前作用域可以访问上级作用域中的变量 闭包解决的问题:能够让函数作用域中的变量在函数执行结束之后不被销毁,同时也能在函数外部可以访问函数内部的局部变量。 闭包带来的问题:由于垃圾回收器不会将闭包中变量销毁,于是就造成了内存泄露,内存泄露积累多了就容易导致内存溢出。

说一说promise常见的方法:

pendding、rejected、resolved、 微任务、then、catch、Promise.resolve()、Promise.reject()、Promise.all() Promise.any()、Promise.race()

说一说跨域是什么?如何解决跨域问题?

当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了。
跨域限制的原因:浏览器为了保证网页的安全,出的同源协议策略。 跨域解决方案 :

cors:目前最常用的一种解决办法,通过设置后端允许跨域实现。
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader("Access-Control-Allow-Methods", "GET, PUT, OPTIONS, POST");

node中间件、nginx反向代理:跨域限制的时候浏览器不能跨域访问服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制。

JSONP:利用的原理是script标签可以跨域请求资源,将回调函数作为参数拼接在url中。后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成javascript。

postmessage:H5新增API,通过发送和接收API实现跨域通信。

块级格式化上下文BFC

1.定义:块级格式化上下文,独立的渲染区域,不会影响边界外的元素 MDN文档:任何一个元素,比如div,p,a,span在标准流里面必然属于某个FC div/p/h/ 属于BFC的布局中 a/span/i属于IFC的布局中

2.MDN文档上有整理出哪些具体的情况会创建BFC 根元素

浮动元素 float 的值不是none

绝对定位元素 position为fixed 或者 absolute

行内块元素 display:inline-block

表格单元格 display:table-cell 表格标题display:table-caption

匿名表格单元格元素

overflow 计算值(computed)不为 visible的块元素

弹性元素display:flex // display:inline-flex元素的直接子元素

网格元素display:grid 或者 inline-grid元素的子元素

display值为 flow-root

3.布局规则: a.区域内box从上到下排列 b.box垂直方向的距离由margin决定 c.同一个bfc内box margin会重叠 d.bfc不会与flaot重叠 e.bfc计算高度 也会计算float元素

  1. BFC有什么作用?

对MDN文档的BFC描述简单概括:

  • 在BFC中,box会在垂直方向上一个挨着一个排布

  • 垂直方向的间距有margin属性决定

  • 在同一个BFC中,相邻两个box之间的margin会折叠(coolapse)

  • 在BFC中,每个元素的左边缘是紧挨着包含块的左边缘的

说一说Vuex是什么,每个属性是干嘛的,如何使用 ?

定义: Vuex是集中管理项目公共数据的。

Vuex 有state、mutations 、getters、actions、module属性。

  • state 属性用来存储公共管理的数据。 mutations 属性定义改变state中数据的方法,
  • getters 属性可以认为是定义 store 的计算属性。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
  • action属性类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。
  • moudle属性是将store分割成模块。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块,从上至下进行同样方式的分割

使用方法

  • state :直接以对象方式添加属性

  • mutations :通过store.commit调用 action:通过 store.dispatch 方法触发

  • getters:直接通过store.getters.调用

  • 可以使用mapState、mapMutations、mapAction、mapGetters一次性获取每个属性下对应的多个方法。 VueX在大型项目中比较常用,非关系组件传递数据比较方便。

注意:不要在mutation中的方法中写异步方法ajax,那样数据就不可跟踪了

说一说JavaScript有几种方法判断变量的类型?

JavaScript有4种方法判断变量的类型,分别是typeofinstanceofObject.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型)

  • typeof:常用于判断基本数据类型,
  • 对于引用数据类型除了function返回function,其余全部返回object。 在判断null,[], {}的时候统统返回 object

image.png

  • instanceof:主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。

image.png

  • constructor:用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。

image.png

image.png

  • Object.prototype.toString.call(): 适用于所有类型的判断检测,检测方法是 Object.prototype.toString.call() 返回的是该数据类型的字符串。 这四种判断数据类型的方法中,各种数据类型都能检测且检测精准的就是Object.prototype.toString.call()这种方法。

image.png instanceof的实现原理:验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为true。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,找到返回true,未找到返回false。 Object.prototype.toString.call()原理:Object.prototype.toString 表示一个返回对象类型的字符串,call()方法可以改变this的指向, 那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果

说一说样式优先级的规则是什么?

!important > 内联样式(style) > ID选择器(id) > 类选择器(class) > 标签选择器

说一说Vue2.0 双向绑定的原理与缺陷?

Vue响应式指的是:组件的data发生变化,立刻触发试图的更新

原理: Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理。 通过原生js提供的监听数据的API,当数据发生变化的时候,在回调函数中修改dom

核心API:Object.defineProperty

Object.defineProperty API的使用 作用: 用来定义对象属性

特点: 默认情况下定义的数据的属性不能修改 描述属性和存取属性不能同时使用,使用会报错

响应式原理: 获取属性值会触发getter方法 设置属性值会触发setter方法 在setter方法中调用修改dom的方法

Object.defineProperty的缺点:

  1. 一次性递归到底开销很大,如果数据很大,大量的递归导致调用栈溢出

  2. 不能监听对象的新增属性和删除属性

  3. 无法正确的监听数组的方法,当监听的下标对应的数据发生改变时

说一说null 和 undefined 的区别,如何让一个属性变为null

undefind 是全局对象的一个属性,

  • 当一个变量没有被赋值
  • 一个函数没有返回值
  • 某个对象不存在某个属性却去访问或者函数定义了形参但没有传递实参,这时候都是undefined。 undefined通过typeof判断类型是'undefined'。undefined == undefined undefined === undefined

null代表对象的值未设置,相当于一个对象没有设置指针地址就是null。 null通过typeof判断类型是'object'。null === null null == null null == undefined null !== undefined

undefined 表示一个变量初始状态值,而 null 则表示一个变量被人为的设置为空对象,而不是原始状态。在实际使用过程中,不需要对一个变量显式的赋值 undefined,当需要释放一个对象时,直接赋值为 null 即可。 让一个变量为null,直接给该变量赋值为null即可。

null 其实属于自己的类型 Null,而不属于Object类型,typeof 之所以会判定为 Object 类型,是因为JavaScript 数据类型在底层都是以二进制的形式表示的,

二进制的前三位为 0 会被 typeof 判断为对象类型,

而 null 的二进制位恰好都是 0 ,因此,null 被误判断为 Object 类型。 对象被赋值了null 以后,对象对应的堆内存中的值就是游离状态了,GC 会择机回收该值并释放内存。因此,需要释放某个对象,就将变量设置为 null,即表示该对象已经被清空,目前无效状态。

说一下浮动?

  • 浮动的作用,设置浮动的图片,可以实现文字环绕图片,

  • 设置了浮动的块级元素可以排列在同一行,设置了浮动的行内元素可以设置 宽高,同时可以按照浮动设置的方向对齐排列盒子。

  • 设置浮动元素的特点: 设置了浮动,该元素脱标。元素不占位置 浮动可以进行模式转换(行内块元素)

  • 浮动造成的影响,使盒子脱离文档流。如果父级盒子没有设置高度,需要被子盒子撑开,那么这时候父级盒子的高度就塌陷了,同时也会造成父级盒子后面的兄弟盒子布局受到影响。如果浮动元素后面还有其他兄弟元素,其他兄弟元素的布局也会受到影响。

  • 清除浮动的方法: 伪元素清除浮动:给浮动元素父级增加

    .clearfix::after { 
    content: ''; 
    display: table; 
    clear: both; 
    } 
    /*兼容IE低版本 */ 
    .clearfix { *zoom: 1; } 
    

    overflow:hidden:给浮动元素父级增加overflow:hidden`属性

    额外标签法:给浮动元素父级增加标签

overflow:hidden:不会新增标签,但是如果父级元素有定位元素超出父级,超出部分会隐藏,在不涉及父级元素有超出内容的情况,overflow:hidden比较常用,毕竟写法方便简洁

标签插入法:清除浮动的语法加在新增标签上,由于新增标签会造成不必要的渲染

说说es6的箭头函数。

箭头函数最大的特点就是没有this,所以this是从外部获取,就是继承外部的执行上下文中的this,

由于没有this关键字所以箭头函数也不能作为构造函数, 同时通过 call()apply() 方法调用一个函数时,只能传递参数(不能绑定this),第一个参数会被忽略。

箭头函数也没有原型和super。不能使用yield关键字,因此箭头函数不能用作 Generator 函数。不能返回直接对象字面量。

说几个未知宽高元素水平垂直居中方法

  1. 设置元素相对父级定位position:absolute;left:50%;right:50%,让自身平移自身高度50% transform: translate(-50%,-50%);,这种方式兼容性好,被广泛使用的一种方式

  2. 设置元素的父级为弹性盒子display:flex,设置父级和盒子内部子元素水平垂直都居中justify-content:center; align-items:center ,这种方式代码简洁,但是兼容性ie 11以上支持,由于目前ie版本都已经很高,很多网站现在也使用这种方式实现水平垂直居中

  3. 设置元素的父级为网格元素display: grid,设置父级和盒子内部子元素水平垂直都居中justify-content:center; align-items:center ,这种方式代码简洁,但是兼容性ie 10以上支持

  4. 设置元素的父级为表格元素display: table-cell,其内部元素水平垂直都居中text-align: center;vertical-align: middle; ,设置子元素为行内块display: inline-block; ,这种方式兼容性较好

说一说 HashRouter 和 HistoryRouter的区别和原理?

标准回答 HashRouter和 HistoryRouter的区别:
    1. history和hash都是利用浏览器的两种特性实现前端路由,history是利用浏览历史记录栈的API实现,hash是监听location对象hash值变化事件来实现
    1. history的url没有'#'号,hash反之
    1. 相同的url,history会触发添加到浏览器历史记录栈中,hash不会触发,history需要后端配合,如果后端不配合刷新新页面会出现404,hash不需要。 HashRouter的原理:通过window.onhashchange方法获取新URL中hash值,再做进一步处理 HistoryRouter的原理:通过history.pushState 使用它做页面跳转不会触发页面刷新,使用window.onpopstate 监听浏览器的前进和后退,再做其他处理 加分回答 hash模式下url会带有#,需要url更优雅时,可以使用history模式。 需要兼容低版本的浏览器时,建议使用hash模式。 需要添加任意类型数据到记录时,可以使用history模式。

说一说map 和 forEach 的区别?

map创建新数组、map返回处理后的值;
forEach()不修改原数组、forEach()方法返回undefined

map 和 forEach 的区别:map有返回值,可以开辟新空间, return出来一个length和原数组一致的数组,即便数组元素是undefined或者是null。forEach默认无返回值,返回结果为undefined,可以通过在函数体内部使用索引修改数组元素。

map的处理速度比forEach快,而且返回一个新的数组,方便链式调用其他数组新方法,

   let arr = [1, 2, 3, 4, 5];
   let arr2 = arr.map(value => value *value).filter(value => value > 10); // arr2 = [16, 25]

说一说Vue3.0 实现数据双向绑定的方法 ?

得分点 Proxy、数据拦截、劫持整个对象、返回一个新对象、有13种劫持

Vue3.0 是通过Proxy实现的数据双向绑定,Proxy是ES6中新增的一个特性,实现的过程是在目标对象之前设置了一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

用法: ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。 var proxy = new Proxy(target, handler)

target: 是用Proxy包装的被代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

handler: 是一个对象,其声明了代理target 的一些操作,其属性是当执行一个操作时定义代理的行为的函数。

Object.defineProperty 的问题:在Vue中,Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。目前只针对以上方法做了hack处理,所以数组属性是检测不到的,有局限性Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue里,是通过递归以及遍历data对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象,不管是对操作性还是性能都会有一个很大的提升。 Proxy的两个优点:可以劫持整个对象,并返回一个新对象,有13种劫持

说一下Diff算法?

分点 patch、patchVnode、updateChildren、vue优化时间复杂度为O(n) 标准回答 Diff算法比较过程 第一步:patch函数中对新老节点进行比较 如果新节点不存在就销毁老节点 如果老节点不存在,直接创建新的节点 当两个节点是相同节点的时候,进入 patctVnode 的过程,比较两个节点的内部 第二步:patchVnode函数比较两个虚拟节点内部 如果两个虚拟节点完全相同,返回 当前vnode 的children 不是textNode,再分成三种情况 - 有新children,没有旧children,创建新的 - 没有新children,有旧children,删除旧的 - 新children、旧children都有,执行updateChildren比较children的差异,这里就是diff算法的核心 当前vnode 的children 是textNode,直接更新text 第三步:updateChildren函数子节点进行比较 - 第一步 头头比较。若相似,旧头新头指针后移(即 oldStartIdx++ && newStartIdx++),真实dom不变,进入下一次循环;不相似,进入第二步。 - 第二步 尾尾比较。若相似,旧尾新尾指针前移(即 oldEndIdx-- && newEndIdx--),真实dom不变,进入下一次循环;不相似,进入第三步。 - 第三步 头尾比较。若相似,旧头指针后移,新尾指针前移(即 oldStartIdx++ && newEndIdx--),未确认dom序列中的头移到尾,进入下一次循环;不相似,进入第四步。 - 第四步 尾头比较。若相似,旧尾指针前移,新头指针后移(即 oldEndIdx-- && newStartIdx++),未确认dom序列中的尾移到头,进入下一次循环;不相似,进入第五步。 - 第五步 若节点有key且在旧子节点数组中找到sameVnode(tag和key都一致),则将其dom移动到当前真实dom序列的头部,新头指针后移(即 newStartIdx++);否则,vnode对应的dom(vnode[newStartIdx].elm)插入当前真实dom序列的头部,新头指针后移(即 newStartIdx++)。 - 但结束循环后,有两种情况需要考虑: - 新的字节点数组(newCh)被遍历完(newStartIdx > newEndIdx)。那就需要把多余的旧dom(oldStartIdx -> oldEndIdx)都删除,上述例子中就是c,d; - 新的字节点数组(oldCh)被遍历完(oldStartIdx > oldEndIdx)。那就需要把多余的新dom(newStartIdx -> newEndIdx)都添加。

说一说vue钩子函数?

beforeCreate、created、beforeMounted、mounted beforeUpdate、updated 、 beforeDestroy、destroyed

钩子函数用来描述一个组件从引入到退出的全过程中的某个过程,整个过程称为生命周期。 钩子函数按照组件生命周期的过程分为,挂载阶段=>更新阶段=>销毁阶段。

每个阶段对应的钩子函数

  • 挂载阶段:beforeCreate、created、beforeMounted、mounted
  • 更新阶段:beforeUpdate、updated
  • 销毁阶段:beforeDestroy、destroyed

created:实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,不能访问到el属性,el属性,ref属性内容为空数组,常用于简单的ajax请求,页面的初始化

beforeMount:在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数

mounted:实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问常用于获取VNode信息和操作,ajax请求

beforeupdate:响应式数据更新时调用,发生在虚拟DOM打补丁之前,适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器

updated:虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作避免在这个钩子函数中操作数据,可能陷入死循环

beforeDestroy:实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例,常用于销毁定时器、解绑全局事件、销毁插件对象等操作

父子组件钩子函数在三个阶段的代码执行顺序 挂载:父亲created> 子created > 子mounted> 父亲mounted> 更新:父亲beforeUpdate > 子beforeUpdated > 子updated > 父亲updated 销毁:父亲beforeDestroy> 子beforeDestroy > 子destroyed> 父destroyed

说一说 Vue 列表为什么加 key?

为了性能优化 因为vue是虚拟DOM,更新DOM时用diff算法对节点进行一一比对,

比如有很多li元素,要在某个位置插入一个li元素,但没有给li上加key,那么在进行运算的时候,就会将所有li元素重新渲染一遍,

但是如果有key,那么它就会按照key一一比对li元素,只需要创建新的li元素,插入即可,不需要对其他元素进行修改和重新渲染。

key也不能是li元素的index,因为假设我们给数组前插入一个新元素,它的下标是0,那么和原来的第一个元素重复了,整个数组的key都发生了改变,这样就跟没有key的情况一样了

如何实现可过期的localStorage

主要是惰性删除,定时删除

localStorage只能用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。

所以要实现可过期的localStorage缓存的中重点就是:如何清理过期的缓存。

目前有两种方法,一种是惰性删除,另一种是定时删除

惰性删除是指某个键值过期后,该键值不会被马上删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。实现方法是,存储的数据类型是个对象,该对象有两个key,一个是要存储的value值,另一个是当前时间。实现过程 获取数据的时候,拿到存储的时间和当前时间做对比,如果超过过期时间就清除Cookie。

定时删除是指,每隔一段时间执行一次删除操作,并通过限制删除操作执行的次数和频率,来减少删除操作对CPU的长期占用。另一方面定时删除也有效的减少了因惰性删除带来的对localStorage空间的浪费。 实现过程,获取所有设置过期时间的key判断是否过期,过期就存储到数组中,遍历数组,每隔1S(固定时间)删除5个(固定个数),直到把数组中的key从localstorage中全部删除。

LocalStorage清空应用场景:token存储在LocalStorage中,要清空

说一说axios的拦截器原理及应用?

axios的拦截器的应用场景:

  • 请求拦截器用于在接口请求之前做的处理,比如为每个请求带上相应的参数(token,时间戳等)。

  • 响应拦截器用于在接口返回之后做的处理,比如对返回的状态进行判断(token是否过期),判断服务端给的状态码,从而方便前端纠错。

axios为开发者提供了这样一个API:拦截器。拦截器分为 请求(request)拦截器和 响应(response)拦截器。

拦截器原理:创建一个chn数组,数组中保存了拦截器相应方法以及dispatchRequest(dispatchRequest这个函数调用才会真正的开始下发请求),把请求拦截器的方法放到chn数组中dispatchRequest的前面,把响应拦截器的方法放到chn数组中dispatchRequest的后面,把请求拦截器和相应拦截器forEach将它们分unshift,push到chn数组中,为了保证它们的执行顺序,需要使用promise,以出队列的方式对chn数组中的方法挨个执行。

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求

支持 Promise API,可拦截请求和响应,可转换请求数据和响应数据,可取消请求,可自动转换 JSON 数据,客户端支持防御 XSRF

说一下浏览器如何渲染页面的?

  • 1、HTML被HTML解析器解析成DOM树。

  • 2、CSS被CSS解析器解析成CSS规则树。

  • 3、浏览器会将CSS规则树附着在DOM树上,并结合两者生成渲染树Render Tree。

  • 4、生成布局(flow),浏览器通过解析计算出每一个渲染树节点的位置和大小,在屏幕上画出渲染树的所有节点。

  • 5、将布局绘制(paint)在屏幕上,显示出整个页面

说一说跨域是什么?如何解决跨域问题?

跨域:当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了。

跨域限制的原因:浏览器为了保证网页的安全,出的同源协议策略。

跨域报错信息:

跨域解决方案
cors:目前最常用的一种解决办法,通过设置后端允许跨域实现。
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader("Access-Control-Allow-Methods", "GET, PUT, OPTIONS, POST");

node中间件、nginx反向代理:跨域限制的时候浏览器不能跨域访问服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面面和代理服务器是同源的,然后代理服务器再向后端服务器发请求,服务器和服务器之间不存在同源限制。

JSONP:利用的原理是script标签可以跨域请求资源,将回调函数作为参数拼接在url中。后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成javascript。

postmessage:H5新增API,通过发送和接收API实现跨域通信。

new 一个对象发生了什么事情?

new 关键字会进行如下的操作:

    1. 创建一个空的简单JavaScript对象(即{});
    1. 为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象 ;
    1. 将步骤1新创建的对象作为this的上下文 ;
    1. 如果该函数没有返回对象,则返回this

箭头函数不能执行第二,第三步 new关键字后面的构造函数不能是箭头函数。

说一下token 能放在cookie中吗?

能、不设置cookie有效期、重新登录重写cookie覆盖原来的cookie 标准回答 能。 token一般是用来判断用户是否登录的,它内部包含的信息有:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)

token可以存放在Cookie中,token 是否过期,应该由后端来判断,不该前端来判断,所以token存储在cookie中只要不设置cookie的过期时间就ok了,如果 token 失效,就让后端在接口中返回固定的状态表示token 失效,需要重新登录,再重新登录的时候,重新设置 cookie 中的 token 就行。

token认证流程 1. 客户端使用用户名跟密码请求登录 2. 服务端收到请求,去验证用户名与密码 3. 验证成功后,服务端签发一个 token ,并把它发送给客户端 4. 客户端接收 token 以后会把它存储起来,比如放在 cookie 里或者 localStorage 里 5. 客户端每次发送请求时都需要带着服务端签发的 token(把 token 放到 HTTP 的 Header 里) 6. 服务端收到请求后,需要验证请求里带有的 token ,如验证成功则返回对应的数据