面试准备---202年6月15日

2020-06-16  本文已影响0人  学的会的前端

HTML部分

你是如何理解 HTML 语义化的?

HTML语义化就是使用合适的标签书写合适的内容,避免使用过多无意义的标签,例如div。举例来说:段落使用p标签,标题使用h1-h6,连接使用a标签,动画使用canvas等。HTML语义化可以便于搜索引擎更好的解析代码,也利于浏览器爬虫获得更多的信息,并且对团队的合作开发和维护也更有利。

meta viewport 是做什么用的,怎么写?

针对移动端优化,在手机上,不想让页面缩放,不采用媒体查询,应使用meta vieport。Viewport 就是浏览器窗口,它不是一个 HTML 结构,因而不能通过 CSS 去改变它的形态。

<meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1 minimum-scale=1 user-scalable=no”>

你用过哪些 HTML 5 标签?

<canvas id = "canvas" width="150" height="150"></canvas> 
//width和height已经限制了canvas 的长度和宽度,并且width和height是HTML标签属性,
//不是使用CSS设置的。使用css对width和height进行设置,只是拉伸了canvas的长宽,
//并不是真的修改了.
const canvas = document.getElementById('canvas')
//获取2d渲染上下文
const ctx = canvas.getContext('2d')
//填充
ctx.fillStyle = "red"
//画矩形
ctx.fillRect(10,10,3000,3000)
//上面限制了canvas的跨宽高,所以3000,3000最大只能为150-10,150-10
<video controls>
  <source src="myVideo.mp4" type="video/mp4">
  <source src="myVideo.webm" type="video/webm">
  <p>Your browser doesn't support HTML5 video. Here is
    a <a href="myVideo.mp4">link to the video</a> instead.</p>
</video>
//使用source元素
<audio controls="controls">
  Your browser does not support the <code>audio</code> element.
  <source src="foo.wav" type="audio/wav">
</audio>
//不适用source元素
<audio src="http://developer.mozilla.org/@api/deki/files/2926/=AudioTest_(1).ogg" autoplay>
  Your browser does not support the <code>audio</code> element.
</audio>

H5 是什么?

H5表示微信等移动端的解决方案。这个解决方案包括HTML5的新特性,例如audio,canvas,拖曳特性,本地存储等。也包括盒模型,绝对定位等一系列的前端知识。H5特指基于HTML5技术的交互网页应用,以商业用途为主。

H5动画,微信H5

HTML5 跨平台性,更有效的数据推送,本地存储,无插件播放视频audio,图像动画canvas

HTML5新特性包括哪些?

  1. 语义化更好的标签
1. 结构标签:article,header,nav,footer,aside,section
2. 其他元素:video,audio,canvas,menu,meter,time
  1. 废除了一些部分浏览器支持的元素,以及对页面产生负面影响的元素。html5支持iframe
  2. 新增了一些API,
获取canvas的上下文对象,利用该上下文的绘图功能进行绘制
let ctx = canvas.getContext('2d')
<svg height = "100" width = "100">
    <circle cx = "50" cy = "50" r = "50"></circle>
</svg>

Label标签的 作用是什么?

Label表情通常写在form表单内,通常关联一个控件

<label for = "username" accesskey = "N">
  <input id = "username" type = "text">
</lbael>

CSS部分

两种盒模型分别说一下

box-sizing: content-box ;标准盒模型 (默认)
bo-sizing:border-box; IE盒模型

如何垂直居中?

flex布局怎么用,常用属性有哪些?

BFC 是什么?

  1. 清楚浮动,父元素设置overflow:hidden / float:left
  2. 实现左右布局,左边元素float: left,width: 100px; 右边元素overflow: auto
  3. FC会阻止垂直(父子)的外边距折叠:只要把父元素设置为BFC就可以了。
  1. 浮动元素(元素的 float 不是 none)
  2. 绝对定位元素(元素的 position 为 absolute 或 fixed)
  3. 行内块元素
  4. overflow 值不为 visible 的块元素
  5. 弹性元素(display为 flex 或 inline-flex元素的直接子元素)

CSS 选择器优先级

  1. 越具体优先级越高
  2. 后面的会覆盖前面的
  3. !important优先级最高,但不建议经常使用

清除浮动说一下

.clearfix:after {
  display: block;
  content: '';
  clear: both;
}
//IE兼容
 .clearfix{
     zoom: 1; /* IE 兼容*/
 }

响应式布局

  1. 响应式布局指的是同一页面在不同的屏幕有不同的布局。
  2. 响应式布局与自适应布局的区别:
    响应式布局只有一个页面,根据视口分辨率的不同,做不通的代码代理,之后显示相应的内容和布局,自适应布局,有很多页面,根据视口分辨率的不同,判断是Pc端还是手机端等,之后返回一套完成的页面用于展示。
  3. 响应式布局的实现方案
因为后面的样式会覆盖前面的样式,
移动优先应使用min-width
PC优先,应使用max-width
max-width:100%; height: auto
不用width,是因为width无法进行图片的自适应

使用srcset

<img srcset="photo_w350.jpg 1x, photo_w640.jpg 2x" src="photo_w350.jpg" alt="">
设置viewport
媒体查询
字体的适配(字体单位)
百分比布局
图片的适配(图片的响应式)
结合flex,grid,BFC,栅格系统等已经成型的方案

:before和:after的区别是什么?

你用过哪些伪类?

  1. a标签相关伪类
