面试题整理

590 阅读11分钟

本文仅作为本人复习梳理之用

参考:

作者:阳呀呀 juejin.cn/post/684490…

作者:张张-💫 链接:juejin.cn/post/684490…

小明同学呦 juejin.cn/post/684490…

blog.poetries.top/FE-Intervie… 淘淘笙悦 www.jianshu.com/p/c8b86b09d… yck segmentfault.com/a/119000001… 安歌 juejin.cn/post/694786…

CSS

盒模型

盒模型由margin、border、padding、content组成,分为标准盒模型和怪异盒模型,标准盒模型的宽度=content宽+左右padding,怪异盒模型的宽度=左右border+左右padding+content宽。

垂直居中的方法

1.将父元素设置成表格,子元素设置成表格元素
#parent {
	display: table;
}

#child {
	display: table-cell;
	vertical-align: middle; //text-align: center;
}
Internet Explorer(甚至 IE8 beta)中无效

2.css2属性
//#parent {text-align: center;}
#child{
    display: inline-block;
    vertical-align: middle;
}
#cbrother{
    display: inline-block;    width: 0;
    heigh: 100%
    vertical-align: middle;
}
parent{

    width: 0;
    heigh: 100%
    vertical-align: middle;
}

父相子绝
3.定位 + margin
parent{
    position: relative; 
 } 
#child {
	position: absolute;
	top: 50%;//left
	height: 240px;
	margin-top: -120px; /* negative half of the height */
}

4.定位
#parent{
    position: relative; 
 } 
#child {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
	margin: auto;
}
IE(IE8 beta)中无效

5.定位+动画
#parent{
    position: relative; 
 } 
#child{ 
    position: absolute; 
    top: 50%; 
    transform: translateY(-50%); 
}

6.flex布局
#parent{
    display:flex;/*Flex布局*/
    display: -webkit-flex; /* Safari */
    align-items:center;/*指定垂直居中*/
}

三列布局

圣杯布局的思路是先将中列的宽度设为100%,然后用margin来控制左列和右列
双飞翼布局是先用margin控制中列(设置最小值),左右两侧留出空白区域,
然后再用margin来控制左列和右列填充
1、圣杯布局
圣杯布局将页面分三栏,页面布局为middle、left和right,middle的宽度为
100%,本来left和right会被挤到第二行,通过margin-left控制left和right
的位置在第一行左右两边,达到左右固定,中间自适应的效果。
<style type="text/css">
    * {
      margin: 0;
      padding: 0;
    }

    .main>div {
    /*在给定的祖先元素下匹配所有的后代元素,main下的div全部左浮动*/
      float: left;
    }

    .left {
      width: 200px;
      background: red;
      margin-left: -100%;
    }

    .right {
      width: 200px;
      background: blue;
      margin-left: -200px;
    }

    .middle {
      width: 100%;
      background: yellow;

    }

    .content {
      margin-left: 200px;
      margin-right: 200px;
    }
  </style>

<body>
  <div class="main">
    <div class="middle">
      <div class="content">
        中间
      </div>
    </div>
    <div class="left">
      左边
    </div>
    <div class="right">
      右边
    </div>
  </div>
</body>

2、双飞翼布局
<style>
body {
  min-width: 500px;
}

#container {
  width: 100%;
}

.column {
  float: left;
}
        
#center {
  margin-left: 200px;
  margin-right: 150px;
}
        
#left {
  width: 200px; 
  margin-left: -100%;
}
        
#right {
  width: 150px; 
  margin-left: -150px;
}
        
#footer {
  clear: both;
}
</style>
<body>
  <div id="header"></div>
  <div id="container" class="column">
    <div id="center"></div>
  </div>
  <div id="left" class="column"></div>
  <div id="right" class="column"></div>
  <div id="footer"></div>
<body>

3.flex布局
左右固定宽度,中间设为flex:1
<style type="text/css">
 html*{
   margin: 0;
   padding: 0;
 }
 .container{
   display: flex;
 }
 .left{
   background-color: aqua;
   width: 300px;
   height: 100px;
 }
 .center{
   height: 100px;
   flex: 1;
   background: #f296ff;
 }
 .right{
   height: 100px;
   background-color: #6ee28d;
   width: 300px;
 }
