前端面试题

monster-hash

发布日期: 2021-04-13 08:57:07 浏览量: 170
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

h5新特性

  1. 用于绘画 canvas 元素。

  2. 用于媒介回放的du video 和 audio 元素。

  3. 本地离线存储 localStorage 长期存储数据dao,浏览器关闭后数据不丢失;sessionStorage 的数据在浏览器关闭后自动删除。

  4. 语意化更好的内容元素,比如 article、footer、header、nav、section。

  5. 表单控件,calendar、date、time、email、url、search

    1.语义化标签

    语义化标签 为页面提供了更好的页面结构。

描述 属性
<header></header> 定义文档的头部区域
<footer></footer> 尾部区域
<nav></nav> 导航区域
<section></section> 段落
<article></article> 页面独立的内容区域
<aside></aside> 页面侧边栏内容
<command></command> 命令按钮
<details></details> 标签包含 details 元素的标题
<dialog></dialog> 对话框

2.增强型表单

HTML5 提供了多个新的表单输入类型。

输入类型 描述
color 主要用于选取颜色
date 从一个日期选择器选择一个日期
datetime 选择一个日期(UTC 时间)
datetime-local 选择一个日期和时间 (无时区)
email 包含 e-mail 地址的输入域
month 选择一个月份
number 数值的输入域
range 一定范围内数字值的输入域
search 用于搜索域
tel 定义输入电话号码字段
time 选择一个时间
url URL 地址的输入域
week 选择周和年

同时,还增加了新的表单属性:

1、placehoder 属性,简短的提示在用户输入值前会显示在输入域上。即我们常见的输入框默认提示,在用户输入后消失。

2、required 属性,是一个 boolean 属性。要求填写的输入域不能为空

3、pattern 属性,描述了一个正则表达式用于验证<input> 元素的值。

4、min 和 max 属性,设置元素最小值与最大值。

5、step 属性,为输入域规定合法的数字间隔。

6、height 和 width 属性,用于 image 类型的 <input> 标签的图像高度和宽度。

7、autofocus 属性,是一个 boolean 属性。规定在页面加载时,域自动地获得焦点。

8、multiple 属性 ,是一个 boolean 属性。规定<input> 元素中可选择多个值。  

 

3.音频和视频

HTML5 提供了 音频和视频 。

音频:<audio>

  1. <audio controls>
  2. <source src="xxx.ogg" type="audio/ogg">
  3. <source src="xxx.mp3" type="audio/mpeg">
  4. 您的浏览器不支持 audio 元素。
  5. </audio>

视频:<video>

  1. <video width="500" height="300" controls>
  2. <source src="xxx.mp4" type="video/mp4">
  3. <source src="xxx.ogg" type="video/ogg">
  4. 您的浏览器不支持Video标签。
  5. </video>

4.canvas 绘图

标签只是图形容器,必须使用脚本来绘制图形。

详情点这里…

5.SVG 绘图

SVG是指可伸缩的矢量图形

SVG 与 Canvas两者间的区别

1.SVG 是一种使用 XML 描述 2D 图形的语言。

2.Canvas 通过 JavaScript 来绘制 2D 图形。

3.SVG 基于 XML,这意味着 SVG DOM 中的每个元素都是可用的。您可以为某个元素附加 JavaScript 事件处理器。

4.在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。

5.Canvas 是逐像素进行渲染的。在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。

6.地理定位(Geolocation)

HTML5 Geolocation(地理定位)用于定位用户的位置。

  1. window.navigator.geolocation {
  2. getCurrentPosition: fn 用于获取当前的位置数据
  3. watchPosition: fn 监视用户位置的改变
  4. clearWatch: fn 清除定位监视
  5. }

获取用户定位信息:

  1. 复制代码
  2. navigator.geolocation.getCurrentPosition(
  3. function(pos){
  4.     console.log('用户定位数据获取成功')
  5.     //console.log(arguments);
  6.     console.log('定位时间:',pos.timestamp)
  7.     console.log('经度:',pos.coords.longitude)
  8.     console.log('纬度:',pos.coords.latitude)
  9.     console.log('海拔:',pos.coords.altitude)
  10.     console.log('速度:',pos.coords.speed)
  11. }, //定位成功的回调
  12. function(err){
  13.     console.log('用户定位数据获取失败')
  14.     //console.log(arguments);
  15. } //定位失败的回调
  16. )

7.拖放API

在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放

8.Web Storage

使用HTML5可以在本地存储用户的浏览数据。

客户端存储数据的两个对象为:

localStorage :没有时间限制的数据存储

sessionStorage : 针对一个 session 的数据存储, 当用户关闭浏览器窗口后,数据会被删除。

不管是 localStorage,还是sessionStorage,可使用的API都相同,常用的有如下几个(以localStorage为例):

  1、保存数据:localStorage.setItem(key,value);

  2、读取数据:localStorage.getItem(key);

  3、删除单个数据:localStorage.removeItem(key);

  4、删除所有数据:localStorage.clear();

  5、得到某个索引的key:localStorage.key(index);

9.WebSocket

WebSocket 是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。

两者之间就直接可以数据互相传送。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

vue知识点

v-show 与 v-if 区别

在Vue的内部指令中,v-show与v-if的区别,总结如下:

在Vue中,我们可以使用v-if和v-show来控制元素或模板的渲染。而v-if和v-show也属于Vue的内部常用的指令(条件渲染)。这里所说的指令就是directive,指特殊的带有前缀v-的命令,指令的值限定为绑定表达式,指令的职责是当表达式的值改变时把某些特殊的行为应用到DOM上。

v-show

除了v-if之外,Vue还提供v-show也可以控制元素的渲染。v-show和v-if功能有点相似,其中v-if依赖于控制DOM节点,而v-show是依赖于控制DOM节点的display属性。当v-show传入的值为true时,对应DOM元素的display的值为block之类的,反之为false时,display的值为none。也就是用户看不到元素的显示,但其DOM元素还是存在的。

v-if和v-show都能控制DOM元素的显示和隐藏,但是在切换v-if模块时,Vue有一个局部编译/卸载过程,因为v-if中的模板可能包括数据绑定或者子组件,v-if是真是的条件渲染,它会确保条件快在切换时合适的销毁与重建条件块内的时间监听器和子组件。

v-if 是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
v-if 有更高的切换开销,v-show有更高的初始渲染开销。如果需要频繁切换,则使用v-show 较好,如果运行条件不太可能改变,使用v-if较好。

这两个都是Vue的内部指令,而且都是用来控制元素的渲染。只不过,v-if判断是否加载,可以减轻服务器的压力,在需要时加载;v-show调整DOM元素的CSS的dispaly属性,可以使客户端操作更加流畅。虽然这两都都能很好的控制元素的渲染,但实际使用的时候,更应该根据自己的场景来判断使用哪一个指令。

  1. v-hsow和v-if的区别:
    v-show是css切换,v-if是完整的销毁和重新创建。
  2. 使用
    频繁切换时用v-show,运行时较少改变时用v-if
  3. v-if=‘false’ v-if是条件渲染,当false的时候不会渲染

绑定 class 的数组用法

  • 对象方法 v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
  • 数组方法v-bind:class="[class1, class2]"
  • 行内 v-bind:style="{color: color, fontSize: fontSize+'px' }"

计算属性和 watch 的区别

计算属性是自动监听依赖值的变化,从而动态返回内容,监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些事情。
所以区别来源于用法,只是需要动态值,那就用计算属性;需要知道值的改变后执行业务逻辑,才用 watch,用反或混用虽然可行,但都是不正确的用法。
说出一下区别会加分
computed 是一个对象时,它有哪些选项?
computed 和 methods 有什么区别?
computed 是否能依赖其它组件的数据?
watch 是一个对象时,它有哪些选项?

  1. 有get和set两个选项
  2. methods是一个方法,它可以接受参数,而computed不能,computed是可以缓存的,methods不会。
  3. computed可以依赖其他computed,甚至是其他组件的data
  4. watch 配置
    handler
    deep 是否深度
    immeditate 是否立即执行

总结

当有一些数据需要随着另外一些数据变化时,建议使用computed。
当有一个通用的响应数据变化的时候,要执行一些业务逻辑或异步操作的时候建议使用watcher

事件修饰符

  • 绑定一个原生的click事件, 加native,
  • 其他事件修饰符

stop prevent self

  • 组合键

click.ctrl.exact 只有ctrl被按下的时候才触发

组件中 data 为什么是函数

为什么组件中的 data 必须是一个函数,然后 return 一个对象,而 new Vue 实例里,data 可以直接是一个对象?

因为组件是用来复用的,JS 里对象是引用关系,这样作用域没有隔离,而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

keep-alive

https://cn.vuejs.org/v2/guide…

自定义组件的语法糖 v-model 是怎样实现的

https://www.cnblogs.com/attac…
根据官方文档介绍,v-model本质上就是语法糖,即利用v-model绑定数据后,其实就是既绑定了数据,又添加了一个input事件监听,如下:

怎样理解单向数据流

这个概念出现在组件通信。父组件是通过 prop 把数据传递到子组件的,但是这个 prop 只能由父组件修改,子组件不能修改,否则会报错。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。
一般来说,对于子组件想要更改父组件状态的场景,可以有两种方案:
在子组件的 data 中拷贝一份 prop,data 是可以修改的,但 prop 不能:

  1. export default {
  2. props: {
  3. value: String
  4. },
  5. data () {
  6. return {
  7. currentValue: this.value
  8. }
  9. }
  10. }

如果是对 prop 值的转换,可以使用计算属性:

  1. export default {
  2. props: ['size'],
  3. computed: {
  4. normalizedSize: function () {
  5. return this.size.trim().toLowerCase();
  6. }
  7. }
  8. }

生命周期

  • 创建前后 beforeCreate/created

在beforeCreate 阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象有了,el还没有。

  • 载入前后 beforeMount/mounted

在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前未虚拟的DOM节点,data尚未替换。
在mounted阶段,vue实例挂载完成,data成功渲染。

  • 更新前后 beforeUpdate/updated