a:link {color:#FF0000;} /* 未访问的链接 */
a:visited {color:#00FF00;} /* 已访问的链接 */
a:hover {color:#FF00FF;} /* 鼠标划过链接 */
a:active {color:#0000FF;} /* 已选中的链接 */
  1. :focus
  2. :first-child
  3. :first-of-type
  4. :last-child

animation对应的属性

animation:none duration timig-function delay iteration-count direction

px em rem vh vw的区别?

原生 JS

ES 6 语法知道哪些,分别怎么用?

var let const 区别

  1. var 存在变量提升,可以声明写在下面,使用写在上面。此时JS 只有函数作用域和全局作用域
  2. let 使JS 存在块级作用域,必须先声明在使用,(存在暂时性死区,即在声明之前使用是不可以的。)let 更适合和for结合使用,每次都会生成一个新的块级作用域。
  3. let 不允许重复声明,但允许重复赋值,let a = 1,a=2可以,let a = 1,let a = 2不可以.
  4. const 只有一次声明和赋值的机会,不允许重复声明及赋值.

箭头函数

  1. 箭头函数只能做赋值,不能做声明
let a = (x,y) => {return x + y}
  1. 函数只有在调用的时候,才能确定this的值,箭头函数可以保证,函数内的this与函数外的this值相等.
  2. 箭头函数没有this的概念,箭头函数的第一个参数就是一个参数,没有隐藏的this
let a = () => {console.log(this)}
a.call({name:"ll"})
a() 
//以上结果相等  this为window
  1. 箭头函数的应用,
let arr = [1,2,3]
arr.map(number => number * number) //[1,4,9]
  1. Vue中不要直接使用箭头函数,Vue依赖this,可以当this捕获之后,在使用箭头函数.
  2. 箭头函数返回一个对象,必须用(),因为{}被理解为块级作用域
let x = () => ({name: 'qq'})
  1. 箭头函数还可以和变量解构结合使用
let x = ({x,y}) => {return x + y}
  1. 箭头函数的注意事项
  1. 定义对象的方法,且该方法内包含对象
let obj = {
  name: 'lili',
  fn: () => {this.name} //this指向window
}
此种错误,箭头函数的this是指创建函数时所在的作用域,但是对象不能创建作用(只有函数才可),所以此时This为window
//改建
let obj = {
  name: 'lili',
  fn: function(){
    let f = () => {this.name}
  }
}
button.onClick = function(){
  this.classList.add('active')
}
//此时就不能用箭头函数

展开操作符(...)

MDN: 展开语法(Spread syntax), 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。(译者注: 字面量一般指 [1, 2, 3] 或者 {name: "mdn"} 这种简洁的构造方式)
展开运算符不仅适用于数组,还适用于对象,只能用于可迭代对象

  1. 伪数组变真数组的方法
//ES6
let args = [...arguments]   OR
let args = Array.from(arguments)
//ES5
let args = Array.prototype.slice.call(arguments)
  1. 获取array1的剩余部分
let array1 = [1,2,3,4,5,6,7]
let [a,b,...array2] = array1
 // array2 = [3,4,5,6,7]
//语法糖
[,,...array2] = array1
  1. 复制一个数组
let array1 = [1,2,3]
let [...array2] = array1 //let 很重要
// array2 = [1,2,3]
  1. 在array1前面加1,在后面加7
let array1 = [3,4,5]
let array2 = [1,...array1,7]
// array2 = [1,3,4,5,7]
  1. 函数调用
function sum(x,y,z){
  return x + y + z
}
const numbers = [1,2,3]
sum(...numbers) //6   等价于apply  sum.apply(null,numbers)
  1. 使用 new 关键字来调用构造函数时,
var dateFields = [1970, 0, 1]; // 1970年1月1日
var d = new Date(...dateFields);
  1. 连接多个数组,代替concat()
let arr1 = [1,2,3]
let arr2 = [4,5,6]
let arr3 = arr1.concat(arr2)
console.log(arr3)  //[1,2,3,4,5,6]

//展开运算符
let arr3 = [...arr1,...arr2]
console.log(arr3)  //[1,2,3,4,5,6]
  1. 字面量对象展开运算符,浅拷贝
let obj1 = {foo: 'zzz',num: 23}
let obj2 = {foo: 'xxx',age: 45}
let obj3 =  {...obj1}
console.log(obj3) //{foo: 'zzz',num: 23}

默认参数

默认参数允许在没有值或undefined传入的时候,使用默认形参

  1. 设置了默认参数,即使函数调用时显示把参数设置为undefined,值还是默认值,但是设置null,参数值就是null
function sum(a = 1){
  console.log(a)
}
sum(undefined)   //1
sum(null) //null
sum('') //''
  1. 在函数被调用时,默认参数值就会被解析,每次都会创建一个新的参数对象。
function array (value, arr = []){
  arr.push(value)
  console.log(arr)
}
array(1)   // [1]
array(2)  // [2]   不是[1,2]
这是两个完全不同的数组。

解构赋值

解构赋值是JavaScript的一种表达式,通过解构赋值可以把属性/值从对象 或数组中取出来,赋值给其他变量.

  1. 赋值,剩余数组必须是最后一个元素
[a,b,...rest] = [1,2,3,4,5,6,7]
console.log(a)  //1
console.log(b)  //2
console.log(rest)  //[3,4,5,6,7]
  1. 对象
//取对象的属性值
let a,b;
({a,b} = {a: 'li',b:20})
console.log(a)  //li 
console.log(b)  //20
//  其他情况,一个变量可以独立于声明进行结构赋值
let a,b;
({a,b} = {name: 'li',b:20})
console.log(a)   //undefined 
console.log(b)   //20
// 其他情况,浅拷贝,代替object.assign()
let rest;
({...rest} = {name: 'li',b:20})
console.log(rest) // {name: 'li',b:20}
等价于 let rest = Object.assign({},{name: 'li',b:20})
  1. 为了防止从数组中取出undefined对象,可以为变量设置默认值
let [a=2,b=3] = [1]
console.log(a) //1
console.log(b) //3
  1. 交换两个变量的值
let a = 1,b = 2;
//左边为需要赋值的变量,
[a,b]= [b,a]
console.log(a)  //2
console.log(b)  //1
  1. 可以给新的变量名赋值
let o = {q: 42,p:23 }
let {q: foo,p: bar} = o
console.log(foo)  //42
console.log(bar)  //23
  1. 解构对象时会查找原型链(如果属性不在对象自身,将从原型链中查找)

impoer export

export 用于从模块中导出函数,对象,原始值等,以便其他程序通过import导入相应的模块进行使用.

  1. 有名字的导入导出
eaport {name.age.city} 
import {name,age,city} from "1/js"
使用时,使用什么变量import什么变量即可
  1. 默认导出
export default Name
import Name from "1.js"
  1. 导出模块变量名相同,需要重新设置变量名
import {name as name1} from "1.js"
//name 重命名为name1
  1. 导入模块的所有
import * as name from '1.js';
  1. 关键字import可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个 promise。
import("1.js").then(() => {},() =>{})
  1. 对于不支持import 和export 的浏览器,建议使用babel.js

JS数据类型,ES6新增的数据类型

null ,number,String,undefined,object,boolean,symbol, 
Symbol
  1. Symbol()不支持new()语法,因为他不具有constructor()函数.
new Symbol() //报错
  1. 每个从Symbol()返回的symbol值都是唯一的
var a = Symbol()
var b = Symbol()
console.log(a === b)  //false
  1. 一个Symbol值可以作为对象属性的标识符,这是该数据类型仅有的目的。。ES6之前,对象的属性标识符都是字符串,现在也可以使Symbol
var a = Symbol()
var obj = {}
obj[0] = '000'   //[0]0 其实是字符串
obj[a] = 'sss'

  1. symbol是一种基本数据结构,不是对象
var a = Symbol()
typeof a //symbol
  1. symbol可以实现有一个真的私有属性
{
  let a = Symbol()
  let obj = {
    name: 'li',
    age: 18,
    [a]:'隐藏属性'
  }
  window.object = obj
}
console.log(object)
console.log(object['Symbol()'])  //undefined

如何实现数组去重?

  1. 利用hash来实现
let array = [1,2,3,4,5,3,4,2,5,1,6,8]
function unip(array){
  let result = []
  let hash = {}
  for(let i = 0; i < array.length; i++){
    hash[array[i]] = true

  }
  console.log(hash)
//遍历对象使用for...in
  for(let key in hash){
    result.push(key)
  }
  console.log(result)
}
unip(array)
  1. 使用ES6 的set方法实现数组去重
Array.from()方法从一个类似数组或可迭代对象创建一个新的浅拷贝的数组实例
Set()方法允许存储任意类型的唯一值,无论是原始值还是对象引用值
let array = [1,2,3,4,5,3,4,2,5,1,6,8]
function unip(array){
  return Array.from(new Set(array))
//语法糖 return [...new Set(array)]
}
unip(array)
  1. 利用filter()过滤和indexOf的索引
 //只将数组中元素第一次出现的返回
 // 之后出现的将被过滤掉
function unip(array){
  return array.filter((item,index) => {
    console.log(item + '----' + index)
    
    return array.indexOf(item) ===index 
  })
}
let array = [1,3,5,2,4,6,4,2,4,3,1]
unip(array)

  1. 利用Map()对象
function unip(array) {
  const newArray = [];
  const tmp = new Map();
  for(let i = 0; i < array.length; i++){
        if(!tmp.get(array[i])){
            tmp.set(array[i], 1);
            newArray.push(array[i]);
        }
    }
    return newArray;
}

什么是 JSONP,什么是 CORS,什么是跨域?

  1. 同源策略
    浏览器出于安全机制的考虑,只允许同源相互访问数据,不允许跨域请求。同源指的是:同协议,同域名,同端口。window.origin / location.origin可以获取到当前的源。
  2. 为什么跨域可以使用CSS,JS,图片等
    同源策略限制的是数据的访问,引用CSS,JS,图片的时候,不知道内容是什么,只是单纯的在引用,使用ajax的时候,需要获取数据,所以背会浏览器限制。
  3. CORS 实现跨域
    CORS:跨域资源共享,主要用过设置响应头,决定浏览器是否允许跨域请求数据。
    如果frank.com想访问11.com里面的数据,就是跨域,正常浏览器出于安全机制,是不允许访问的,通过在11.com的服务器端设置reponse setHeader('Access-Control-Allow-Origin','http://frank.com')即可实现在frank.com访问11.com数据.
    若要允许多个网站访问reponse.setHeaders['refers']
    Access-Control-Allow-Origin:允许的域名
  4. JSONP实现跨域
 if(path === '/index.js'){
      if(request.headers['referer'].indexOf('http://frank.com') === 0 ){
        reponse.statusCode = 200;
        reponse.setHeader('Content-type',"text/javascript",'charset = utf-8')
        const string = fs.readFileSync('/index.js').toString()
        const data = fs.readFileSync('./index.json').toString()
        const string1 = string.replace({data},data)
        reponse.write(string1)
        reponse.send()
    }else {
    response.statusCode = 404
    reponse.send()
    }
}

在frank.com中只要引用index.js即可<script src = "http://11.com/index.js"></script>
拿到数据之后,要移除script,防止页面一直在请求数据,script只有onloa事件

script.onload = function(){
  script.remove()
}
function jsonp(url) {
  return new Promise((resolve, reject) => {
    let random = Math.random();
    window[random] = (data) => {
      resolve(data);
    };
    let script = document.createElement("script");
    script.src = `${url}?callback=${random}`;
    script.onload = () => {
      script.remove();
    };
    script.onerror = () => {
      reject();
    };
    document.body.appendChild(script);
  });
}
// 使用
 jsonp("http://localhost:9991/friends.js").then((data) => {
  console.log(data);
});

对11.com服务器后台的改变

 if (path === "/index.js") {
    if (request.headers["referer"].indexOf("http://frank.com") === 0) {
      response.statusCode = 200;
      //query查询字符串
      console.log(query.callback);
      response.setHeader("Content-Type", "text/javascript;charset=utf-8");
      const string = fs.readFileSync("./index.js").toString();
      const data = fs.readFileSync("./index.json").toString();
      const string2 = string
        .replace("{{data}}", data)
        .replace("{{xxx}}", query.callback);
      response.write(string2);
      response.end();
    } else {
      response.statusCode = 404;
      response.send();
    }
  1. 一定要进行后台设置,才能拿到数据(主动沟通才有可能实现跨域)
  2. 面试题JSONP
    在跨域请求的时候,由于当前浏览器的某些原因不支持CORS,所以需要采用JSONP
    JSONP原理:请求JS文件,JS文件汇之星一个回调函数,回到里面就有需要的数据。回调函数的函数名是随机生成,把这个函数名以callback的形式传递给后台,后台会执行callback并在次返回给我们。
    JSONP优点:1,IE支持 2,实现跨域
    JSONP缺点: 由于它是script标签,读取不到ajax那么精确的状态,也不知道状态码是什么,也不知道响应头是什么,他只知道成功和失败。并且他只能发送get请求.
    CORS是在服务器端加上响应头,采用的是ajax请求。CORS支持所有类型的HTTP请求。

手写ajax

let xml = new XMLHttpRequest()
xml.open('get','/xxx')
xml.onreadystatechange = function(){
   if (xml.readyState === 4){
       if((xml.response.status >= 200 && xml.response.status < 300) || (xml.response.status === 304)){
           let data = xml.reponseText
       }else {
           console.log('失败')
       }
   }
}
xml.send()

//post请求只需要在 xml.send()中写入传递参数即可

xml.send('userbane=lili&passwoed=123')
0:请求未初始化,尚未调用open()方法
1:服务器连接已建立,启动,已经调用open()方法,但尚未调用send()方法。
2:发送,已经调用send()方法,但尚未接收到响应。
3:请求处理中,已经接收到部分响应数据。
4:请求处理完成且响应就绪。此时,触发load事件。

new一个函数发生了什么?

new命令的作用:执行构造函数,返回一个实例对象,this指对象实例。未使用new命令,构造函数就是普通函数,this指的就是window对象。

var fn = new Fn() 
//new Fn()生成的实例对象保存在变量fn中
  1. 创建一个空对象,作为将要返回的对象实例var a = {}
  2. 将这个空对象的原型指向构造函数的prototype属性a.__proto__ = FN.prototype
  3. 将这个空对象赋值给构造函数内部的thisthis = a
  4. 执行构造函数内部代码
    如果构造函数内部有return语句,并且return一个对象,那么new构造函数返回的对象就是return的对象,否则不管return语句。对普通函数,内部没有this的函数,new会返回一个空对象。
    总结:new一个函数,总是会返回一个对象,要么是实例对象,要么是return语句的对象.

闭包,立即执行函数,异步

  1. 闭包:函数及内部函数的总和就构成了闭包
  2. 作用:隐藏变量。
function foo(){
  var local = 1
  function bar(){
    local ++ 
  }
  return bar()
}
var f = foo()
f() //访问到了闭包
  1. 立即执行函数:创建一个匿名函数,立即执行这个匿名函数
  2. 作用: 创建一个独立作用域,防止产生全局fn
(function(){alert('声明一个立即执行函数')})()
  1. 异步:一种并行处理机制,不等待结果,例如:数据加载过程
  2. 同步:等待结果,比如登录
  3. 异步的形式: 轮询和回调
  4. 判断异步的方式
如果函数的返回值出于以下三个内,就是异步函数
1. ajax (XMLHttpRequest)
2. setTimeout()
3. addEventListener()
  1. 关于异步和回调
1. 异步任务不能拿到结果
2. 于是传递一个回调给异步任务
3. 异步任务完成后调用这个回调
4. 异步的结果为回调函数的参数
  1. 例子
function f(){
    setTimeout(() => {
        return 1
    },1000)
}
//f函数并没有return,默认return undefined
//此时这个异步函数拿不到结果,需要借助一个回调函数

function f(fn){
    setTimeout(() => {
        fn(1)
    })
}
function f1(x){console.log(x)}
f(f1)
  1. 回调,定义一个函数,在另外一个函数中调这个函数,这个函数就是回调函数
function f1(fn){
    fn()
}
f1(f2)
function f2(){

}
//f2即回调函数

bind(),call(),apply()的区别

作用:改变函数执行时的执行上下文,具体一点就是改变函数运行时的this指向.

这段代码里的 this 是什么?

1. fn()
this => window/global
2. obj.fn()
this => obj
3. fn.call(xx)
this => xx
4. fn.apply(xx)
this => xx
5. fn.bind(xx)
this => xx
6. new Fn()
this => 新的对象
7. fn = ()=> {}
this => 外面的 this
var obj = {
    foo: function(){
        console.log(this)
    }
}
var bar = obj.foo
obj.foo()  //obj  === obj.foo.call(obj)
bar()  //window === bar.call()

不用 class 如何实现继承?用 class 又如何实现?

//不用class实现继承
function Person(age){
    this.age = age
}
Person.prototype.move = function(){console.log('人类会移动')}

function Man(name){
    Person.call(this,age) //指定this为Man()。也可以使用Person.apply(this,age)
    this.name = name
}
//以下三行代码实现Man.prototype.__proto__ = Person.prototype
function temp(){}
temp.prototype = Person.prototype
Man.prototype = new temp()

Man.prototype.run = function(){console.log('男人会跑')}
var man = new Man(18,'li')

//使用class实现继承
class Person{
    constructor(age){
        this.age = age
    }
    move(){}
}
class Man extends Person{
    constructor(age,name){
        super(age)
        this.name = name
    }
    run(){}
}

原生JS有哪些获取元素的方法

1. 通过ID获取:document.getElementById('id')
2. 通过标签获取:document.getElementsByTageName()
3. 通过class获取:document.getElementsByClassName('class')
4. 通过name获取: document.getElementsByName('name')
5. 获取HTML:document.document.element()
6. 获取body:document.body 
7. 选择器选择一个元素:querySelector()
8. 选择器选择一组元素:querySelectorAll()

数组拷贝

1.扩展运算符浅拷贝数组

let a = [1,2,3,4,5,6]
let array = [...a]
console.log(array) //[1,2,3,4,5,6]
  1. for循环浅拷贝数组
let a = [1,2,3,4,5,6]
let array = []
for(let i = 0; i < a.length; i++){
    array.push(a[i])
}
console.log(array) //[1,2,3,4,5,6]
  1. Array.map()浅拷贝数组,map()接受一个回调函数,作为对数组的处理
let a = [1,2,3,4,5,6]
let array = a.map(x => x)
console.log(array) //[1,2,3,4,5,6]
  1. Array.filter()浅拷贝数组,filter()也接受一个回调函数
let a = [1,2,3,4,5,6]
let array = a.filter(x => x)
console.log(array) //[1,2,3,4,5,6]
  1. Array.slice()浅拷贝,指定start,end对原数组进行拷贝,包括start,不包括end
let a = [1,2,3,4,5,6]
let array = a.slice(2,5)
console.log(array) //[3,4,5] 
  1. Array.concat()浅拷贝,将原数组和其他数组结合
let a = [1,2,3,4,5,6]
let array = a.concat(2,5)
console.log(array) //[1, 2, 3, 4, 5, 6, 2, 5]
  1. Array.from()浅拷贝,可以将任何一个可迭代对象转化为数组
let a = 'foo'
let array = Array.from(a)
console.log(array) //["f", "o", "o"]
//实例2
let a = [1,2,3,4,5,6]
let array = Array.from(a)
console.log(array) //[1,2,3,4,5,6]

数组翻转,使用reverse()即可实现数组的翻转

let a = [1,2,3,4,56]
let array = a.reverse()
console.log(array) // [56, 4, 3, 2, 1]

JS的原型是什么?

typeof的结果有哪些?typeof null?为什么?

  1. typeof的结果
1. string  2.number  3. boolean  4. symbol  5. undefined  6. object  7. function
  1. typeof null
typeof null: object
原因:在JS最初的版本中,使用的是32位系统,为了性能考虑,使用地位存储性能变量的信息,对象是000开头,null全是0,所以误将null认为是对象了。
  1. typeof object
typeof 判断对象,除了function 显示function 之外,其他都显示对象,所以typeof不能很
好的判断对象。

instanceof的作用是什么?实现原理的思路是什么?

let Person = function(){}
let p1 = new Person()
console.log(p1 instanceof Person)  //true
let a = 'acb'
console.log(a instanceof String)  //false
- 正确的判断方法
let a = 'acb'
let b = new String(a)
console.log(b instanceof String)  //true

如何用正则实现 trim()?

String.prototype.trim = function(){
    return this.replace(/^\s+|\s+$/g, '')
}
//或者 
function trim(string){
    return string.replace(/^\s+|\s+$/g, '')
}

手写函数防抖和函数节流

防抖和节流都是为了防止函数的高频复用

let timerId;
function debounce(fn,wait = 0){
  if(timerId){
    clearTimeout(timerId)
    timerId = null
  }else {
    timerId = setTimeout(() => {
      fn()
      timerId = null
    },wait)
  }
}
function throttle(fn,wait = 200){
  let last = 1;
  let timerId;
  const now = + new Date()
  return function(...rest){
    //在时间间隔之内,不触发
    if(last && now-last < wait){
      clearTimeout(timerId)
      setTimeout(() => { 
        last = now
        fn.apply(this,rest);
      },wait)
    }else {
      fn.apply(this,rest)
      clearTimeout(timerId)
    }
  }
}

null和undefined的区别是什么?

Object.create()原理?

ES6引入的新方法,用来创建一个对象,这个对象的原型就是调用create方法时传入的参数

var a = Object.create(b)  
//a 的原型就是b

hasOwnPrototype()

是JS中唯一处理属性且不会遍历整个原型链的方法

必考 Promise、Promise.all、Promise.race 分别怎么用?

手写一个 Promise

移动端适配方案

常见的移动端兼容问题

用过token么?他有啥通,你把token放在那边了?

DOM相关

事件委托

用mouse事件写一个可拖曳的div

HTTP相关

一个URL从输入到页面加载共发生了什么?

无论是地址栏输入还是代码里加载,都会有一个URL,通过这个URL可以发送HTTP/HTTPS请求。请求过程,先查看缓存:浏览器缓存-系统缓存-路由缓存,如果缓存有,直接在缓存中获取,没有的话,对这个URL进行解析,提取信息,在进行DNS解析,得到对应域名的IP地址,通过三次握手,建立TCP连接,通过GET/POST等方式发送HTTP/HTTPS请求,服务器处理请求并响应请求,返回资源,浏览器拿到资源进行解析渲染,四次挥手,断开连接。

三次握手

  1. 客服端发送SYN报文 SYN = 1, seq = x 进入SYN_SEND阶段
  2. 服务器端接受SYN报文,返回一个ACK响应ACK = 1,SYN = 1,ack = x+1,seq = y进入SYN_RECV阶段
  3. 客户端接受服务器的SYN报文,返回一个ACK响应axk = y+1,seq = x+1.ACK=1进入Etablished阶段

四次挥手

  1. 客户端发送FIN=1,请求关闭连接SYN=1,seq = x进入FIN-WAIT-1阶段
  2. 服务器端返回ACK,ACK =1,seq = y,sck = x+1,进入CLOSE_WAIT阶段,客服端进入FIN-WAIT-2阶段
  3. 服务器通知应用程序关系连接,之后返回给客户端ACK=1,seq = z,ack = x+1,FIN=1进入LAST_ACK阶段
  4. 客户端返回ACK = 1,FIN = 1,seq = x+1,ack = z+1进入TIME_WAIT,服务端进入CLOSED阶段

为什么是三次握手,四次挥手呢?

因为服务器在接收到客户端关闭连接的请求时,是先返回一个应答ACK,表示收到这个请求了,之后通知应用程序去关闭连接,当应用程序关闭连接后,服务器才会通知客户端,已关闭,所以这个地方是分两步走的,所以比握手建立连接多了一步。

HTTP的状态码及意思

  1. 状态码:
    • 1XX:Informational(信息性状态码),接收的请求正在处理。
    • 2XX:Success(成功状态码),请求正常处理完毕。
    • 3XX:Redirection(重定向状态码),需要进行附加操作以完成请求。
    • 4XX:Client Erroe(客户端错误状态码),服务器无法处理请求。
    • 5XX:Server Error(服务器错误状态码),服务器处理请求出错。
  2. 200状态码:(成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
  3. 301状态码:(永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
  4. 302状态码:(临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
  5. 304状态码:(未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
  6. 403:状态码:(禁止) 服务器拒绝请求。
  7. 404状态码:(未找到) 服务器找不到请求的网页。
  8. 500状态码:(服务器内部错误) 服务器遇到错误,无法完成请求。
  9. 503状态码:(服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
    HTTP常见状态码

GET和POST的区别

GET和POST本质上就是TCP链接,并无差别,但是GET产生一个TCP数据包;POST产生两个TCP数据包。

  1. 作用不同:GET获取资源,像后台要数据;POST传输实体主体,像后台传输数据。
  2. 请求参数的展现发送不同:GET请求会用?将请求参数拼接成url;POST请求的请求参数在请求主体内。
  3. 传输数据长度不同:因为浏览器地址栏对自动对url进行截取,所以当数据量过大时,GET请求会造成数据丢失。
  4. 安全性:因为GET请求会拼接成url展示,但是浏览器的历史记录和服务器的请求日志,都会保存其信息,造成信息的不安全。

请求的动词

OSI的七层模型是什么?TCP/IP是哪四层模型?

  1. 应用层:
    应用层决定了向用户提供应用服务时通信的活动。下述的三层负责处理网络通讯的相关细节,这部分需要稳定高效,因此它们是在操作系统的内核空间中,而应用层是在用户空间实现的,负责处理众多业务逻辑,如文件传输、网络管理。
    应用层的协议众多:
    • 运行在TCP协议上的协议
      1.1 HTTP(80端口):主要用于普通浏览。
      1.2 HTTPS(443端口):HTTP协议的安全版本。
      1.3 FTP(20和21端口):用于传输文件。
      1.4 POP3(110端口):收邮件用。
      1.5 SMTP(25端口):用来发送电子邮件。
      1.6 SSH(22端口):用于加密安全登录用。
    • 运行在UDP协议上的协议
      2.1 DCHP(67端口,动态主机配置协议),动态配置IP地址。
    • 其他
      3.1 DNS(域名服务):用于完成地址查找,邮件转发等工作(运行在TCP/IP协议上)。
      3.2 SNMP(简单网络管理协议):用于网络信息的收集和网络管理。
      3.3 ARP(地址解析协议):用于动态解析以太网硬件的地址。
  2. 传输层:
    传输层对上层应用层,提供处于网络连接中的两台计算机之间的数据传输,即为应用程序隐藏了数据包跳转的细节,负责数据包的收发、链路超时重连等。
    传输层的协议:
    • TCP协议:传输控制协议,是一种面向连接的,可靠的,基于字节流的传输层通信协议。
    • UDP协议:用户数据报协议,不可靠的传输层协议。
  3. 网络层:
    网络层用来处理在网络上流动的数据包。
    网络层协议:
    • IP协议: 是网络层最核心的协议,它根据数据包的目的IP地址来决定如何投递该数据包。若数据包不可直接发送给目标主机,那么IP协议就为它寻找一个合适的下一跳路由器,并将数据包交付给该路由器去转发,如此循环直至到达目标主机或者发送失败而丢弃该数据包。
    • ICMP协议: 因特网控制报文协议ICMP,是IP协议的补充,用于检测网络的连接状态,如ping应用程序就是ICMP协议的使用。
  4. 链路层:
    用来处理连接网络的硬件部分。包括控制操作系统、硬件设备驱动、NIC(网络设备器即网卡),及光纤等物理课件部分(还包括连接器等一切传输媒介)。

说一下request包括哪些header

说一下reponse包括哪些header

第一行状态行: 协议版本号 状态码 状态信息
Content-Length 服务器返回消息的正文的长度
Content-type 返回的字符类型和字符编码格式
Date 显示当前的时间

HTTP缓存有哪几种?

HTTP1.0、HTTP1.1 和 HTTP2.0 的区别

  1. HTTP1.0(1996年)和HTTP1.1(1999年)的区别
  1. HTTP和HTTPS的区别
  1. SPDY对HTTP1.x的优化
  1. HTTP2.0和SPDY的区别
    HTTP2.0是对SPDY的升级,但也有不同
  1. HTTP2.0 和HTTP1.x的区别

HTTP2.0的多路复用和HTTP1.X中的长连接复用有什么区别?

Cookie VS LocalStorage(本地存储) VS SessionStorage(会话存储) VS Session

  1. Cookie VS LocalStorage
  1. LocalStorage VS SessionStorage
  1. Cookie VS Session

框架VUE相关

watch和method和computed三者的区别

Vue有哪些钩子函数,有什么用?

  1. beforeCreate:vue对象被创建了,但是Vue属性还没有绑定,template模板还没有HTML元素。
  2. created:vue属性被绑定了,但此时DOM还没有生成,$el还没有值
  3. beforeMount:this.$el有值,但是数据还没有挂载到页面上,{{}}内的变量还没有被替换
  4. mounted:模板编译完成,数据挂载完毕.此时可以发送异步ajax请求
  5. beforeUpdate:数据更新之前执行的函数,只有数据更新才会触发beforeupdate。此数据一定是在模板上出现的数据,否则,不会,也没有必要触发组件更新(因为数据不出现在模板里,就没有必要再次渲染)
  6. updated:组件更新之后执行的函数
  7. beforeDestory:组价对象销毁之前执行的函数
  8. destoryed:组件销毁了执行的函数.

Vue如何实现组件间的通信

  1. 父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed
//父组件
<template>
  <div id="app">
    <HelloWorld v-bind:users = "users"/>
  </div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'App',
  data(){
    return {
      users: ['li','xiao','qi']
    }
  },
  components: {
    HelloWorld
  }
}
</script>
//子组件
<template>
  <div>
    <ul>
      <li v-for="user in users">{{user}}</li>
    </ul>
  </div>
</template>
<script>
export default {
  name: 'HelloWorld',
  props: { //通过props接受从父组件传来的数据
      users: {
        type: Array  
      }
  }
}
</script>
  1. 父子组件:使用v-on通过事件通信
    子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。
//子组件
<template>
  <div>
    <h1 @click = "changeTitle">{{title}}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data(){
    return {
      title: "this is a son"
    }
  },
  methods: {
    changeTitle(){
      this.$emit('changeTitle','子组件想父组件传值')
    }
  }
}
</script>
//父组件
<template>
  <div id="app">
    <HelloWorld v-on:changeTitle = "updatetitle"/>
    <h2>{{title}}</h2>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  data(){
    return {
      title: "一个值"
    }
  },
  methods: {
    updatetitle(e){
      this.title = e
    }
  },
  components: {
    HelloWorld
  }
}
</script>
  1. 爷孙组件:使用两次v-on通过爷爷爸爸通信,爸爸儿子通信实现爷孙通信
  2. 任意组件:使用eventBus = new Vue()来通信,eventBus.$oneventBus.$emit是主要的API
var eventBus = new Vue()
eventBus.$emit(事件名,数据)
eventBus.$on(事件名,data =>{})
  1. 任意组件: 使用vuex通信

Vuex的原理及如何使用Vuex

  1. state:数据处理中心,用来存储数据
  2. getters:getters和组件的computed类似,方便生成一些直接可用的数据,当组装的数据要在多个页面使用的时候,使用getters比较好。
  3. Mutations:提交更改数据,使用store.commit()方法更改state的存储状态。
  4. Action:提交的是mutation,而不是直接更改状态,Action可以直接包含异步操作。由组件中的$store.dispatch('action名称',deta1)来触发,然后由commit()`来触发mutation的调用,间接更新State。
npm install vuex --save / yarn add vuex
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
  1. this.$store.state获取
    通过在根实例中注册store选项,改store实例会注入到根组件下的所有子组件,且子组件都能通过this.$store获取到
this.$store.state.count
  1. mapState()辅助函数获取
    当一个组件需要多个状态时,推荐使用mapState,他帮助我们生成计算属性。
import {mapState} from "vuex"
computed: mapState({
  count: state => state.count,
  //穿字符串'count'等同于传入'state => state.count'
  countAlias: 'count'
  //为了使用This,所以不能使用箭头函数
  countPlusLocalState(state){
    return state.count + this.countAlias
  }
})
  1. 通过属性访问
store.getters.doneTodos
  1. 通过方法访问
getters: {
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

getter在通过方法访问时,每次都会去进行调用,而不会缓存。

  1. mapGetters辅助函数获取
import {mapGetters} from "vuex"
export default {
  ....
   computed:{
      //使用对象展开符将getters混入computed 对象中
      ...mapGetters([
        'doneTodoCount',
      ])
    }
  }
  1. 使用常量替代Mutation事件类型
const store = new Vuex.Store = ({
  state: {...},
  mutations: {
    [SOME_MUTATION](state){
      //使用常量作为函数名
      //mutate state
    }
  }
  1. 可以在组件中使用this.$store.commit('xxx')提交mutation,或者使用mapMutations辅助函数将组件中的methods映射为store.commit调用
export default{
  ...mapMutaions([
    'increment',
    //将this.increment映射为this.$store.commit('increment')
  ])
}
const store = new Vuex.Store({
  state: {count: 0},
  mutations: {
    increment(state){state.count ++}
  },
  actions: {
    increment(context){
      context.commit('increment')
    }
  }
})
  1. 分发action
store.dispatch('increment',{
  acount:10
})
store.dispatch({
  type: 'increment',
  acount: 10
})
  1. 在组件中分发action
    在组件中使用this.$store.dispatch('xxx')分发action,或者使用mapActions辅助函数将组件中的Methods映射为store.dispatch调用
export default {
  methods: {
    ...mapMutations([
      'increment'
    ])
  }
}

vue数据响应式是怎么做到的

  1. property必须在data对象上存在才是响应式的。
var vm = new Vue({
  data: {
    a:1
  }
})
 // vm.a 是响应式的
vm.b =1 
//vm.b不是响应式
  1. 对于已经创建的实例,Vue不允许动态添加根级别的响应式property,但是可以使用Vue.set(object,propertyName,value)或者this.$set(object,propertyName,value)方法嵌套对象添加响应式property。
Vue.set(vm.object,'b',2)
this.$set(this.object,'b',2)
  1. 为对象赋值多个属性时
this.object = Object.assign({},this.object,{a:1,b:2})
  1. vue不能检测到一下数组的变动
    1.1利用索引直接修改一个数组的选项时vm.items[indexOf] = newValue
    1.2当修改数组的长度时,vn.length = newLength
  2. 对于1.1的情况,使用set,并且还可以触发响应式更新
Vue.set(vm.items,indexOf,newValue)
this.$set(this.items,indexOf,newValue)
  1. 对于1.2的情况,使用splice
this.$items.splice(newLength)
var vn = new Vue({
  data:{
    message:''
  }
})

Vue set有什么用

vue 是非侵入性响应式系统,所有的数据模型都是JS对象,一个JS对象传入Vue实例作为data选项时,VUE会遍历对象所有的property,使用Object.defineProperty将他们转化为getter/setter,,但是vue不支持动态添加根级别的响应式property,无法检测property的添加或者移除,所以采用set对属性进行添加和移除.

VueRouter怎么用

vue router是vue.js官方的路由管理器

  1. router-link
    导航,根据to属性去匹配对应的组件,然后渲染到正确的位置,若使用a标签,页面会发生跳转,router-link默认会渲染成a标签
<router-link  :to="{path:'/home'}" tag="li" ctive-class="activeClass" event="mouseover" exact>
 <span>home</span>
</router-link>
tag: 设置生成指定的标签名
to:页面要跳转的文件位置,可以动态绑定
active-class:设置单独的,独有的激活状态的颜色
event:指定事件
exact:其他路径被点亮的时候去掉根路径的active
redirect:重定向
  1. router-view
    命名视图,在同级同时展现多个视图,而不是嵌套展示,要对router-view起一个名字
<router-view name  = "silder"></router-view>
  1. 路由信息对象的params属性
    路由传参params ,只有通过路由配置的name跳转,才会生效,即使没有使用动态路由,也可以通过params传参
    如果使用动态路由,那么在动态路由页面刷新路由,params参数依然存在,
    如果没有使用动态路由,params参数只在跳转路由时有效,刷新页面则会丢失params
this.$route.params 获取到自己配置的动态路由参数,路由ID

一个路由信息对象,表示当前激活的路由的状态信息,包含当前URL解析得到的信息,还有URL匹配得到的路由记录。

  1. 其他
this.$route.back() //回退一步
this.$route.foreard() //前进一步
this.$route.go() //指定回退前进的步数
this.$route.push() //导航到不同的URL,向history栈中添加一个新的记录
this.$route.replace() //导航到不同的URL,替换掉栈中当前的记录
this.s4route.meta() //访问Meta中的数据
  1. 钩子函数
router实例上:beforeEach,afterEach
单个路由中: beforeEnter
组件内部的钩子: beforeRouterEnter beforeRouteUpdate BeforeRouteLeave 
参数: to from next
  1. vue-router默认是Hash模式,当URL改变时,页面不会重新加载。history模式,充分利用history.pushState API来完成URL跳转页面无需重新加载页面。当路由变化时,JS会根据路由渲染对应的VUE组件。
  2. vue-router是为单页面服务的需要在服务端增加一个覆盖所有情况的候选资源,如果URL匹配不到任何静态资源,返回一个index.html页面,也是app依赖的页面。这个index.html是我们项目的入口,index.html里面会读取当时打包好的app.js,就可以读取到路由配置了。
    hash是不需要配置的,因为浏览器会忽略#和?后面的参数
const router = new VueRouter({
  mode:'history',
  routes: [...]
})
  1. 警告:
    这么做以后,服务器就不在返回404页面,因为对于所有的路径都会返回Index.html,为了避免这种情况,应该在vue应用里面覆盖所有的路由情况,然后给出一个404
const router = new VueRouter({
  mode:'history',
  routes: [{
      path: '*',component: NotFoundComponent
    }]
})
  1. 原因:打包构建应用时,JS包会变得非常大,影响页面的加载。
  2. 解决:不同路由对应的组件分割成不同的代码块,然后当路由被访问时,加载对应的组件。
  3. 实现路由的懒加载:
    Vue的异步组件和webpack的代码分隔功能。
  4. 步骤
    4.1可以将异步组件定义为返回一个Promise的工厂函数
const Foo = () => Promise.resolve({/*组件定义对象*/})

4.2在webpack2中,使用动态Import语法来定义代码分块点

import ('./Foo.vue')
  1. 定义一个能够被webpack自动代码分隔的异步组件
const Foo = () => import('./Foo.vue')
const router = new VueRouter({
  routes: [
    {path:'/foo',component: Foo}
  ]
})

路由守卫是什么?

const router = new VueRouter({...})
router.beforeEach((to,from,next) => {})
to: Route:即将要进入的目标对象
from:Route:当前导航正要离开的路由
next:Function:一定要调用这个方法来resolve这个钩子,执行效果依赖Next方法传递的参数.
如果钩子全部执行完,导航的状态是confirmed(确认的)
router.beforeEach((to,from,next) => {
  if(to.name !==Login && !isLogin)next({name: 'Login'})
  else next()
})
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
  1. beforeRouteEnter:不能获取组件实例this,此时组件实例还未创建
  2. beforeRouteUpdate: 组件复用的时候调用,可以获取组件的实例this
  3. beforeRouteLeave:组件离开的时候调用,可以获取组件实例this
  4. beforeRouteEnter不能获取组件实例this,但是可以给next函数传递一个回调函数来访问组件的实例,在导航被确认的时候执行回调,并且吧实例作为回调的参数
beforeRouteEnter(to,from,next){
  next(vm => {})
}

beforeRouteEnter是唯一一个支持next传递回调函数的导航守卫,其他都不可以。

  1. beforeRouteLeave离开守卫通过进制用户在还未保存修改前突然离开,next(false)可以取消该导航.
  1. 导航被触发
  2. 在失活的组件里调用beforeRouteLeave
  3. 调用全局的beforeEach守卫
  4. 在复用的组件里调用beforeRouteUpdate守卫
  5. 在路由配置里调用beforeEnter守卫
  6. 解析异步路由组件
  7. 在被激活的组件里调用beforeRouteEnter
  8. 调用全局的beforeResolve
  9. 导航被确定
  10. 调用全局的afterEach钩子
  11. 触发DOM更新
  12. 用创建好的实例调用beforeEnter守卫中传给next回调函数

Vue有哪些指令

  1. 解释: 带有v-前缀的特殊属性
  2. 作用: 当表达式的值发生概念时,将其产生的影响响应式的作用于DOM。
事件修饰符
.stop 阻止冒泡,调用 event.stopPropagation()
.prevent 阻止默认事件,调用 event.preventDefault()
.capture 添加事件侦听器时使用事件捕获模式
.self 只当事件在该元素本身(比如不是子元素)触发时触发回调
.once 事件只触发一次

你发送请求放在哪个生命周期,beforeDestory应用场景

vue中的filters是干甚用的

{{}} --- 双花括号插值 {{message | capitalize}}
v-bind表达式 <div v-bind:id = "ravID | formatId"></div>
filters: {
  'capitalize': function(){}
}
Vue.filter('capitalize',function(){})
  1. 过滤器可以通过管道符写多个过滤器 {{messa | filter1 | fliter2}}而写多个函数就是一个很麻烦的事情,可能会产生很多的对象代理,依赖收集等一大推降低性能的问题
  2. Array原型链上可以用v-for循环解决,没必要在methods方法上面添加太多

vue 为什么data必须是函数。

JS的实例是由构造函数创建的,一个构造函数可以New出很多个实例,Vue 的data其实是vue 原型上的属性,数据是保存在内存中的,为了保证数据之间是互相独立的,互不影响的,使用return即函数,而不是对象,因为对象是内存引用。

slot的作用

<slot name = "headerr"></slot>

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称: v-slot 只能添加在 <template> 上

<template v-slot = "header'></template>
<ul>
  <slot name = "item" v-for = "item in items" :text = "item.text" :myname = "item.myname">
    slotmore内容
  </slot>
</ul>
<Child>
  <template slot = "item" v-slot = "props">
    <li>{{props.myname}}</li>
  </template>
</Child>

vue-router你说怎么传参的,有几种方式传参,他们的区别是什么?

  1. 直接在路由路径后面写参数${}
//页面列表传递参数
this.$router.push({
  path: '/custome/customeDetailPage/${id}'
})
//对路由的配置
{
  path: '/custome/customeDetailPage/:id'
}
//获取路由参数
this.$route.params.id
  1. 通过name属性来匹配路由,通过params传递参数
//页面列表参数
this.$router.push({
  name: 'CDetailPage', //name 属性是必须的
  params: {
    dataObj: id
  }
})
//路由配置
{
  path: '/custome/customeDetailPage',
  name: 'CDetailPage', //那么属性必须存在
  component: ''
}
//接受参数
  1. 通过path匹配路由,然后通过query传递参数
//页面列表参数
this.$router.push({
  path: '/custome/customeDetailPage',
  query: {
    name: 'id',
    dataObj: id
  }
})
//路由配置,name属性可有可无
{
  path: '/custome/customeDetailPage',
  component: ''
}
//接受参数
this.$route.query.dataObj
  1. 字符串
<router-link to = "news"></router-link>
  1. 命名路由
<router-link :to ={name: 'news',params: {userId: id}}></router-link>
  1. 查询参数
<router-link :to ={path: 'news',query: {userId: id}}></router-link>
  1. 命名路由搭配params,刷新页面数据会丢失
  2. 查询路由搭配query,舒心页面数据不会丢失。
  3. 命名路由的URL没有参数,只有/news
  4. 查询路由的Url带有参数,/news?id = 111

vuex的mutation action的作用

  1. 最好提前在store中初始化好所有所需的属性
  2. 需要在对象上添加属性时使用set或者展开符[...]
state: {
  num: [1,2,3,4]
}
mutations: {
  numChange(state){
    state.num[0]++
  }
}
  1. action提交的是Mutation,而不是直接更改状态
  2. action可以包含异步操作

axios是如何做到响应式拦截的

借助axios的拦截器实现Vue.js中登陆状态校验

上一篇 下一篇

猜你喜欢

热点阅读