</style>
<body>
 <!-- 已知高度,写出三栏布局,左右宽度300px,中间自适应-->
  <div class="container">
   <div class="left"></div>
   <div class="center"></div>
   <div class="right"></div>
 </div>
</body>

选择器权重计算方式

  • !important 权重始终最高。
  • 内联样式权重为1000。
  • ID选择器权重为0100。
  • 类,伪类和属性选择器权重为0010。
  • 元素选择器和伪元素选择器权重为0001。
  • 通配符、子选择器、相邻选择器等的。如*、>、+,权重为0000。
  • 继承的样式权重继承自父级元素。

清除浮动的方法(防止高度塌陷的方法)

1.给父元素添加声明overflow:hidden; (触发一个BFC)   
缺点:隐藏内容区以外的元素

2.在浮动元素下方添加空div,并给该元素添加声明:
div{clear:both; height:0; overflow:hidden;}  
缺点:造成代码的冗余

3.万能清除浮动法(给父元素引用)
选择符:after{content:"";clear:both;display:block;height:0;
overflow:hidden;visibility:hidden; font-size:1px;}

BFC

1.什么是BFC

BFC(Block formatting context)直译为“块级格式化上下文”。它是一个独立的渲染区域, 只有Block-level box(块)参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

2.怎么触发BFC

  1. float属性不为none
  2. position为absolute或fixed
  3. display为inline-block, table-cell, table-caption, flex, inline-flex
  4. overflow不为visible

3.BFC可以解决哪些问题

  1. 自适应两栏布局
  2. 清除内部浮动
  3. 防止margin上下重叠

如何实现一个自适应的正方形

.box{
    width: 20%;//width:20vw也可以
    height: 20vw;
    background: pink;
}

如何用css实现一个三角形

 <style>
    .box {
      height: 0;
      width: 0;
      overflow: hidden;
      /* 这里设置overflow, font-size, line-height */
      font-size: 0;
      /*是因为, 虽然宽高度为0, 但在IE6下会具有默认的 */
      line-height: 0;
      /* 字体大小和行高, 导致盒子呈现被撑开的长矩形 */
      border-color: #FF9600 #3366ff #12ad2a #f0eb7a;
      border-style: solid;
      border-width: 20px;
    }
  </style>

<body>
  <div class="box"></div>
</body>

em和rem的区别

  • rem等于html的font-size的大小
  • em等于父级元素的字体大小

link与@import的区别

  1. link是HTML方式, @import是CSS方式,link标签除了可以加载CSS外,还可以做很多其它的事情,比如定义rel连接属性等,@import就只能加载CSS。
  2. 兼容性的差别,@import是CSS2.1提出的,只在IE5以上的才能识识别,而link标签无此问题。
  3. link引用的CSS会同时被加载,而@import引用的CSS 会等到页面全部被下载完再被加载,页面样式会短暂失效。
  4. 当使用javascript控制dom去改变样式的时候,只能使用link标签。

文本省略号显示

单行
text-overflow属性仅是...,要实现溢出时产生省略号的效果还需定义:
1、容器宽度:width:value;
2、强制文本在一行内显示:white-space:nowrap;
3、溢出内容为隐藏:overflow:hidden;
4、溢出文本显示省略号:text-overflow:ellipsis;

多行
overflow: hidden;
display: -webkit-box;// 将对象作为弹性伸缩盒子模型显示。
text-overflow: ellipsis;
-webkit-line-clamp: 2;//显示的行数
-webkit-box-orient: vertical; // 从上到下垂直排列子元素(设置伸缩盒子的子元素排列方式)

哪些元素可以继承

  • 内联元素可继承:letter-spacing、word-spacing、white-space、line-height、color、font-family、font-size、font-style、font-weight、text- decoration、text-transform.
  • 块状元素可继承:text-indent和text-align。
  • 列表元素可继承:list-style、list-style-type、list-style-position、list-style-image。
  • 表格元素可继承:border-collapse

谷歌浏览器字体12px以下显示

font-size: 10px;
-webkit-transform-origin-x: 0;
// 解决字体缩小后的偏移问题
-webkit-transform: scale(0.8);

css移动端0.5x的直线怎么实现

div::before {
    content: "";
    dispaly: block;
    height: 1px;
    width: 200%;
    transform: scale(.5);
    background: red;
    position: absloute;
    left: 50%;
}

js