当data变化时,会触发beforeUpdate和updated方法。这两个不常用,不推荐使用。

  • 销毁前后beforeDestory/destoryed

beforeDestory是在vue实例销毁前触发,一般在这里要通过removeEventListener解除手动绑定的事件。实例销毁后,触发的destroyed。

组件间的通信

  1. 父子 props/event parent/paren**t/children ref provide/inject
  2. 兄弟 bus vuex
  3. 跨级 bus vuex provide.inject

路由的跳转方式

一般有两种

  1. <router-link to='home'> router-link标签会渲染为<a>标签,咋填template中的跳转都是这种;
  2. 另一种是编程是导航 也就是通过js跳转 比如 router.push('/home')

Vue.js 2.x 双向绑定原理

这个问题几乎是面试必问的,回答也是有深有浅。基本上要知道核心的 API 是通过 Object.defineProperty() 来劫持各个属性的setter / getter,在数据变动时发布消息给订阅者,触发相应的监听回调,这也是为什么 Vue.js 2.x 不支持 IE8 的原因(IE 8 不支持此 API,且无法通过 polyfill 实现)。
https://cn.vuejs.org/v2/guide…

什么是 MVVM,与 MVC 有什么区别

http://www.ruanyifeng.com/blo…

nextTick()

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后,立即使用这个回调函数,获取更新后的 DOM。

  1. // 修改数据
  2. vm.msg = 'Hello'
  3. // DOM 还未更新
  4. Vue.nextTick(function () {
  5. // DOM 更新
  6. })

vue的原理

https://segmentfault.com/a/11…

Vue的模式是m-v-vm模式,即(model-view-modelView),通过modelView作为中间层(即vm的实例),进行双向数据的绑定与变化。

  1. 通过建立虚拟dom树document.createDocumentFragment(),方法创建虚拟dom树。
  2. 一旦被监测的数据改变,会通过Object.defineProperty定义的数据拦截,截取到数据的变化。
  3. 截取到的数据变化,从而通过订阅——发布者模式,触发Watcher(观察者),从而改变虚拟dom的中的具体数据。
  4. 最后,通过更新虚拟dom的元素值,从而改变最后渲染dom树的值,完成双向绑定

双向绑定的实现

  1. object.defineProperty 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
  2. 语法:Object.defineProperty(obj, prop, descriptor)
  3. var obj = {};
  4. Object.defineProperty(obj,'hello',{
  5. get:function(){
  6. //我们在这里拦截到了数据
  7. console.log("get方法被调用");
  8. },
  9. set:function(newValue){
  10. //改变数据的值,拦截下来额
  11. console.log("set方法被调用");
  12. }
  13. });
  14. obj.hello//输出为“get方法被调用”,输出了值。
  15. obj.hello = 'new Hello';//输出为set方法被调用,修改了新值

我们可以做到数据的双向绑定:

  1. var obj = {};
  2. Object.defineProperty(obj,'hello',{
  3. get:function(){
  4. //我们在这里拦截到了数据
  5. console.log("get方法被调用");
  6. },
  7. set:function(newValue){
  8. //改变数据的值,拦截下来额
  9. console.log("set方法被调用");
  10. document.getElementById('test').value = newValue;
  11. document.getElementById('test1').innerHTML = newValue;
  12. }
  13. });
  14. //obj.hello;
  15. //obj.hello = '123';
  16. document.getElementById('test').addEventListener('input',function(e){
  17. obj.hello = e.target.value;//触发它的set方法
  18. })

理解Vue中的Render渲染函数

https://www.cnblogs.com/tugen…

VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数。

render函数return一个createElement组件中的子元素存储在组件实列中 $slots.default 中。

return createElement('h1', this.title); createElement返回的是包含的信息会告诉VUE页面上需要渲染什么样的节点及其子节点。我们称这样的节点为虚拟DOM,可以简写为VNode。

createElement 参数

  1. {String | Object | Function}

一个HTML标签字符串,组件选项对象,或者一个返回值类型为String/Object的函数。该参数是 必须的

子节点

子节点,可选,String 或 Array

  1. Vue.component('anchored-heading', {
  2. render: function (createElement) {
  3. return createElement(
  4. 'h' + this.level, // 标签名称
  5. this.$slots.default // 由子节点构成的数组
  6. )
  7. },
  8. props: {
  9. level: {
  10. type: Number,
  11. required: true
  12. }
  13. }
  14. })

slot插槽

https://www.jianshu.com/p/316…

https://vue.docschina.org/v2/…

单个插槽

当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,并替换掉插槽标签本身。

最初在<slot>标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。

命名插槽

solt元素可以用一个特殊的特性name来进一步配置如何分发内容。多个插槽可以有不同的名字。
这样可以将父组件模板中 slot 位置,和子组件 slot 元素产生关联,便于插槽内容对应传递

作用域插槽scoped slots

可以访问组件内部数据的可复用插槽(reusable slot)
在父级中,具有特殊特性 slot-scope<template> 元素必须存在,表示它是作用域插槽的模板。slot-scope 的值将被用作一个临时变量名,此变量接收从子组件传递过来的 prop 对象。

js中split()和join()区别

Split()方法:把一个字符串分割成字符串数组

如上所示:把字符串a按空格分隔,得3个字符串数组。

  • 再如: var a=”hao are you” a.split(“”); 得到[h,a,o,a,r,e,y,o,u];

Join方法: 把数组中的所有元素转换为一个字符串

如上图所示:数组fruits Join过后得到元素的字符串

  • 再如:

Fruits数组Join(“ and ”)后,变成了上图所示。

:split 和Join方法都识别空格位,Split方法是将字符串转成数组形式,Join方法是将数组转化成字符串形式。

1.数组前插后插

push() 在数组末尾添加元素,接收一个或多个参数

unshift() 在数组首位添加元素,接收一个或多个参数

pop() 删除数组末尾元素

shift() 删除数组第一个元素

数组去重

https://segmentfault.com/a/1190000016418021?utm_source=tag-newest

1. Set去重

  1. function unique (arr) {
  2. return Array.from(new Set(arr))
  3. }

兼容性差,代码少,无法去掉“{}”空对象

2. for嵌套for,然后splice去重

双层循环,外层循环元素,内层循环时比较值。值相同时,删去这个值

  1. function unique(arr){
  2. for(var i=0; i<arr.length; i++){
  3. for(var j=i+1; j<arr.length; j++){
  4. if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
  5. arr.splice(j,1);
  6. j--;
  7. }
  8. }
  9. }
  10. return arr;
  11. }

3. indexOf去重

新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。

  1. var array = [];
  2. for (var i = 0; i < arr.length; i++) {
  3. if (array .indexOf(arr[i]) === -1) {
  4. array .push(arr[i])
  5. }
  6. }
  7. return array;

4. sort()

利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对

  1. arr = arr.sort()
  2. var arrry= [arr[0]];
  3. for (var i = 1; i < arr.length; i++) {
  4. if (arr[i] !== arr[i-1]) {
  5. arrry.push(arr[i]);
  6. }
  7. }
  8. return arrry;

5. includes

  1. var array =[];
  2. for(var i = 0; i < arr.length; i++) {
  3. if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
  4. array.push(arr[i]);
  5. }
  6. }
  7. return array

6. hasOwnProperty

  1. function unique(arr) {
  2. var obj = {};
  3. return arr.filter(function(item, index, arr){
  4. return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  5. })
  6. }

7. filter

  1. function unique(arr) {
  2. return arr.filter(function(item, index, arr) {
  3. //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
  4. return arr.indexOf(item, 0) === index;
  5. });
  6. }

8. 递归去重