var,let,conse的区别

  • var声明的范围是函数作用域,let声明的范围是块级作用域
  • var可以重复声明,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明,let不能重复声明
  • var声明的变量会提升到函数作用域顶部
  • let声明的变量不会在作用域中被提升,JavaScript引擎会注意到块后面的let声明,在此之前不能以任何方式引用未声明的变量,在let声明之前的执行瞬间被称为“暂时性死区”,会抛出referenceError
  • 使用var关键字在全局作用域中声明的变量会成为window对象的属性,let不会
  • const 的行为与 let 基本一致,唯一重要区别是它声明的同时必须初始化。

手写题

防抖和节流

  1. 防抖:连续触发事件,函数在N秒之后只执行一次
function debounce(func, delay) {
    let timer = null //借助闭包
    return function() {
        if (timer) {
            clearTimeout(timer) 
        }
        timer = setTimeout(() => {
            func.apply(this, args)
        }, delay) // 简化写法
    }
}
  1. 节流:连续触发事件,函数在N秒内只执行一次
 function throttle(func, wait) {
    let timeout
    return function() {
        if (!timeout) {
            timeout = setTimeout(() => {
                func.apply(this, args)
                timeout = null
            }, wait)
        }
    }
 }

赋值、浅拷贝和深拷贝

1.赋值:
var a = [1, 2, 3, 4, 5];
var b = a;
a[0] = 2;
console.log(a);//[2, 2, 3, 4, 5]
console.log(b);//[2, 2, 3, 4, 5]
//ab指向同一个内存地址
//b会随着a的变化而变化
2. 浅拷贝是对对象第一层的拷贝
Object.assign()
是一种对象浅拷贝,只能拷贝第一层,其他的只能是引用
var obj1 = {a: 1, b: 2, c: {d: 4, e: 5}};
var obj2 = Object.assign({}, obj1);
console.log(obj1.c === obj2.c);//true
3. 深拷贝的实现
简单的深拷贝
var a = [1, 2, 3, 4, 5];
var b = [];
forEach(element => {
    b.push(element);
})

利用JSON深拷贝
var obj1 = {a: 1, b: 2, c: {d: 4, e: 5}};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1.c === obj2.c); //false,此时已经是对obj1.c 的整个复制,而不是只引用了地址

数组去重、数组排序

  1. 数组去重
方法一
function norepeat(arr) {
  for (var i=0;i<arr.length;i++) {
    for (var j=0;j<arr.length;j++) {
      if (arr[i] == arr[j] && i !=j) {
        arr.splice(j,1);
      }
    }
  }
  return arr;
} 

方法二
function noRepeat(arr) {
    return arr.filter(function(item, index) {
      return arr.indexOf(item, 0) === index;
  });
}
  1. 数组排序
  • 冒泡排序
function bubbleSort(arr) {
    var tem;
    for (var i = 0; i < arr.length - 1; i++) {
        for (var j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j+1]) {
                tem = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tem;
            }
        }
    }
    return arr;
}
  • 选择排序
function selectionSort(arr) {
      var index, temp;
      for (var i = 0; i < arr.length - 1; i++) {
        index = i;
        for (var j = i + 1; j < arr.length; j++) {
          if (arr[index] > arr[j]) {
            index = j;
          }
          if (index > i) {
            temp = arr[index];
            arr[index] = arr[i];
            arr[i] = temp;
          }
        }
      }
      return arr;
    }
}

继承

  1. 构造函数继承
构造函数继承无法继承原型中的方法
function Cat(n, m) {
    this.name = n;
    this.color =m;
     this.trait = function () {
       console.log('卖萌~');
    }
    Cat.prototype.behaviour = function (){
        console.log('抓老鼠');
    }
}
function Dog(n,c,f) { 
   this.food = f;
   Cat.call(this,n,c); 
}
var dog1 = new Dog('二哈','yellow','shi');
console.log(dog1.name); // 二哈
dog1.trait(); // 卖萌
dog1.behaviour(); // 报错 dog1.behaviour is not a function
  1. 原型链继承
原型链继承只能继承原型上的方法,无法继承自有方法
function Cat(n,c) { 
   this.name = n;
   this.color = c;
   this.trait = function (){
       console.log('卖萌~');
   }
}
Cat.prototype.behaviour = function () {
   console.log('抓老鼠');
}