9. Map数据结构去重

  1. function arrayNonRepeatfy(arr) {
  2. let map = new Map();
  3. let array = new Array(); // 数组用于返回结果
  4. for (let i = 0; i < arr.length; i++) {
  5. if(map .has(arr[i])) { // 如果有该key值
  6. map .set(arr[i], true);
  7. } else {
  8. map .set(arr[i], false); // 如果没有该key值
  9. array .push(arr[i]);
  10. }
  11. }
  12. return array ;

2.浏览器跨域

1、什么是跨域

跨域的产生来源于现代浏览器所通用的同源策略,所谓同源策略,是指只有在地址的:

  1. 协议名 https,http
  2. 域名 http://a.study.cn http://study.cn
  3. 端口名 http://study.cn:8080/json/jsonp/jsonp.html study.cn/json/jsonp/jsonp.html
    均一样的情况下,才允许访问相同的cookie、localStorage或是发送Ajax请求等等。若在不同源的情况下访问,就称为跨域。

例如a.cn下面的js不能调用b.cn中的js,对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了.

同源策略:

请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同.

比如:我在本地上的域名是study.cn,请求另外一个域名一段数据

这个时候在浏览器上会报错:

这个就是同源策略的保护,如果浏览器对javascript没有同源策略的保护,那么一些重要的机密网站将会很危险~

请求地址 形式 结果
http://study.cn/test/a.html 同一域名,不同文件夹 成功
http://study.cn/json/jsonp/jsonp.html 同一域名,统一文件夹 成功
http://a.study.cn/json/jsonp/jsonp.html 不同域名,文件路径相同 失败
http://study.cn:8080/json/jsonp/jsonp.html 同一域名,不同端口 失败
https://study.cn/json/jsonp/jsonp.html 同一域名,不同协议 失败

jsonp:

jsonp 全称是JSON with Padding,是为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。

一个是描述信息的格式,一个是信息传递双方约定的方法。

jsonp的产生:

1.AJAX直接请求普通文件存在跨域无权限访问的问题,不管是静态页面也好.

2.不过我们在调用js文件的时候又不受跨域影响,比如引入jquery框架的,或者是调用相片的时候

3.凡是拥有scr这个属性的标签都可以跨域例如<script><img><iframe>

4.如果想通过纯web端跨域访问数据只有一种可能,那就是把远程服务器上的数据装进js格式的文件里.

5.而json又是一个轻量级的数据格式,还被js原生支持

6.为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback 参数给服务端,

demo1:基于script标签实现跨域
demo2: 基于script标签实现跨域
demo3: 基于jquery跨域
要点就是 :通过修改document.domain来跨子域
demo4: 通过iframe来跨子域

链接地址:https://www.cnblogs.com/liubingyjui/p/10804785.html

3.深拷贝浅拷贝

深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象的。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝

4.判断数据类型

1: typeof

返回数据类型,包含这7种: number、boolean、symbol、string、object、undefined、function。

typeof null 返回类型错误,返回object

引用类型,除了function返回function类型外,其他均返回object。

其中,null 有属于自己的数据类型 Null , 引用类型中的 数组、日期、正则 也都有属于自己的具体类型,而 typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 Object 类型,没有错,但不是我们想要的结果。

2:toString (最完美)

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

  1. Object.prototype.toString.call('') ; // [object String]
  2. Object.prototype.toString.call(1) ; // [object Number]
  3. Object.prototype.toString.call(true) ; // [object Boolean]
  4. Object.prototype.toString.call(Symbol()); //[object Symbol]
  5. Object.prototype.toString.call(undefined) ; // [object Undefined]
  6. Object.prototype.toString.call(null) ; // [object Null]
  7. Object.prototype.toString.call(new Function()) ; // [object Function]
  8. Object.prototype.toString.call(new Date()) ; // [object Date]
  9. Object.prototype.toString.call([]) ; // [object Array]
  10. Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
  11. Object.prototype.toString.call(new Error()) ; // [object Error]
  12. Object.prototype.toString.call(document) ; // [object HTMLDocument]
  13. Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用

3:constructor

constructor是原型prototype的一个属性,当函数被定义时候,js引擎会为函数添加原型prototype,并且这个prototype中constructor属性指向函数引用, 因此重写prototype会丢失原来的constructor。

缺陷:

1:null 和 undefined 无constructor,这种方法判断不了。

2:还有,如果自定义对象,开发者重写prototype之后,原有的constructor会丢失,因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。

4:instanceof

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型

由上图可以看出[]的原型指向Array.prototype,间接指向Object.prototype, 因此 [] instanceof Array 返回true, [] instanceof Object 也返回true。

instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。

5. promise

Promise是异步编程的一种解决方案,比传统的回调函数和事件更合理和强大。

所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事情(通常是一个异步操作)。从语法上说,Promise是一个对象,从他可以获取异步操作的消息。

特点:

  • 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(以失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来。
  • 一旦状态改变,就不会再变,任何时候都是可以得到这个结果的。Promise对象的状态改变只有两种可能:*从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就会凝固,不会再变了。再对Promise对象添加回调函数也会立即得到这个结果。

有了Promise对象,就可以将异步操作以同步操作的流程表达出来。

缺点:

首先无法取消Promise,一旦新建他就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部跑出的错误无法反应到外部。当pending的时候,无法知道进展到了哪一步。

●什么是Promise

●传统的回调式异步操作有什么缺点

(Promise如何解决异步信任问题的)

●Promise中的异步模式有哪些?有什么区别?

●如果向Promise.all()和Promise.race()传递空数组,运行结果会有什么不同?

●如何确保一个变量是可信任的Promise(Promise.resolve方法传入不同值的不同处理有哪些)

●Promise是如何捕获异常的?与传统的try/catch相比有什么优势?

5.1 什么是Promise

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理,让开发者不用再关注于时序和底层的结果。Promise的状态具有不受外界影响和不可逆两个特点。

5.2 传统的回调式异步操作有什么缺点(Promise如何解决异步信任问题的)

传统的回调有五大信任问题:

  1. 调用回调太早
  2. 调用回调过晚(或没有被调用)
  3. 调用回调次数过少或过多
  4. 未能传递所需的环境和参数
  5. 吞掉可能出现的错误和异常

Promise的解决办法:

1.调用回调过早

对于Promise来说,即使是立即完成的Promise也无法被同步观察到,也就是说一个Promise调用then()的时候,即使这个Promise已经决议了,提供给then的回调也总会被异步调用。

2.调用回调过晚(或没有被调用)

对于一个Promise对象注册的每一个观察回调都是相对独立、互不干预的。而Promise对象调用resolve()和reject()时,每个注册的观察回调也都会被自动调度。所以这些观察回调的任意一个都无法影响或延误对其他回调的调用。

此外,关于回调未调用。正常情况下,没有任何东西可以阻止Promise向你通知它的决议,即使你的JavaScript代码报错了,一会通过异常回调来捕获到。如果Promise永远不被决议的话,Promise本身已提供了竞态的抽象机制来作为解决方案。

3.调用回调次数过少或过多

Promise的定义方式使得它只能被决议一次。即使代码中出现多次决议,这个Promise也会接受第一次决议,并会忽略掉其他任何后续调用。所以任何通过then()注册的回调只会被调用一次。

4.未能传递所需的环境和参数

凡是被决议的值都会传递到观察回调中,如果没有显示的决议值也会传递一个undefined给观察回调。需要注意的是,Promise只允许传一个决议值,其他值将会被默默忽略掉。

5.吞掉可能出现的错误和异常

如果在创建Promise时,存在JavaScript代码错误,会直接导致该Promise的拒绝决议,那么你可以通过reject()来捕获异常,代码中的任何异常都不会吞掉。

以上的回答十分的啰嗦,但是如果上面的五点你都能记住的话,你会了解很多关于Promise的细节问题,也会应对一些面试官的追问,如Promise的then()会不会被重复调用 等。

5.2 Promise中的异步模式有哪些?有什么区别?

好吧,这个问题可能会把面试者问懵……可以考虑另一种问法,或者直接进入下一个问题,说一说Promise.all()和Promise.race()的区别。因为ES6中的Promise中只有这两个模式all和race,其他的如first、any、last等都是其他Promise库提供的。

回到问题本身,

Promise.all()和Promise.race()的区别

all会将传入的数组中的所有promise全部决议以后,将决议值以数组的形式传入到观察回调中,任何一个promise决议为拒绝,那么就会调用拒绝回调。

race会将传入的数组中的所有promise中第一个决议的决议值传递给观察回调,即使决议结果是拒绝。

5.3 如果向Promise.all()和Promise.race()传递空数组,运行结果会有什么不同?

all会立即决议,决议结果是fullfilled,值是undefined

race会永远都不决议,程序卡住……

5.4 如何确保一个变量是可信任的Promise(Promise.resolve方法传入不同值的不同处理有哪些)

可以通过Promise.resolve()方法对不确定的值进行Promise化,返回一个Promise对象。

如果是一个立即值,如一个普通变量,那么该Promise会立即决议为成功。

如果是一个Promise值,那么会将该Promise直接返回赋值给这个Promise,不会有额外开销。

如果是一个类Promise值, 比如其中含有名称为then的成员变量,那么会将then展开形成一个新的Promise对象。

5.5 Promise是如何捕获异常的?与传统的try/catch相比有什么优势?

传统的try/catch捕获异常方式是无法捕获异步的异常的。

而对于Promise对象来说,构造Promise实例时的代码如果出错,则会被认为是一个拒绝的决议,并会向观察回调中传递异常信息。所以即使是一个异步的请求,Promise也是可以捕获异常的。此外,Promise还可以通过catch回调来捕获回调中的异常。

5.6 总结

Promise是一个不错异步操作解决方案,他解决了传统的通过回调和事件来解决异步操作的诸多问题,如“竞争”,回调信任度低的问题。ES6中也提供了标准的Promise供大家使用。

5.7 Promise 中的 then

  • promise的then中默认返回一个promise实例
  • 当then中没有return时返回的是undefined
  • 当then中return的对象或者基本类型等非new Promise实例时,对下一个进程then是同时执行的

  • 当then中return的是一个new Promise或者Promise.resolve()等实例时,对下一个进程then时队列顺序执行的

  • 在node项目中,多少情况下都是以函数导出导入方式使用Promise【尤其是路由层和数据层】,此时一定要对函数return才有效

6. vue双向绑定

https://www.cnblogs.com/webcabana/p/11077628.html

6.1 总结

Vue是采用数据劫持结合发布/订阅模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发相应的监听回调。

首先为每个vue属性用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;

然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会;

接着为input会添加监听事件,修改值就等于为该属性赋值,则会触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。

6.2 什么是setter、getter ?

对象有两种属性:

(1)数据属性,就是我们经常使用的属性

(2)访问器属性,也称存取器属性(存取器属性就是一组获取和设置值的函数)

get和set就是关键字 它们后面各自对应一个函数,这个函数就是上面红字部分所讲的,存储器属性。

  get对应的方法称为getter,负责获取值,它不带任何参数。set对应的方法为setter,负责设置值,在它的函数体中,一切的return都是无效的。

6.3 Object.defineProperty()

对象是由多个名/值对组成的无序的集合。对象中每个属性对应任意类型的值

7. 箭头函数及与普通函数的区别

箭头函数:

  1. let fun = () => {
  2. console.log('abc');
  3. }

普通函数:

  1. function fun() {
  2. console.log('abc');
  3. }

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种只包含一个表达式,连{ … }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ … }和return。

箭头函数是匿名函数,不能作为构造函数,不能使用new

  1. let FunConstructor = () => {
  2. console.log('lll');
  3. }

箭头函数不绑定arguments,要用rest参数…解决

  1. function A(a){
  2. console.log(arguments);
  3. }
  4. A(1,2,3,4,5,8); // [1, 2, 3, 4, 5, 8, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  5. let B = (b)=>{
  6. console.log(arguments);
  7. }
  8. B(2,92,32,32); // Uncaught ReferenceError: arguments is not defined
  9. let C = (...c) => {
  10. console.log(c);
  11. }
  12. C(3,82,32,11323); // [3, 82, 32, 11323]

箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值

  1. var obj = {
  2. a: 10,
  3. b: () => {
  4. console.log(this.a); // undefined
  5. console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  6. },
  7. c: function() {
  8. console.log(this.a); // 10
  9. console.log(this); // {a: 10, b: ƒ, c: ƒ}
  10. }
  11. }
  12. obj.b();
  13. obj.c();
  1. var obj = {
  2. a: 10,
  3. b: function(){
  4. console.log(this.a); //10
  5. },
  6. c: function() {
  7. return ()=>{
  8. console.log(this.a); //10
  9. }
  10. }
  11. }
  12. obj.b();
  13. obj.c()();

箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。

  1. let obj2 = {
  2. a: 10,
  3. b: function(n) {
  4. let f = (n) => n + this.a;
  5. return f(n);
  6. },
  7. c: function(n) {
  8. let f = (n) => n + this.a;
  9. let m = {
  10. a: 20
  11. };
  12. return f.call(m,n);
  13. }
  14. };
  15. console.log(obj2.b(1)); // 11
  16. console.log(obj2.c(1)); // 11

箭头函数没有原型属性

  1. var a = ()=>{
  2. return 1;
  3. }
  4. function b(){
  5. return 2;
  6. }
  7. console.log(a.prototype); // undefined
  8. console.log(b.prototype); // {constructor: ƒ}

箭头函数不能当做Generator函数,不能使用yield关键字

总结

  • 箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
  • 普通函数的this指向调用它的那个对象

8. 登录流程的前后端交互

1注册(建立可用账号)—->

2登录

(后端session中存储账号基本信息,

根据配置的时间记录登录的时长,生成一个tocken值,也一起存储到session中,

然后将session的信息都以json返回给前端 ,

之后前端在每次调用后端登录以外的接口时都需要在 request header中存储access_tocken,用于后端拿这个值跟session中存储的值比对验证,

验证一是否是同一个tocken;

验证二解析后和当前时间比较,看是否登录超时,

将账号是否可用这个状态再redis hashmap中存储,

再其他项目中操作账号状态时更新redis hashmap的值,

这样多个项目虽然各自有自己的session,是跟各自的浏览器绑定的,但是redis是共享的,

这里是的jedis客户端,缺点是多线程不安全)

以上的操作方式中,tocken同时干了2件事:

1保存了唯一标识符,保证是同一账号操作,在用户名密码基础上的另一层验证;

2在这个唯一标识tocken中,加上了登录时间值, 每次拿这个时间和当前时间做对比,到配置时间后做登出操作

9. es6新特性

  1. 默认参数
  2. 模版表达式
  3. 多行字符串
  4. 拆包表达式
  5. 改进的对象表达式
  6. 箭头函数 =&>
  7. Promise
  8. 块级作用域的letconst
  9. 模块化

10. 浏览器缓存机制

强制缓存优先于协商缓存进行,若强制缓存 ExpiresCache-Control 生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-SinceEtag / If-None-Match)。

协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回 304,继续使用缓存,主要过程如下:

11. ajax

1、什么是Ajax和JSON,它们的优缺点

  Ajax是全称是asynchronous JavaScript andXML,即异步JavaScript和xml,用于在Web页面中实现异步数据交互,实现页面局部刷新

  优点:可以实现异步通信效果,页面局部刷新,带来更好的用户体验

  JSON是一种轻量级的数据交换格式,看着像对象,本质是字符串

  优点:轻量级、易于人的阅读和编写,便于js解析,支持复合数据类型

2、ajax的交互流程有哪几步?

  1)创建ajax对象

    xhr = new XMLHttpRequest

  2)规定请求地址

    xhr.open(method,url,async)

  3)等待服务器相应

    xhr.onload

  4)向服务器发送请求

    xhr.send()

3、AJAX应用和传统Web应用有什么不同

  在传统的Js中,如果想发送客户端信息到服务器,需要建立一个HTML 表单然后GET或者POST数据到服务器端

  用户需要点击提交按钮来发送数据信息,然后等待服务器响应请求,页面重新加载

  使用AJAX技术,就可以使Javascript通过XMLHttpRequest对象直接与服务器进行交互

4、XMLHttpRequest对象在IE和Firefox中创建方式有没有不同?

  IE中通过new ActiveXObject()得到,Firefox中通过newXMLHttpRequest()得到

  使用jquery封装好的ajax,会避免这些问题

5、ajax如何解决浏览器缓存问题

  1)在ajax发送请求前加上 anyAjaxObj.setRequestHeader(“If-Modified-Since”,”0”)

  2)在ajax发送请求前加上 anyAjaxObj.setRequestHeader(“Cache-Control”,”no-cache”)

  3)在URL后面加上一个随机数: “fresh=” + Math.random();

  4)在URL后面加上时间戳:”nowtime=” + new Date().getTime()

  5)在jq ajax下,使用 $.ajaxSetup({cache:false}) 这样就不会保存缓存记录

6、简述ajax的优缺点

  优点:

  1)无刷新更新数据(在不刷新整个页面的情况下维持与服务器通信)

  2)异步与服务器通信(使用异步的方式与服务器通信,不打断用户的操作)

  3)前端和后端负载均衡(将一些后端的工作交给前端,减少服务器与宽度的负担)

  4)界面和应用相分离(ajax将界面和应用分离也就是数据与呈现相分离)

  缺点:

  1)ajax不支持浏览器back按钮

  2)安全问题 Aajax暴露了与服务器交互的细节

  3)对搜索引擎的支持比较弱

  4)破坏了Back与History后退按钮的正常行为等浏览器机制

7、阐述一下异步加载JS

  1)异步加载的方案: 动态插入 script 标签

  2)通过 ajax 去获取 js 代码,然后通过 eval 执行

  3)script 标签上添加 defer 或者 async 属性

  4)创建并插入 iframe,让它异步执行 js

8、json字符串与对象如何相互转换

  把JSON格式转成对象:JSON.parse()

  把对象转成标准json:JSON.stringify()

  使用eval能够把字符串尽量转成js运行的代码 eval(‘(‘ + jsonstr + ‘)’)

  eval是不安全的(可能会注入不必要的东西),通过new Function(‘’,’return’+json)();可以解决该问题

9、get与post的区别,什么时候使用post?

  get和post在HTTP中都代表着请求数据,其中get请求相对来说更简单、快速,效率高些

  get相对post安全性低

  get有缓存,post没有

  get体积小,post可以无限大

  get的url参数可见,post不可见

  get只接受ASCII字符的参数数据类型,post没有限制

  get请求参数会保留历史记录,post中参数不会保留

  get会被浏览器主动catch,post不会,需要手动设置

  get在浏览器回退时无害,post会再次提交请求

  post一般用于修改服务器上的资源,对所发送的信息没有限制。比如

  1. 无法使用缓存文件(更新服务器上的文件或数据库)
  2. 向服务器发送大量数据(POST 没有数据量限制)
  3. 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

10、介绍一下XMLHttpRequest对象,他有哪些常用方法和属性

  XMLHttpRequest是ajax的核心,通过XMLHttpRequest对象,Web开发人员可以在页面加载以后进行页面的局部更新

  常用的方法:

  open(get/post,url,是否异步)创建http请求

  send()发送请求给服务器

  setRequestHeader()设置头信息(使用post才会用到,get并不需要调用该方法)

  常用的属性:

  onreadystatechange 用于监听ajax的工作状态(readyState变化时会调用此方法)

  readyState 用来存放XMLHttpRequest的状态

  status 服务器返回的状态码

  responseText 服务器返回的文本内容

11、说下readyState属性是干嘛的,都有哪几个状态

  readyState属性用来存放XMLHttpRequest的状态,监听从0-4发生不同的变化

  0:请求未初始化(此时还没有调用open)

  1:服务器连接已建立,已经发送请求开始监听

  2:请求已接收,已经收到服务器返回的内容

  3:请求处理中,解析服务器响应内容

  4:请求已完成,且响应就绪

12、jquery ajax怎么实现,你认为他有什么不足之处

  

;)

  1. $.ajax({
  2. url:发送请求的地址,
  3. data:数据的拼接,//发送到服务器的数据
  4. type:'get',//请求方式,默认get请求
  5. dataType:'json',//服务器返回的数据类型
  6. async:true,//是否异步,默认true
  7. cache:false,//设置为 false 将不会从浏览器缓存中加载请求信息
  8. success:function(){},//请求成功后的回调函数
  9. error: function(){}//请求失败时调用此函数
  10. })

;)

  不足之处:

  (1)针对MVC的编程,不符合现在前端MVVM的浪潮

  (2)基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案

13、说一下同步和异步的区别

  同步会阻塞,异步不会阻塞

  同步:程序运行从上而下,浏览器必须把这个任务执行完毕,才能继续执行下一个任务

  异步:程序运行从上而下,浏览器任务没有执行完,但是可以继续执行下一行代码

14、解释一下 JavaScript的同源策略

  同源策略是客户端脚本的安全度量标准,为了防止某个文档或脚本从多个不同源装载

  同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性

  所谓同源就是同域名、同协议、同端口,只有同源的地址才能相互通过ajax方式请求

15、如何解决跨域问题?

  跨域的概念:协议、域名、端口都相同才同域,否则都是跨域

  解决跨域问题:

  1)使用JSONP(json+padding)把数据内填充起来

  2)CORS方式(跨域资源共享),在后端上配置可跨域

  3)服务器代理,通过服务器的文件能访问第三方资源

16、解释jsonp的原理

  ajax请求受同源策略影响,不允许进行跨域请求,而script标签src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,

  而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。

17、请问jsonp是不是ajax中实现跨域访问的技术

  jsonp不是AJAX中实现跨域访问的技术

  jsonp没有使用XMLHttpRequest对象

  jsonp只是一种跨域的协议

  jsonp只支持Get方式

18、页面编码和被请求的资源编码如果不一致如何处理?

  对于ajax请求传递的参数,如果是get请求,参数传递中文,在有些浏览器会乱码

  不同的浏览器对参数编码的处理方式不同,所以对于get请求的参数需要使用 encodeURIComponent函数对参数进行编码处理

  于post请求不需要进行编码

19、AJAX请求总共有多少种CALLBACK

  总共有八种Callback

  onSuccess、onFailure、onUninitialized、onLoading

  onLoaded、onInteractive、onComplete、onException

20、拿到数据怎么区分是ajax还是jsonp

  ajax: {}

  jsonp:fn({})

  ajax的数据jsonp不能用,jsonp的数据ajax是可以用的

  jsonp本质是通过URL的方式进行请求的,所以它是get方式请求,没有post

12. 同步异步

同步和异步区别:

1.同步是阻塞模式,异步是非阻塞模式。

2.同步是指发送一个请求,需要等待返回,然后才能发送下一个请求。有个等待过程。

3.异步发送一个请求,不需要等待返回,直接就可以发送下一个请求。

13. JS闭包和作用域

14. 单线程和多线程

1. JS为何是单线程的?

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成这门语言的核心特征,将来也不会改变。

注:所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。

2. 计算机的同步与异步(重点)

计算机领域中的同步(Synchronous)和异步(Asynchronous)和我们生活中的同步和异步的概念是恰好相反的,感觉是翻译要背这个锅。生活中的同步,突出的是‘同’,相同的步伐,是咱俩一起行动,比如一起去逛街吃饭饭睡觉觉。异步则是你忙你的,我忙我的,步调不致且互不干扰。难到计算机里的同步和异步不是这样?确实不是。

\”计算机的同步”\就好比:你去外地上学人生地不熟,突然生活费不够了;此时你决定打电话回家,通知家里转生活费过来,可是当你拨出电话时,对方一直处于待接听状态(即:打不通,联系不上),为了拿到生活费,你就不停的oncall、等待,最终可能不能及时要到生活费,导致你今天要做的事都没有完成,而白白花掉了时间。

“计算机的异步”就是:在你打完电话发现没人接听时,猜想:对方可能在忙,暂时无法接听电话,所以你发了一条短信(或者语音留言,亦或是其他的方式)通知对方后便忙其他要紧的事了;这时你就不需要持续不断的拨打电话,还可以做其他事情;待一定时间后,对方看到你的留言便回复响应你,当然对方可能转钱也可能不转钱。但是整个一天下来,你还做了很多事情。或者说你找室友临时借了一笔钱,又开始happy的上学时光了。

总结:计算机中的同步就是排队等待,假如你是第一百零一个备胎,那你只能等前面的一百个爆了之后才能‘处理’你。异步就是,尽管你是第一百零一个,她还是能照顾到你的感受。

15. HTML5几种存储方式

HTML5 提供了两种在客户端存储数据的新方法:

  • localStorage - 没有时间限制的数据存储
  • sessionStorage - 针对一个 session 的数据存储

1.本地存储localstorage

localStorage 方法存储的数据没有时间限制。第二天、第二周或下一年之后,数据依然可用。

存储方式:

以键值对(Key-Value)的方式存储,永久存储,永不失效,除非手动删除。

注意:IE9 localStorage不支持本地文件,需要将项目署到服务器,才可以支持!

检测方法:

  1. if(window.localStorage){`` ``alert('This browser supports localStorage');``}else{`` ``alert('This browser does NOT support localStorage');``}

常用的API:

getItem //取记录

setIten//设置记录

removeItem//移除记录

key//取key所对应的值

clear//清除记录

存储的内容:

数组,图片,json,样式,脚本。。。(只要是能序列化成字符串的内容都可以存储)

2.本地存储sessionstorage

HTML5 的本地存储 API 中的 localStorage 与 sessionStorage 在使用方法上是相同的,区别在于 sessionStorage 在关闭页面后即被清空,而 localStorage 则会一直保存。

3.离线缓存(application cache)

本地缓存应用所需的文件

使用方法:

①配置manifest文件

页面上:

  1. <!DOCTYPE HTML>
  2. <html manifest="demo.appcache">
  3. ...
  4. </html>

Manifest 文件:

manifest 文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容)。

manifest 文件可分为三个部分:

CACHE MANIFEST - 在此标题下列出的文件将在首次下载后进行缓存

NETWORK - 在此标题下列出的文件需要与服务器的连接,且不会被缓存

FALLBACK - 在此标题下列出的文件规定当页面无法访问时的回退页面(比如 404 页面)

完整demo:

  1. CACHE MANIFEST``# 2016-07-24 v1.0.0``/theme.css``/main.js` `NETWORK:``login.jsp` `FALLBACK:``/html/ /offline.html

服务器上:manifest文件需要配置正确的MIME-type,即 “text/cache-manifest”。

如Tomcat:

  1. <``mime-mapping``>`` ``<``extension``>manifest</``extension``>`` ``<``mime-type``>text/cache-manifest</``mime-type``>``</``mime-mapping``>

常用API:

核心是applicationCache对象,有个status属性,表示应用缓存的当前状态:

0(UNCACHED) : 无缓存, 即没有与页面相关的应用缓存

1(IDLE) : 闲置,即应用缓存未得到更新

2 (CHECKING) : 检查中,即正在下载描述文件并检查更新

3 (DOWNLOADING) : 下载中,即应用缓存正在下载描述文件中指定的资源

4 (UPDATEREADY) : 更新完成,所有资源都已下载完毕

5 (IDLE) : 废弃,即应用缓存的描述文件已经不存在了,因此页面无法再访问应用缓存

相关的事件:

表示应用缓存状态的改变:

checking : 在浏览器为应用缓存查找更新时触发

error : 在检查更新或下载资源期间发送错误时触发

noupdate : 在检查描述文件发现文件无变化时触发

downloading : 在开始下载应用缓存资源时触发

progress:在文件下载应用缓存的过程中持续不断地下载地触发

updateready : 在页面新的应用缓存下载完毕触发

cached : 在应用缓存完整可用时触发

Application Cache的三个优势:

① 离线浏览

② 提升页面载入速度

③ 降低服务器压力

注意事项:

  • 浏览器对缓存数据的容量限制可能不太一样(某些浏览器设置的限制是每个站点 5MB)

  • 如果manifest文件,或者内部列举的某一个文件不能正常下载,整个更新过程将视为失败,浏览器继续全部使用老的缓存

  • 引用manifest的html必须与manifest文件同源,在同一个域下

  • 浏览器会自动缓存引用manifest文件的HTML文件,这就导致如果改了HTML内容,也需要更新版本才能做到更新。

  • manifest文件中CACHE则与NETWORK,FALLBACK的位置顺序没有关系,如果是隐式声明需要在最前面

  • FALLBACK中的资源必须和manifest文件同源

  • 更新完版本后,必须刷新一次才会启动新版本(会出现重刷一次页面的情况),需要添加监听版本事件。

  • 站点中的其他页面即使没有设置manifest属性,请求的资源如果在缓存中也从缓存中访问

  • 当manifest文件发生改变时,资源请求本身也会触发更新

离线缓存与传统浏览器缓存区别:

  1. 离线缓存是针对整个应用,浏览器缓存是单个文件

  2. 离线缓存断网了还是可以打开页面,浏览器缓存不行

  3. 离线缓存可以主动通知浏览器更新资源

15.前后端交互

16. 钩子函数

钩子函数:钩子函数是在一个事件触发的时候,在系统级捕获到了他,然后做一些操作。一段用以处理系统消息的程序。“钩子”就是在某个阶段给你一个做某些处理的机会。

钩子函数: 1、是个函数,在系统消息触发时被系统调用 2、不是用户自己触发的

钩子函数的名称是确定的,当系统消息触发,自动会调用。例如react的componentWillUpdate函数,用户只需要编写componentWillUpdate的函数体,当组件状态改变要更新时,系统就会调用componentWillUpdate。

常见的钩子函数:

react的生命周期函数、vue的生命周期函数,vue的自定义指令等

17. vue router

原理

原理核心就是 更新视图但不重新请求页面。

vue-router实现单页面路由跳转,提供了三种方式:hash模式、history模式、abstract模式,根据mode参数来决定采用哪一种方式。

路由模式

vue-router 提供了三种运行模式:
● hash: 使用 URL hash 值来作路由。默认模式。
● history: 依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。
● abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端

Hash模式

hash即浏览器url中#后面的内容,包含#。hash是URL中的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会加载相应位置的内容,不会重新加载页面。
也就是说

  • 即#是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中,不包含#。
  • 每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置。

所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据。

History模式

HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;

由于hash模式会在url中自带#,如果不想要很丑的 hash,我们可以用路由的 history 模式,只需要在配置路由规则时,加入”mode: ‘history’”,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

有时,history模式下也会出问题:

hash模式下:xxx.com/#/id=5 请求地址为 xxx.com,没有问题。
history模式下:xxx.com/id=5 请求地址为 xxx.com/id=5,如果后端没有对应的路由处理,就会返回404错误;

为了应对这种情况,需要后台配置支持:
在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

abstract模式

abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端。
根据平台差异可以看出,在 Weex 环境中只支持使用 abstract 模式。 不过,vue-router 自身会对环境做校验,如果发现没有浏览器的 API,vue-router 会自动强制进入 abstract 模式,所以 在使用 vue-router 时只要不写 mode 配置即可,默认会在浏览器环境中使用 hash 模式,在移动端原生环境中使用 abstract 模式。 (当然,你也可以明确指定在所有情况下都使用 abstract 模式)。

18. CSS盒子居中的常用的几种方法

1. 用css的position属性

position: relative; //相对定位
position: absolute; //绝对定位

2. flex布局

  1. display:flex;
  2. justify-content: center; //左右居中(侧轴)
  3. align-items: center; //上下居中(横轴)

3. table-cell, vertical-align:middle;属性

  1. display: table-cell;
  2. vertical-align: middle;

4.transform属性

让left和top都是50%,这在水平方向上让div的最左与屏幕的最左相距50%,垂直方向上一样,所以再用transform向左(上)平移它自己宽度(高度)的50%,也就达到居中效果了

  1. position: absolute;
  2. left: 50%;
  3. top: 50%;
  4. transform: translate(-50%,-50%);

19. css3种不知道宽高的情况下水平垂直居中的方法

20. cookies机制和session机制的区别

https://www.cnblogs.com/123blog/articles/10297650.html

  • cookies数据保存在客户端,session数据保存在服务器端;
  • cookies可以减轻服务器压力,但是不安全,容易进行cookies欺骗;
  • session较安全,但占用服务器资源

21.GET和POST的区别

从安全性讲,get和post都一样(get请求参数在url地址上,直接暴露,post请求的参数放body部分,按F12也直接暴露了)

GET产生一个TCP数据包;POST产生两个TCP数据包。
即:
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

22. css中单位px和em,rem