function Dog(n,c,f) { 
   this.food = f;
}
Dog.prototype = Object.create(Cat.prototype);
Dog.prototype.constructor = Dog;
var dog1 = new Dog('二哈', 'yellow', '骨头');
//原型链:dog1.__proto__->->Cat.prototype->Object.prototype->null
console.log(dog1.name); // undefined
console.log(dog1.food); // 骨头
dog1.trait(); // dog1.trait is not a function
dog1.behaviour(); // 抓老鼠
  1. 混合继承
function Cat(n,c) {
   this.name = n;
   this.color = c;
   this.trait = function () {
       console.log('卖萌~');
   }
}
Cat.prototype.behaviour = function () {
   console.log('抓老鼠');
}

function Dog(n,c,f) {
   this.food = f;
   Cat.call(this,n,c);
}
Dog.prototype = Object.create(Cat.prototype);
Dog.prototype.constructor = Dog;
var dog1=new Dog('二哈', 'yellow', '骨头');
console.log(dog1.name);// 二哈
console.log(dog1.food);// 骨头
dog1.trait();// 卖萌
dog1.behaviour();// 抓老鼠
console.log(dog1.constructor);// Dog

Promise

  1. promise
  let p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        var num = parseInt(Math.random() * 10)
        if (num > 5) {
          resolve("1s请求成功")
        } else {
          reject("1s请求失败")
        }
      }, 1000)
    }).then(data => {
      console.log(data)
    }).catch(data => {
      console.log(data)
    })
  1. promise.all 和 promise.race
let p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        var num = parseInt(Math.random() * 10)
        if (num > 3) {
          resolve("2s请求成功")
        } else {
          reject("2s请求失败")
        }
      }, 2000)
    })
    let p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        var num = parseInt(Math.random() * 10)
        if (num > 3) {
          resolve("1s请求成功")
        } else {
          reject("1s请求失败")
        }
      }, 1000)
    })
    let p3 = new Promise((resolve, reject) => {
      setTimeout(() => {
        var num = parseInt(Math.random() * 10)
        if (num > 5) {
          resolve("3s请求成功")
        } else {
          reject("3s请求失败")
        }
      }, 3000)
    })
    
     //Promise.all,相当于后一个promise写在前一个promise的then里,
     所以只有前一个promise请求成功,才会执行后一个promise,全部
     请求成功时,返回一个请求成功的结果数组,请求失败时,则会抛
     出请求失败的那个Promise的结果
    Promise.all([p1, p2, p3]).then(data => {
      console.log(data)
    }).catch(data => {
      console.log(data)
    })
    //["2s请求成功", "1s请求成功", "3s请求成功"] 或 ns请求失败
   
    // Promise.race只会捕获最先执行完成的Promise
    Promise.race([p1, p2, p3]).then(data => {
      console.log(data)
    }).catch(data => {
      console.log(data)
    })
     //1s请求成功 或 1s请求失败

promise、async await

async/await是在Promise之后产生的,它和Promise诞生的目的都是为了解决“回调地狱”

  • async/await函数是异步代码的新方式
  • async/await是基于promise实现的
  • async/await使异步代码更像同步代码
  • await 只能在async函数中使用,不能再普通函数中使用,要成对出现
  • 默认返回一个promise实例,不能被改变
  • await下面的代码是异步,后面的代码是同步的
  • async 函数就是 Generator 函数的语法糖。

详细了解async await可参考:www.jianshu.com/p/2afb088ab…

如果async函数中是return一个值,这个值就是Promise对象中resolve的值;

如果async函数中是throw一个值,这个值就是Promise对象中reject的值。

    async function imAsync(num) {
      if (num > 0) {
        return num // 这里相当于resolve(num)
      } else {
        throw num // 这里相当于reject(num)
      }
    }
    //所以这个函数相当于
    function imAsync(num) {
      return new Promise((resolve, reject) => {
        if (num > 0) {
          resolve(num)
        } else {
          reject(num)
        }
      })
    }

await的作用是暂停当前async函数的执行,等待后面的Promise的计算结果返回以后再继续执行当前的async函数

(async function () {
  console.log(1);
  await new Promise(resolve => {
  //执行到这一步会先暂停 async函数的执行,先执行await后的promise
  //所以打印结果是先打印1,1s后打印2-3
    "use strict";
    setTimeout(() => {
      console.log(2);
      resolve();
    }, 1000);
  });
  console.log(3);
}())

正则实现一个邮箱