1.区别

px:绝对单位,页面按精确像素展示。

em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px),整个页面内1em不是一个固定的值。

rem:相对单位,可理解为”root em”, 相对根节点html的字体大小来计算,CSS3新加属性,chrome/firefox/IE9+支持。

2.特点

PX特点:

  1. IE无法调整那些使用px作为单位的字体大小;

  2. 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位;

  3. Firefox能够调整px和em,rem,但是96%以上的中国网民使用IE浏览器(或内核)。

em特点 :

  1. em的值并不是固定的;

  2. em会继承父级元素的字体大小。

rem特点:

在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。

这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。

目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。

JS对象

本地对象

  • 与宿主无关,独立于宿主环境的ECMAScript实现提供的对象。
  • 简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。
  • 这些引用类型在运行过程中需要通过new来创建所需的实例对象。
  • 包含:ObjectArrayDateRegExpFunctionBooleanNumberString等。

内置对象

  • 与宿主无关,独立于宿主环境的ECMAScript实现提供的对象。
  • 在 ECMAScript 程序开始执行前就存在,本身就是实例化内置对象,开发者无需再去实例化。
  • 内置对象是本地对象的子集。
  • 包含:GlobalMath
  • ECMAScript5中增添了JSON这个存在于全局的内置对象。

宿主对象

  • 由 ECMAScript 实现的宿主环境提供的对象,包含两大类,一个是宿主提供,一个是自定义类对象。
  • 所有非本地对象都属于宿主对象。
  • 对于嵌入到网页中的JS来说,其宿主对象就是浏览器提供的对象,浏览器对象有很多,如WindowDocument等。
  • 所有的DOMBOM对象都属于宿主对象。

JS 基础

1.null与undfined的区别

null表示没有对象,即该处不应该有值
1.作为函数的参数,表示该函数的参数不是对象
2.作为对象原型链的终点
undefined表示缺少值,即此处应该有值,但没有定义
1.定义了形参,没有传实参,显示undefined
2.对象属性名不存在时,显示undefined
3.函数没有写返回值,即没有写return,拿到的是undefined
4.写了return,但没有赋值,拿到的是undefined
null和undefined转换成number数据类型
null 默认转成 0
undefined 默认转成 NaN

2. var、let、const的区别

1.var声明的变量会挂载在window上,而let和const声明的变量不会:

  1. var a = 100;
  2. console.log(a,window.a); // 100 100
  3. let b = 10;
  4. console.log(b,window.b); // 10 undefined
  5. const c = 1;
  6. console.log(c,window.c); // 1 undefined

2.var声明变量存在变量提升,let和const不存在变量提升

  1. console.log(a); // undefined ===> a已声明还没赋值,默认得到undefined值
  2. var a = 100;
  1. console.log(b); // 报错:b is not defined ===> 找不到b这个变量
  2. let b = 10;
  1. console.log(c); // 报错:c is not defined ===> 找不到c这个变量
  2. const c = 10;

3.let和const声明形成块作用域

  1. if(1){
  2. var a = 100;
  3. let b = 10;
  4. }
  5. console.log(a); // 100
  6. console.log(b) // 报错:b is not defined ===> 找不到b这个变量
  1. if(1){
  2. var a = 100;
  3. const c = 1;
  4. }
  5. console.log(a); // 100
  6. console.log(c) // 报错:c is not defined ===> 找不到c这个变量

4.同一作用域下let和const不能声明同名变量,而var可以

  1. var a = 100;
  2. console.log(a); // 100
  3. var a = 10;
  4. console.log(a); // 10
  5. let a = 100;
  6. let a = 10;
  7. // 控制台报错:Identifier 'a' has already been declared ===> 标识符a已经被声明了。

5.暂存死区

  1. var a = 100;
  2. if(1){
  3. a = 10;
  4. //在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域找变量a,
  5. // 而这时,还未到声明时候,所以控制台Error:a is not defined
  6. let a = 1;
  7. }

6.const

  1. /*
  2. *   1、一旦声明必须赋值,不能使用null占位。
  3. *   2、声明后不能再修改
  4. *   3、如果声明的是复合类型数据,可以修改其属性
  5. * */
  6. const a = 100;
  7. const list = [];
  8. list[0] = 10;
  9. console.log(list);  // [10]
  10. const obj = {a:100};
  11. obj.name = 'apple';
  12. obj.a = 10000;
  13. console.log(obj);  // {a:10000,name:'apple'}

3. JS中split()和join()区别

Split()方法:把一个字符串分割成字符串数组

如上所示:把字符串a按空格分隔,得3个字符串数组。

  • 再如: var a=”hao are you” a.split(“”); 得到[h,a,o,a,r,e,y,o,u];

Join方法: 把数组中的所有元素转换为一个字符串

如上图所示:数组fruits Join过后得到元素的字符串

  • 再如:

    Fruits数组Join(“ and ”)后,变成了上图所示。

:split 和Join方法都识别空格位,Split方法是将字符串转成数组形式,Join方法是将数组转化成字符串形式。

h5新特性

  1. 用于绘画 canvas 元素。

  2. 用于媒介回放的du video 和 audio 元素。

  3. 本地离线存储 localStorage 长期存储数据dao,浏览器关闭后数据不丢失;sessionStorage 的数据在浏览器关闭后自动删除。

  4. 语意化更好的内容元素,比如 article、footer、header、nav、section。

  5. 表单控件,calendar、date、time、email、url、search

1.语义化标签

语义化标签 为页面提供了更好的页面结构。

描述 属性
<header></header> 定义文档的头部区域
<footer></footer> 尾部区域
<nav></nav> 导航区域
<section></section> 段落
<article></article> 页面独立的内容区域
<aside></aside> 页面侧边栏内容
<command></command> 命令按钮
<details></details> 标签包含 details 元素的标题
<dialog></dialog> 对话框

2.增强型表单

HTML5 提供了多个新的表单输入类型。

输入类型 描述
color 主要用于选取颜色
date 从一个日期选择器选择一个日期
datetime 选择一个日期(UTC 时间)
datetime-local 选择一个日期和时间 (无时区)
email 包含 e-mail 地址的输入域
month 选择一个月份
number 数值的输入域
range 一定范围内数字值的输入域
search 用于搜索域
tel 定义输入电话号码字段
time 选择一个时间
url URL 地址的输入域
week 选择周和年

同时,还增加了新的表单属性:

1、placehoder 属性,简短的提示在用户输入值前会显示在输入域上。即我们常见的输入框默认提示,在用户输入后消失。

2、required 属性,是一个 boolean 属性。要求填写的输入域不能为空

3、pattern 属性,描述了一个正则表达式用于验证<input> 元素的值。

4、min 和 max 属性,设置元素最小值与最大值。

5、step 属性,为输入域规定合法的数字间隔。

6、height 和 width 属性,用于 image 类型的 <input>标签的图像高度和宽度。

7、autofocus 属性,是一个 boolean 属性。规定在页面加载时,域自动地获得焦点。

8、multiple 属性 ,是一个 boolean 属性。规定<input> 元素中可选择多个值。  

 

3.音频和视频

HTML5 提供了 音频和视频 。

音频:<audio>

  1. <audio controls>
  2. <source src="xxx.ogg" type="audio/ogg">
  3. <source src="xxx.mp3" type="audio/mpeg">
  4. 您的浏览器不支持 audio 元素。
  5. </audio>

视频:<video>

  1. <video width="500" height="300" controls>
  2. <source src="xxx.mp4" type="video/mp4">
  3. <source src="xxx.ogg" type="video/ogg">
  4. 您的浏览器不支持Video标签。
  5. </video>

4.canvas 绘图

标签只是图形容器,必须使用脚本来绘制图形。

5.SVG 绘图

SVG是指可伸缩的矢量图形

SVG 与 Canvas两者间的区别

1.SVG 是一种使用 XML 描述 2D 图形的语言。

2.Canvas 通过 JavaScript 来绘制 2D 图形。

3.SVG 基于 XML,这意味着 SVG DOM 中的每个元素都是可用的。您可以为某个元素附加 JavaScript 事件处理器。

4.在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。

5.Canvas 是逐像素进行渲染的。在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。

6.地理定位(Geolocation)

HTML5 Geolocation(地理定位)用于定位用户的位置。

  1. window.navigator.geolocation {
  2. getCurrentPosition: fn 用于获取当前的位置数据
  3. watchPosition: fn 监视用户位置的改变
  4. clearWatch: fn 清除定位监视
  5. }

获取用户定位信息:

  1. navigator.geolocation.getCurrentPosition(
  2. function(pos){
  3.     console.log('用户定位数据获取成功')
  4.     //console.log(arguments);
  5.     console.log('定位时间:',pos.timestamp)
  6.     console.log('经度:',pos.coords.longitude)
  7.     console.log('纬度:',pos.coords.latitude)
  8.     console.log('海拔:',pos.coords.altitude)
  9.     console.log('速度:',pos.coords.speed)
  10. }, //定位成功的回调
  11. function(err){
  12.     console.log('用户定位数据获取失败')
  13.     //console.log(arguments);
  14. } //定位失败的回调
  15. )

7.拖放API

在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放

8.Web Storage

使用HTML5可以在本地存储用户的浏览数据。

客户端存储数据的两个对象为:

localStorage :没有时间限制的数据存储

sessionStorage : 针对一个 session 的数据存储, 当用户关闭浏览器窗口后,数据会被删除。

不管是 localStorage,还是 sessionStorage,可使用的API都相同,常用的有如下几个(以localStorage为例):

  1、保存数据:localStorage.setItem(key,value);

  2、读取数据:localStorage.getItem(key);

  3、删除单个数据:localStorage.removeItem(key);

  4、删除所有数据:localStorage.clear();

  5、得到某个索引的key:localStorage.key(index);

9.WebSocket

WebSocket 是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。

两者之间就直接可以数据互相传送。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

vue知识点

1.v-show 与 v-if 区别

在Vue的内部指令中,v-show与v-if的区别,总结如下:

在Vue中,我们可以使用v-if和v-show来控制元素或模板的渲染。而v-if和v-show也属于Vue的内部常用的指令(条件渲染)。这里所说的指令就是directive,指特殊的带有前缀v-的命令,指令的值限定为绑定表达式,指令的职责是当表达式的值改变时把某些特殊的行为应用到DOM上。

v-show

除了v-if之外,Vue还提供v-show也可以控制元素的渲染。v-show和v-if功能有点相似,其中v-if依赖于控制DOM节点,而v-show是依赖于控制DOM节点的display属性。当v-show传入的值为true时,对应DOM元素的display的值为block之类的,反之为false时,display的值为none。也就是用户看不到元素的显示,但其DOM元素还是存在的。

v-if和v-show都能控制DOM元素的显示和隐藏,但是在切换v-if模块时,Vue有一个局部编译/卸载过程,因为v-if中的模板可能包括数据绑定或者子组件,v-if是真是的条件渲染,它会确保条件快在切换时合适的销毁与重建条件块内的时间监听器和子组件。

v-if 是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
v-if 有更高的切换开销,v-show有更高的初始渲染开销。如果需要频繁切换,则使用v-show 较好,如果运行条件不太可能改变,使用v-if较好。

这两个都是Vue的内部指令,而且都是用来控制元素的渲染。只不过,v-if判断是否加载,可以减轻服务器的压力,在需要时加载;v-show调整DOM元素的CSS的dispaly属性,可以使客户端操作更加流畅。虽然这两都都能很好的控制元素的渲染,但实际使用的时候,更应该根据自己的场景来判断使用哪一个指令。

  1. v-show和v-if的区别:
    v-show是css切换,v-if是完整的销毁和重新创建。
  2. 使用
    频繁切换时用v-show,运行时较少改变时用v-if
  3. v-if=false v-if是条件渲染,当false的时候不会渲染

2.绑定 class 的数组用法

  • 对象方法 v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
  • 数组方法v-bind:class="[class1, class2]"
  • 行内 v-bind:style="{color: color, fontSize: fontSize+'px' }"

3.计算属性和 watch 的区别

计算属性是自动监听依赖值的变化,从而动态返回内容,监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些事情。
所以区别来源于用法,只是需要动态值,那就用计算属性;需要知道值的改变后执行业务逻辑,才用 watch,用反或混用虽然可行,但都是不正确的用法。
说出一下区别会加分
computed 是一个对象时,它有哪些选项?
computed 和 methods 有什么区别?
computed 是否能依赖其它组件的数据?
watch 是一个对象时,它有哪些选项?

  1. 有get和set两个选项
  2. methods是一个方法,它可以接受参数,而computed不能,computed是可以缓存的,methods不会。
  3. computed可以依赖其他computed,甚至是其他组件的data
  4. watch 配置
    handler
    deep 是否深度
    immeditate 是否立即执行

总结

当有一些数据需要随着另外一些数据变化时,建议使用computed。
当有一个通用的响应数据变化的时候,要执行一些业务逻辑或异步操作的时候建议使用watcher

4.事件修饰符

  • 绑定一个原生的click事件, 加native,
  • 其他事件修饰符

stop prevent self

  • 组合键

click.ctrl.exact 只有ctrl被按下的时候才触发

5.组件中 data 为什么是函数

为什么组件中的 data 必须是一个函数,然后 return 一个对象,而 new Vue 实例里,data 可以直接是一个对象?

因为组件是用来复用的,JS 里对象是引用关系,这样作用域没有隔离,而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

keep-alive

https://cn.vuejs.org/v2/guide…

自定义组件的语法糖 v-model 是怎样实现的

https://www.cnblogs.com/attac…
根据官方文档介绍,v-model本质上就是语法糖,即利用v-model绑定数据后,其实就是既绑定了数据,又添加了一个input事件监听,如下:

怎样理解单向数据流

这个概念出现在组件通信。父组件是通过 prop 把数据传递到子组件的,但是这个 prop 只能由父组件修改,子组件不能修改,否则会报错。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。
一般来说,对于子组件想要更改父组件状态的场景,可以有两种方案:
在子组件的 data 中拷贝一份 prop,data 是可以修改的,但 prop 不能:

  1. export default {
  2. props: {
  3. value: String
  4. },
  5. data () {
  6. return {
  7. currentValue: this.value
  8. }
  9. }
  10. }

如果是对 prop 值的转换,可以使用计算属性:

  1. export default {
  2. props: ['size'],
  3. computed: {
  4. normalizedSize: function () {
  5. return this.size.trim().toLowerCase();
  6. }
  7. }
  8. }

生命周期

  • 创建前后 beforeCreate/created

在beforeCreate 阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象有了,el还没有。

  • 载入前后 beforeMount/mounted

在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前未虚拟的DOM节点,data尚未替换。
在mounted阶段,vue实例挂载完成,data成功渲染。

  • 更新前后 beforeUpdate/updated

当data变化时,会触发beforeUpdate和updated方法。这两个不常用,不推荐使用。

  • 销毁前后beforeDestory/destoryed

beforeDestory是在vue实例销毁前触发,一般在这里要通过removeEventListener解除手动绑定的事件。实例销毁后,触发的destroyed。

组件间的通信

  1. 父子通信:

父向子传递数据是通过 props,子向父是通过 events($emit);

通过父链 / 子链也可以通信($parent / $children);

ref 也可以访问组件实例;

provide / inject API;$attrs/$listeners

  • 兄弟通信:

Bus;Vuex

  • 跨级通信:

Bus;Vuex;provide / inject API、$attrs/$listeners

路由的跳转方式

一般有两种

  1. <router-link to='home'> router-link标签会渲染为<a>标签,咋填template中的跳转都是这种;
  2. 另一种是编程是导航 也就是通过js跳转 比如 router.push('/home')

Vue.js 2.x 双向绑定原理

这个问题几乎是面试必问的,回答也是有深有浅。基本上要知道核心的 API 是通过 Object.defineProperty() 来劫持各个属性的setter / getter,在数据变动时发布消息给订阅者,触发相应的监听回调,这也是为什么 Vue.js 2.x 不支持 IE8 的原因(IE 8 不支持此 API,且无法通过 polyfill 实现)。
https://cn.vuejs.org/v2/guide…

什么是 MVVM,与 MVC 有什么区别

http://www.ruanyifeng.com/blo…

nextTick()

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后,立即使用这个回调函数,获取更新后的 DOM。

  1. // 修改数据
  2. vm.msg = 'Hello'
  3. // DOM 还未更新
  4. Vue.nextTick(function () {
  5. // DOM 更新
  6. })

vue的原理

https://segmentfault.com/a/11…

Vue的模式是m-v-vm模式,即(model-view-modelView),通过modelView作为中间层(即vm的实例),进行双向数据的绑定与变化。

  1. 通过建立虚拟dom树document.createDocumentFragment(),方法创建虚拟dom树。
  2. 一旦被监测的数据改变,会通过Object.defineProperty定义的数据拦截,截取到数据的变化。
  3. 截取到的数据变化,从而通过订阅——发布者模式,触发Watcher(观察者),从而改变虚拟dom的中的具体数据。
  4. 最后,通过更新虚拟dom的元素值,从而改变最后渲染dom树的值,完成双向绑定

双向绑定的实现

  1. object.defineProperty 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
  2. 语法:Object.defineProperty(obj, prop, descriptor)
  3. var obj = {};
  4. Object.defineProperty(obj,'hello',{
  5. get:function(){
  6. //我们在这里拦截到了数据
  7. console.log("get方法被调用");
  8. },
  9. set:function(newValue){
  10. //改变数据的值,拦截下来额
  11. console.log("set方法被调用");
  12. }
  13. });
  14. obj.hello//输出为“get方法被调用”,输出了值。
  15. obj.hello = 'new Hello';//输出为set方法被调用,修改了新值

我们可以做到数据的双向绑定:

  1. var obj = {};
  2. Object.defineProperty(obj,'hello',{
  3. get:function(){
  4. //我们在这里拦截到了数据
  5. console.log("get方法被调用");
  6. },
  7. set:function(newValue){
  8. //改变数据的值,拦截下来额
  9. console.log("set方法被调用");
  10. document.getElementById('test').value = newValue;
  11. document.getElementById('test1').innerHTML = newValue;
  12. }
  13. });
  14. //obj.hello;
  15. //obj.hello = '123';
  16. document.getElementById('test').addEventListener('input',function(e){
  17. obj.hello = e.target.value;//触发它的set方法
  18. })

理解Vue中的Render渲染函数

https://www.cnblogs.com/tugen…

VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数。

render函数return一个createElement组件中的子元素存储在组件实列中 $slots.default 中。

return createElement('h1', this.title); createElement返回的是包含的信息会告诉VUE页面上需要渲染什么样的节点及其子节点。我们称这样的节点为虚拟DOM,可以简写为VNode。

createElement 参数

  1. {String | Object | Function}

一个HTML标签字符串,组件选项对象,或者一个返回值类型为String/Object的函数。该参数是 必须的

子节点

子节点,可选,String 或 Array

  1. Vue.component('anchored-heading', {
  2. render: function (createElement) {
  3. return createElement(
  4. 'h' + this.level, // 标签名称
  5. this.$slots.default // 由子节点构成的数组
  6. )
  7. },
  8. props: {
  9. level: {
  10. type: Number,
  11. required: true
  12. }
  13. }
  14. })

slot插槽

https://www.jianshu.com/p/316…

https://vue.docschina.org/v2/…

单个插槽

当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,并替换掉插槽标签本身。

最初在<slot>标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。

命名插槽

solt元素可以用一个特殊的特性name来进一步配置如何分发内容。多个插槽可以有不同的名字。
这样可以将父组件模板中 slot 位置,和子组件 slot 元素产生关联,便于插槽内容对应传递

作用域插槽scoped slots

可以访问组件内部数据的可复用插槽(reusable slot)
在父级中,具有特殊特性 slot-scope<template> 元素必须存在,表示它是作用域插槽的模板。slot-scope 的值将被用作一个临时变量名,此变量接收从子组件传递过来的 prop 对象。

Vue3.0新特性