var email = /^[a-z0-9A-z\.\-\_]{1,14}@[a-z0-9A-z\.\-\_]{1,14}\.[a-z]{1,4}$/

浏览器相关

get和post的区别

  • get参数通过url传递,post放在请求体(request body)中;
  • get请求在url传递的参数有长度限制,而post没有;
  • get比post更不安全,因为参数直接显示在url地址中,所以不能传递敏感数据;
  • get请求浏览器会主动缓存,而post不会;
  • get请求参数会使用保存在浏览器中的历史记录(使用cookie),而post请求不会;
  • get和post本质上都是tcp连接。

ajax

参考:blog.csdn.net/c__dreamer/…

  • 使用ajax一共有4个步骤:
    • 1.创建ajax
    • 2.连接服务器
    • 3.发送请求
    • 4.接受返回值。
  • readyState 属性存有XMLHttpRequest对象的状态 readyState 会从 0 到 4 发生变化:
    • 0: 请求未初始化
    • 1: 服务器连接已建立
    • 2: 请求已接收
    • 3: 请求处理中
    • 4: 请求已完成

当 readyState 改变时就会触发 onreadystatechange 事件

status:http请求的状态码 状态码代表着http请求是成功还是失败等信息。

  • 下面是常见的HTTP状态码(HTTP Status Code):
    • 200:请求成功
    • 301:网页被重定向到其它URL
    • 304:文件未被修改,使用缓存资源
    • 404:找不到此网页(指定的资源)
    • 500:服务器内部错误
function ajax(options){
    var xhr = null;
    var params = formsParams(options.data);
    //创建对象
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest()
    } else {
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    // 连接
    if(options.type == "GET"){
        xhr.open(options.type,options.url + "?"+ params,options.async);
        //get请求会读取页面缓存,请求的地址没有改变,则get请求会直接从缓存拿数据,
        //可以在params上拼接一个时间戳解决缓存问题 t=new Date().getTime()
        xhr.send(null)
    } else if(options.type == "POST"){
        xhr.open(options.type,options.url,options.async);
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        xhr.send(params);
    }
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && xhr.status == 200){
            options.success(xhr.responseText);
        }
    }
    function formsParams(data){
        var arr = [];
        for(var prop in data){
            arr.push(prop + "=" + data[prop]);
        }
        return arr.join("&");
    }
 
}
 
ajax({
    url : "a.php",  // url---->地址
    type : "POST",   // type ---> 请求方式
    async : true,   // async----> 同步:false,异步:true 
    data : {        //传入信息
        name : "张三",
        age : 18
    },
    success : function(data){   //返回接受信息
        console.log(data);
    }
})

jsonp

  • jsonp跨域就是利用script标签的跨域能力请求资源
  • 利用js创建一个script标签,把json的url赋给script的scr属性,把这个script插入到页面里,让浏览器去跨域获取资源
  • callback是页面存在的回调方法,参数就是想得到的json
  • 回调方法要遵从服务端的约定一般是用 callback 或者 cb
  • 注意:jsonp只针对get请求
<body>
    <input class="ipt"/>
    <ul class="list"></ul>
</body>
<script>
    var ipt = document.querySelector('.ipt');
    var list = document.querySelector('.list');
    var Script = null;

    ipt.onkeyup = function () {
        if (Script) {
            document.body.removeChild(Script);
        }
        Script = document.createElement('script');

        Script.src = 'http://suggestion.baidu.com/su?cb=myCb&wd='+ipt.value;
        //文档接口要求传入两个查询字段  cb:回调函数myCb   wd:关键字
        document.body.appendChild(Script);
    }
    function myCb(json) {//接收处理数据
        list.innerHTML = '';
        for(var i = 0, len = json.s.length; i < len; i++){
            list.innerHTML += '<li>'+ json.s[i] +'</li>';
        }
    }

javascript

闭包

当一个函数能够记住并访问到其所在的词法作用域及作用域链,特别强调是在其定义的作用域外进行的访问,此时该函数和其上层执行上下文共同构成闭包。

需要明确的几点:

  1. 闭包一定是函数对象
  2. 函数内保持对上层作用域的引用
  3. 闭包和词法作用域、作用域链、垃圾回收机制等息息相关
  4. 当函数在其定义的作用域外进行访问时,才产生闭包
  5. 闭包是由该函数和其上层执行上下文共同构成