概览

  1. 响应式原理由defineProperty变为Proxy
  2. 编译优化
  3. composition API
  4. 提升了对TypeScript的支持
  5. createApp()方法创建实例
  6. 避免了this,生命周期的复杂性
  7. vue2.0大量的api挂在Vue实例对象上,难以实现treeshaking
  8. 重写了虚拟DOM,对模板编译进行了优化
  9. vite打包工具

1. new Vue()与createApp()

  • Vue3 之前使用 new Vue() 来构建应用根组件,现在改为 createApp() ,调用 $mount 方法进行挂载
  1. let app = new Vue() =>
  2. let app = createApp(App);
  3. app.mount("#app")
  • Vue3 之前使用 Vue.use() 注册api,现在是挂到具体实例对象上
  1. Vue.use => 实例对象.use()

2. composition API

2.1 与 options api的区别

options

  • 包含了data,methods,watch,props等描述组件的选项
  • Vue 是通过 Options (选项) 的方式对外提供接口,通过已经指定好的不同的 Option 来完成指定的功能
  • 调用时机:创建组件实例,然后初始化 props ,紧接着就调用setup 函数。从生命周期钩子的视角来看,它会在 beforeCreate 钩子之前被调用
  • 原来视图中可使用的数据来源很多:

    • data,props,computed,methods,inject
    • 这种做法数据来源太多,容易造成混乱
  • 使用mixin复用代码会导致命名冲突

composition

  • 基于函数的api

2.2 setup 内部数据

  • 参数

  • props:用于组件间通讯

  • commit:
    commit.emit用于向父级提交方法

2.3 响应式数据

  • ref
  • reactive
  • computed
  • watchEffect
  • watch

2.4 响应式api工具

2.4.1 toRefs 与 toRef

vue3提供了一个api toRef

  • toRef 可以用来为一个 reactive 对象的属性创建一个 ref。这个 ref 可以被传递并且能够保持响应性
  • 第一个参数是哪个对象,第二个参数是对象的哪个属性
  1. setup(){
  2. let obj = {name : 'alice', age : 12};
  3. let newObj= toRef(obj, 'name');
  4. function change(){
  5. newObj.value = 'Tom';
  6. console.log(obj,newObj)
  7. }
  8. return {newObj,change}

toRefs

  • 当想要从一个组合逻辑函数中返回响应式对象时,用 toRefs 是很有效的,该 API 让消费组件可以 解构 / 扩展 返回的对象,并不会丢失响应性
  • 可以使用该对象将props属性解构出来并把每一项变为响应式的
  • 以此来控制percentage属性响应式的传递给底层组件
  1. setup(props, ctx) {
  2. const {percentage} = toRefs(props);
  3. }

我们知道ref可以用于创建一个响应式数据,而toRef也可以创建一个响应式数据,那他们之间有什么区别呢?

事实上,如果利用ref函数将某个对象中的属性变成响应式数据,修改响应式数据是不会影响到原始数据

toRef与ref的区别

  • ref本质是拷贝,修改响应式数据不会影响原始数据;toRef的本质是引用关系,修改响应式数据会影响原始数据
  • ref数据发生改变,界面会自动更新;toRef当数据发生改变是,界面不会自动更新
  • toRef传参与ref不同;toRef接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性
  1. setup() {
  2. const user = reactive({ age: 1 });
  3. const age = toRef(user, "age");
  4. age.value++;
  5. console.log(user.age); // 2
  6. user.age++;
  7. console.log(age.value); // 3
  8. }

2.5 watch与watchEffect的区别

2.5.1 watch

监听ref

  1. let a = ref(0)
  2. let b = ref(1)
  3. watch(() => {
  4. console.log('watch a+b', a.value + b.value)
  5. })
  6. watch(a, () => {
  7. console.log('watch a', a.value + b.value)
  8. })
  9. setTimeout(
  10. () => {
  11. a.value++
  12. }, 1000
  13. )
  14. setTimeout(
  15. () => {
  16. b.value++
  17. }, 2000
  18. )

监听reactive

  1. let a = reactive({count: 1})
  2. let b = reactive({count: 2})
  3. watch(() => {
  4. console.log('a+b', a.count + b.count)
  5. })
  6. watch(() => a.count, () => {
  7. console.log('a.count', a.count + b.count)
  8. })
  9. watch(() => a, () => {
  10. console.log('a', a.count + b.count)
  11. })
  12. setTimeout(() => {
  13. a.count++
  14. }, 1000)
  15. setTimeout(() => {
  16. b.count++
  17. }, 2000)

回调函数停止监听

  1. let a = ref(0)
  2. let stop = watch(() => {
  3. console.log('a', a.value)
  4. })
  5. setTimeout(() => {
  6. a.value++
  7. console.log('change')
  8. stop()
  9. console.log('stop')
  10. }, 1000)

clean函数:watch重复调用时触发,可用于节流

  1. let stop = watch(a, (newVal, oldVal, clean) => {
  2. console.log('a', a.value)
  3. clean(
  4. () => {
  5. console.log('clean')
  6. }
  7. )
  8. }, {
  9. lazy: true // 不在初始化时执行watch中的函数例如clean
  10. })
  11. setTimeout(
  12. () => {
  13. a.value++
  14. console.log('a change')
  15. }, 1000
  16. )
  17. setTimeout(
  18. () => {
  19. a.value++
  20. console.log('a change2')
  21. }, 2000

2.5.2 watchEffect

  1. // watchEffect
  2. setup () {
  3. const age = ref(0)
  4. watchEffect(() => console.log(age))
  5. setTimeout(() => {
  6. age.value = 1
  7. }, 1000)
  8. return {
  9. age
  10. }
  11. }

总结

  • watchEffect 不需要指定监听的属性,他会自动收集依赖, 只要我们回调中引用到了响应式的属性, 就达到了监听效果,而 watch 只能监听指定的属性而做出变更(v3开始可以同时指定多个)。
  • **watch**可以获取到新值与旧值(更新前的值),而 watchEffect 是拿不到的。
  • watchEffect如果存在的话,在组件初始化的时候就会执行一次用以收集依赖(与computed同理),而后收集到的依赖发生变化,这个回调才会再次执行,而 watch 不需要,因为他一开始就指定了依赖。
  • watchEffect会返回一个用于停止这个监听的函数

2.6 生命周期api

  • onMounted
  • onUnmounted
  • nextTick

3. 组件

3.1 Fragment

  • vue3不会再像vue2一样需要手动添加一个根结点
  • vue3会自动使用fragment包裹组件结点

3.2 teleport

teleport组件能帮我们将组件渲染在页面指定的仍和地方

  • 比如modal组件,vue2中可以通过指令来实现modal组件挂载到body上去,但是比较麻烦
  • vue3可以直接使用teleport组件实现这一需求
  1. <teleport to="body" class="modal" v-if="">
  2. ...
  3. </teleport>
  4. <teleport to="#modals" class="modal" v-if="">
  5. ...
  6. </teleport>

4. v-model

我们可能需要对一个 prop 进行“双向绑定”

  • vue2中绑定响应式的props属性写法
  1. <text-document
  2. v-bind:title="title"
  3. v-on:update:title="title = $event"
  4. ></text-document>
  5. this.$emit('update:title', newTitle)

为了方便,可以使用.sync修饰符来简化父组件的绑定

  1. <text-document v-bind:title.sync="doc.title"></text-document>
  • vue3中则将.sync封装到了v-model之中
  1. <text-document v-model:title="doc.title" />

5. CustomRenderAPI

接口

  • createElement
  • insert
  • patchProp

6. 源码层面

编译优化

6.1 运行时编译

  • Slot 默认编译为函数:父子之间不存在强耦合,提升性能
  • Monomorphic vnode factory:参数一致化,给它children信息,
  • Compiler-generated flags for vnode/children types

6.2 重写了虚拟DOM

传统vdom的性能瓶颈:

  • 虽然 Vue 能够保证触发更新的组件最小化,但在单个组件内部依然需要遍历该组件的整个 vdom 树。
  • 传统 vdom 的性能跟模版大小正相关,跟动态节点的数量无关。在一些组件整个模版内只有少量动态节点的情况下,这些遍历都是性能的浪费。
  • JSX 和手写的 render function 是完全动态的,过度的灵活性导致运行时可以用于优化的信息不足

6.3 diff算法

  • vue3标记和提升了所有静态根节点,diff时只比较动态节点

6.4 静态提升

patch flag,patch算法的时候跳过静态节点,缓存事件处理函数

6.4.1 静态树提升(Static Tree Hoisting)
  • 使用静态树提升,这意味着 Vue 3 的编译器将能够检测到什么是静态的,然后将其提升,从而降低了渲 染成本。
  • 跳过修补整棵树,从而降低渲染成本,即使多次出现也能正常工作
6.4.2 静态属性提升

使用静态属性提升,Vue3打补丁时将跳过这些属性不会改变的节点

7. 优化slots的生成

8. vue3中可以单独重新渲染父级和子级

  • 确保实例正确的跟踪依赖关系
  • 避免不必要的父子组件重新渲染

9. 改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及警告

  • defineComponent

10. 基于 Proxy 的数据响应式

JS作用域

作用域是可访问变量的集合。

JavaScript 作用域

在 JavaScript 中, 对象和函数同样也是变量。

在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。

JavaScript 函数作用域: 作用域在函数内修改。

JavaScript 局部作用域

变量在函数内声明,变量为局部作用域。

局部变量:只能在函数内部访问。

因为局部变量只作用于函数内,所以不同的函数可以使用相同名称的变量。

局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁。

JavaScript 全局变量

变量在函数外定义,即为全局变量。

全局变量有 全局作用域: 网页中所有脚本和函数均可使用。

如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量。

以下实例中 carName 在函数内,但是为全局变量。

JavaScript 变量生命周期

JavaScript 变量生命周期在它声明时初始化。

局部变量在函数执行完毕后销毁。

全局变量在页面关闭后销毁。

函数参数

函数参数只在函数内起作用,是局部变量。

HTML 中的全局变量

在 HTML 中, 全局变量是window 对象 : 所有数据变量都属于 window 对象。

上传的附件

发送私信

4
文章数
0
评论数
最近文章
eject