作用域和作用域链

  1. 作用域
    • 词法作用域,也叫静态作用域,它的作用域是指在词法分析阶段就确定了,不会改变。
    • 动态作用域,是在运行时根据程序的流程信息来动态确定的。

词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。

  1. 作用域链
    • 作用域链:本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。 (简而言之,作用域链,就是在当前作用域中如果没有该属性(局部变量)则向上一层作用域中寻找,一直到最上层,也就是window)

原型和原型链

  1. prototype(原型)
    • 每一个函数,解析器都会向函数中添加一个prototype属性,这个属性对应着一个对象,这个对象就叫做原型对象。
  2. __proto__属性
    • 每个对象都有一个隐藏属性__proto__,用于访问创建它的构造函数的原型。属性__proto__非官方标准属性,但主流的浏览器基本都支持
  3. 原型链
    • 访问一个对象属性时,如果在当前对象中没有该属性,则向上一层原型对象中寻找,一直找到最外层,也就是null(Object.prototype__proto__指向null)。

原型链是靠_ _ proto _ _来维护的!

es6

proxy

参考:es6.ruanyifeng.com/#docs/proxy

ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。

var proxy = new Proxy(target, handler);

Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。

webpack

用过哪些loader和plugin

  1. loader
    • style-loader: 将模块的导出作为样式添加到DOM中
    • css-loader: 解析css文件后,使用import导入,并且返回css代码
    • less/sass-loader:加载和转译less/sass文件
    • postcss-loader: 给css代码添加浏览器兼容代码
    • url/file-loader:用于加载图片
    • babel-loader:将代码转译成es5
    • vue-loader:允许以单文件组件的格式撰写 Vue 组件(必备)
  2. plugin
    • UglifyjsWebpackPlugin:压缩javascript代码
    • HtmlWebpackPlugin:打包HTML代码
    • babel-plugin-component:按需引入组件(element)
    • babel-plugin-import:按需引入组件(vant)

vue

推荐: juejin.cn/post/684490…

vue生命周期

  var vm = new Vue({
    el: '#app',
    data: {
      title: '',
    },
    //1.孕育生命,初始化操作,主要是劫持data,设置get和set属性
    beforeCreate: function () {
      console.log('beforeCreate', this.$data, this.$el);//undefined undefined
    },
    //2.实例化完成
    created: function () {
      setInterval( () => {
        // this.title = Math.random();
      }, 2000)
      console.log('created', this.$data, this.$el);
    },//data  undefined
    //3.挂载前
    beforeMount: function () {
      console.log('beforeMount', this.$data, this.$el);
    },//data  el(<p>{{ title }}</p>)
    //4.挂载元素,获取DOM节点,把编译结果放在页面上,但还没有渲染。
    mounted: function () {
      console.log('mounted', this.$data, this.$el);
    },//data  el(<p></p>)
    5.可以监听到data的变化,但是view层没有被重新渲染。
    beforeUpdate: function(){
      console.log('beforeUpdate', this.$data);
    },
    6.view层才被重新渲染,数据更新。
    updated: function(){
      console.log('update', this.$data);
    },
    7.钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。
    beforeDestroy: function () {
      console.log('beforeDestroy');
    }
    8.Vue实例销毁后调用,Vue实例指示的所有东西都会解绑定
    Destroyed: function () {
      console.log('Destroyed');
    }
  })

vue的单项数据流

  1. 什么是单向数据流
    • 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
    • 额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。 2.两种常见的试图改变prop的情形
    • 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值
props: ['initialCounter'],
data: function () {
  return {
    counter: this.initialCounter
  }
}

  • 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性
props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

MVVM

M - Model,代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑

V - View,视图层,代表 UI 组件,它负责将数据模型转化为 UI 展现出来

VM - ViewModel,业务逻辑层,监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View

  1. MVVM 将数据双向绑定(data-binding)作为核心思想,View 和 Model 之间没有联系,它们通过 ViewModel 这个桥梁进行交互。
  2. Model 和 ViewModel 之间的交互是双向的,因此 View 的变化会自动同步到 Model,而 Model 的变化也会立即反映到 View 上显示。
  3. 当用户操作 View,ViewModel 感知到变化,然后通知 Model 发生相应改变;反之当 Model 发生改变,ViewModel 也能感知到变化,使 View 作出相应更新。

参考:www.jianshu.com/p/bcad6a5a6…

简单的数据双向绑定实现

  <div id="app">
    <input v-model="msg" />
  </div>
  
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        msg: ''
      }
    });
  </script>

vue中 key 值的作用

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用让每个item有一个唯一的识别身份,可以下标值index或者id, 主要是为了vue精准的追踪到每一个元素,高效的更新虚拟DOM。

作者:zsy氯化钠 链接:www.jianshu.com/p/df75f6061… 来源:简书

key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。Vue 的 diff 过程可以概括为:oldCh 和 newCh 各有两个头尾的变量 oldStartIndex、oldEndIndex 和 newStartIndex、newEndIndex,它们会新节点和旧节点会进行两两对比,即一共有4种比较方式:newStartIndex 和oldStartIndex 、newEndIndex 和 oldEndIndex 、newStartIndex 和 oldEndIndex 、newEndIndex 和 oldStartIndex,如果以上 4 种比较都没匹配,如果设置了key,就会用 key 再进行比较,在比较的过程中,遍历会往中间靠,一旦 StartIdx > EndIdx 表明 oldCh 和 newCh 至少有一个已经遍历完了,就会结束比较。具体有无 key 的 diff 过程,可以查看作者写的另一篇详解虚拟 DOM 的文章《深入剖析:Vue核心之虚拟DOM》

所以 Vue 中 key 的作用是:key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速

更准确:因为带 key 就不是就地复用了,在 sameNode 函数a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。

更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快,源码如下:

  let i, key
  const map = {}
  for (i = beginIdx; i <= endIdx; ++i) {
    key = children[i].key
    if (isDef(key)) map[key] = i
  }
  return map
}

作者:我是你的超级英雄 链接:juejin.cn/post/684490… 来源:掘金

vue初始化页面时在哪个生命周期发请求

  • beforeCreate ($el$data) 拿不到任何信息,无法篡改数据,一般做loding,这个时候的vue实例还什么都没有,但是$route对象是存在的,可以根据路由信息进行重定向之类的操作
  • created ($el、$data) $el,没有初始化,数据已加载完成,可以篡改数据,并更新,不会触发beforeUpdate,updated,在这结束loading,还做一些初始化,实现函数自执行,$ref属性内容为空数组
  • beforeMount ($el、$data) $el已被初始化,,数据已加载完成,可以篡改数据,并更新,不会触发beforeUpdate,updated,在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数
  • mounted ($el、$data) $el已被初始化,,数据已加载完成,可以篡改数据,并更新,并且触发beforeUpdate,updated,在这发起后端请求,拿回数据,配合路由钩子做一些事情,$ref属性可以访问 综上所述:created可以做简单的请求,但不能操作dom,如需操作dom可以在mounted里发起请求

网络协议

HTTP状态码及其含义

1XX:信息状态码

  • 100 Continue 继续,一般在发送post请求时,已发送了http
  • header之后服务端将返回此信息,表示确认,之后发送具体参数信息

2XX:成功状态码

  • 200 OK 正常返回信息
  • 201 Created 请求成功并且服务器创建了新的资源
  • 202 Accepted 服务器已接受请求,但尚未处理

3XX:重定向

  • 301 Moved Permanently 请求的网页已永久移动到新位置。
  • 302 Found 临时性重定向。
  • 303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。
  • 304 Not Modified 自从上次请求后,请求的网页未修改过。

4XX:客户端错误

  • 400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
  • 401 Unauthorized 请求未授权。
  • 403 Forbidden 禁止访问。
  • 404 Not Found 找不到如何与 URI 相匹配的资源。

5XX: 服务器错误

  • 500 Internal Server Error 最常见的服务器端错误。
  • 503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。

性能优化

  • 减少 HTTP 请求数
  • 减少 DNS 查询
  • 使用 CDN
  • 避免重定向
  • 图片懒加载
  • 减少 DOM 元素数量
  • 减少DOM 操作
  • 使用外部 JavaScript 和 CSS
  • 压缩 JavaScript 、 CSS 、字体、图片等
  • 优化 CSS Sprite
  • 使用 iconfont
  • 字体裁剪
  • 多域名分发划分内容到不同域名
  • 尽量减少 iframe 使用
  • 避免图片 src 为空
  • 把样式表放在link 中
  • 把JavaScript放在页面底部

本文仅作为本人复习梳理之用