Liang2uv's blog Liang2uv's blog
首页
  • 前端文章

    • JavaScript
    • Vue
    • 面试总结
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 小程序笔记
    • TypeScript笔记
    • 数据结构笔记
    • mongoDB笔记
    • nginx笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • 关于
  • 作品集

Liang2uv

我也想成为前端大佬
首页
  • 前端文章

    • JavaScript
    • Vue
    • 面试总结
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 小程序笔记
    • TypeScript笔记
    • 数据结构笔记
    • mongoDB笔记
    • nginx笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
  • 网站
  • 资源
  • 关于
  • 作品集
  • JavaScript文章

    • new命令原理
    • ES5面向对象
    • ES6面向对象
    • 多种数组去重性能对比
    • JS随机打乱数组
    • 判断是否为移动端浏览器
    • 将一维数组按指定长度转为二维数组
    • 防抖与节流函数
    • JS获取和修改url参数
    • 比typeof运算符更准确的类型判断
  • Vue文章

  • 学习笔记

  • 面试总结
    • 事件冒泡
    • 节点
      • 克隆节点
      • 移动节点
    • IE兼容
    • HTML相关
      • HTML5新增标签
      • SEO优化
    • css 问题
      • CSS基础
      • 定位
      • 溢出省略号
      • 隐藏元素
      • 水平垂直居中的方法
      • CSS3新增的属性
      • 选择器
      • 清除浮动
      • BFC
      • 移动端适配
    • JS题目
      • 反转字符串
      • 数组去重
      • 判断变量类型
      • 深拷贝和浅拷贝
      • 取出url参数
      • 防抖和节流
    • 设计模式
      • 设计模式的基本原则
      • 单例模式
      • 工厂模式
      • 创建者模式
      • 装饰器模式
      • 组合模式
      • 策略模式
      • 观察者模式
    • 原型和原型链
      • 创建对象
      • 原型链
      • 继承
    • 网络相关
      • HTTP状态码
      • 跨域
    • Vue题目
      • MVVM
      • 常用指令
      • 生命周期
      • vue-router
      • keep-alive
      • 组件通信
      • vuex
      • 自定义指令
      • 过滤器
      • watch和computed的区别
      • vue和angular以及react的区别
  • 前端
Liang2uv
2019-10-12

面试总结

# 面试总结

# 事件冒泡

  • 阻止事件冒泡的两种方式:

    • event.stopPropagation()

      $("#button").click( function(event){
          alert("button-click");
          // 阻止事件冒泡到DOM树上
          event.stopPropagation(); 
      } );
      
      1
      2
      3
      4
      5
    • event.target

      $('#switcher').click(function(event){
          if(event.target==this){//判断是否是当前绑定事件的元素元素触发的该事件
              $('#switcher .button').toggleClass('hidden');
          }
      })
      
      1
      2
      3
      4
      5
    • 写入return false,虽然阻止了冒泡,但是也阻止了默认行为

  • event.preventDefault()是阻止元素事件的默认行为,不能阻止冒泡

# 节点

# 克隆节点

  • 使用cloneNode(bool deep)方法,deep为true的时候会将节点的子节点都一起克隆

    window.onload = function () {
    	var sourceNode = document.getElementById("div-0"); // 获得被克隆的节点对象
        for (var i = 1; i < 5; i++) {
            var clonedNode = sourceNode.cloneNode(true); // 克隆节点
            clonedNode.setAttribute("id", "div-" + i); // 修改一下id 值,避免id 重复
            sourceNode.parentNode.appendChild(clonedNode); // 在父节点插入克隆的节点
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

# 移动节点

  • 使用jQuery的before()方法或after()方法:

    $(function(){
        $('.move-up').click(function(){
            var cur_li = $('.move');
            var prev_li = cur_li.prev();     // prev()方法:获取当前节点的上一个节点,返回数组
            if(prev_li.length != 0){
                prev_li.before(cur_li); // 调用before()方法向上移动节点
            }
            else {
                alert("元素已经到顶部!");
            }
        });
        
    });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $(function(){
        $('.move-down').click(function(){
            var cur_li = $('.move');
            var next_li = cur_li.next();     // next()方法:获取当前节点的下一个节点,返回数组
            if(next_li.length != 0){
                next_li.after(cur_li); // 调用after()方法向下移动节点
            }
            else {
                alert("元素节点已经到底部!");
            }
        });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  • 参考网址

# IE兼容

  • 参考网址

  • 方法:

    1. 明确你要兼容的浏览器范围

    2. 检查伪类和伪元素:IE9是不支持伪类的,所以不能用伪类:after的方法去清除浮动,只能用clear:both;

    3. 判断浏览器类型:

      // navigator对象是浏览器对象,包含浏览器的相关信息
      if(navigator.userAgent.indexOf('Opera') != -1) { 
      	alert('Opera'); 
      } 
      else if(navigator.userAgent.indexOf('MSIE') != -1) { 
      	alert('Internet Explorer'); 
      } 
      else if(navigator.userAgent.indexOf('Firefox') != -1) { 
      	alert('Firefox'); 
      } 
      else if(navigator.userAgent.indexOf('Netscape') != -1) { 
      	alert('Netscape'); 
      } 
      else if(navigator.userAgent.indexOf('Safari') != -1) { 
      	alert('Safari'); 
      } 
      else{ 
      	alert('无法识别的浏览器。'); 
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19

# HTML相关

# HTML5新增标签

# SEO优化

  • 三大标签:title(百度不超过28个中文)、description(不超过120个字)、Keywords(6-8个关键词)

# css 问题

# CSS基础

  • 轮廓outline

    • 和border的用法一样,不过设置outline不会影响盒子大小和布局
  • 阴影效果box-shadow(x, y, 模糊半径(可省), color)

# 定位

  • 相对定位relative

    1. 相对定位是相对于元素在文档流中的位置决定的
    2. 相对定位会提升元素的层级
    3. 相对定位元素不会使元素脱离文档流
    4. 相对定位不会改变元素的性质,块还是块,行内还是行内
  • 绝对定位absolute

    1. 元素从文档流脱离

    2. 元素性质改变,行内变成块,块的高度被内容撑开

    3. 会提升层级

    4. 是相对于最近的、已定位的父元素进行定位

    5. 注意点:

      • left | right | top | bottom 的默认值是auto

      • 水平布局公式变为:left/right + margin-left/right + border-left/right + padding-left/right + width = 包含块的宽度

      • 垂直布局公式变为:top + margin-top/bottom + border-top/bottom + padding-top/bottom + height = 包含块的高度

      • 利用以上几点,可以实现水平垂直居中

        .parent {
            background-color: red;
            position: relative;
            width: 500px;
            height: 500px;
            margin: 100px auto;
        }
        .child {
            background-color: green;
            width: 100px;
            height: 100px;
            position: absolute;
            margin: auto;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
  • 固定定位fixed

    1. 固定定位也是一种绝对定位,大部分特点和绝对定位一样
    2. 不同的是固定定位是参考于浏览器的视口进行定位
  • 粘性定位sticky

    1. 使元素到达某个位置的时候固定

# 溢出省略号

  • 单行文本
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
1
2
3
  • 多行文本
overflow : hidden;
text-overflow: ellipsis表示用省略号; /*ellipsis表示用省略号表示被裁剪的文本*/
display: -webkit-box; /*伸缩盒子*/
-webkit-line-clamp: 2; /*限制一个块元素显示的文本行数*/
-webkit-box-orient: vertical;/*伸缩盒子子元素的排列方式vertical-垂直*/
1
2
3
4
5

# 隐藏元素

  • 参考网址
  1. {display: none;}不占据空间,无法点击
  2. {visibility: hidden;}占据空间,无法点击
  3. {visibility: hidden; position: absolute;}不占据空间,无法点击
  4. 将该元素改为透明,用opacity:0;
  • display: none和visibility: hidden的区别:
    1. display不占据空间,visibility占据空间
    2. display在隐藏的时候会重绘

# 水平垂直居中的方法

  • 单行文本可以使用height和line-height方法来实现

  • position+margin:需要知道子元素的宽高

    .parent {
        position: relatiive;
    }
    .child {
        position: absolute;
        height: 100px;
        top: 50%;
        left: 50%;
        margin: -50px 0 0 -50px;
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  • position+transform:不需要知道子元素的宽高

    .parent {
        position: relatiive;
    }
    .child {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 使用flex布局:只能在IE10+使用

    .parent {
        display: flex;
        justify-content: center;
        align-items: center;
    }
    .child {
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8

# CSS3新增的属性

  • 边框、背景、渐变、阴影、2D转换、3D转换

# 选择器

# 常用选择器

  • id、class、标签、通配符、属性

# 组合选择器

  • 后代选择器A B
  • 子选择器A > B
  • 相邻兄弟选择器A + B
  • 普通兄弟选择器A ~ B

# 伪类选择器

伪类用 :

  • active、checked、focus、hover
  • first-child/last-child/nth-child
  • first-of-type/last-of-type/nth-of-type

# 伪元素选择器

伪元素用 ::

  • first-letter

    /*实现首字母下沉*/
    p::first-letter {
        font-size: 50px;
    }
    <p>Lorem is dash</p>
    
    
    1
    2
    3
    4
    5
    6
  • first-line:选中第一行

  • first-selection:鼠标选中的时候

  • before和after

# 选择器权重

选择器 权重
!important 无穷大
内联样式 1000
id选择器 100
class | 属性 | 伪类 10
标签选择器 | 伪元素 1
通配符选择器 0

# 清除浮动

  • 作用:

    1. 不让块级元素被浮动元素覆盖,而是在浮动元素下单独一行
    2. 不需要文字环绕效果
    3. 解决浮动导致的高度坍塌问题
  • 方法(解决高度塌陷):

    1. 设置父元素为固定高度

    2. 向父元素的末尾插入一个div,并设置clear:both

    3. 伪元素清除(类似方法2)

      #parent::after {
          content: "";
          display: block | table;
          clear: both;
      }
      
      
      1
      2
      3
      4
      5
      6
    4. 将父元素变为BFC,如设置父元素overflow: hidden

  • 方法(解决父子元素外边距重叠)

    1. 将父元素变为BFC,如设置父元素overflow: hidden

    2. 伪元素清除法

      .con {
          width: 200px;
          height: 200px;
          background-color: #ff0000;
      }
      .con::before {
          content: "";
          display: table;
      }
      .box1 {
          width: 100px;
          height: 100px;
          background-color: #0000ff;
          margin-top: 100px;
      }
      
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16

# BFC

  • 概念:页面中的一块独立的渲染区域,有自己的渲染规则,决定了内部元素的排列方式
  • 规则:
    1. 内部box会在垂直方向一个一个放置
    2. 子元素和父元素的外边框不会合并
    3. 开启BFC的元素不会被浮动元素所覆盖
    4. 计算BFC高度的时候,浮动元素也参与计算(用来解决高度塌陷问题)
    5. 是页面上一个独立的容器,容器里的子元素和外面的元素不会互相影响
  • 产生BFC的方式:
    1. 根元素
    2. float不为none
    3. position为absolute或fixed
    4. display为inline-block
    5. overflow不为visible

# 移动端适配

# 几个概念

  1. 视口viewport:浏览器可显示区域的大小

    <meta name="viewport" content="width=device-width,initial-scale=1"/>
    
    
    1
    2
  2. 物理像素:手机屏幕的最小单元,如分辨率为1980*1080表示1980个物理像素点*1080个像素点

  3. 设备像素比(dpr):dpr = 物理像素/设备独立像素(视口宽度),放大网页会变大,缩小网页会减小

  4. px:设备独立像素,css像素

  5. em:1em = 当前对象的font-size

  6. rem:1rem = 根元素的font-size

  7. vw:100vw = 视口宽度,1vw = 1%视口宽度,在iphone里面视口宽度是375,所有drp=2

# JS题目

# 反转字符串

let str = "adbfka ded";
let reStr = [...str].reverse().join("");

1
2
3

# 数组去重

  • Set结构去重

    // 不能用于数组对象
    let unique = [...new Set(array)];
    
    
    1
    2
    3
  • 遍历:不能用于数组对象,而且不能辨别NaN

    let arr1 = [1,1,'1','1',NaN,NaN,undefined,undefined,null,null];
    let unique = arr => {
        let newArr = [];
        arr1.foreach(item => {
            if(newArr.indexOf(item) < 0){
                aNnewArr.push(item);
            }
        })
        return newArr;
    }
    console.log(unique); //输出:[1,'1',NaN,NaN,undefined,null] //NaN没有去重
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

# 判断变量类型

function getType(value){
    if(Object.prototype.toString.call(value) === "[Object Object]"){
        console.log("value是对象");
    }else if(Object.prototype.toString.call(value) === "[Object Array]"){
        console.log("value是数组");
    }
}

1
2
3
4
5
6
7
8

# 深拷贝和浅拷贝

  • 区别:js的数据类型分为基础类型(Number、String、Boolean等)和引用类型(Object、Array),浅拷贝只复制了对象的引用地址,修改拷贝之后对象的值,被拷贝的对象的值也会改变,深拷贝把对象和值复制过来,修改其中一个对象的值,另一个对象不会受到影响

  • 深拷贝实现

    function deepCopy(obj) {
        let newObj = {};
        let flag = false;
        if (Array.isArray(obj)) {
            newObj = [];
            flag = true;
        }
        for (let key in obj) {
            if (flag) {
                newObj.push(typeof obj[key] == "object" && obj[key] != null ? deepCopy(obj[key]) : obj[key]);
            } else {
                newObj[key] = typeof obj[key] == "object" && obj[key] != null ? deepCopy(obj[key]) : obj[key];
            }
        }
        return newObj;
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

# 取出url参数

function getQuery(url) {
  url = url.replace(/((.*)\?)|(#(.*))/g, "");
  let obj = {};
  let arr = url.split("&")
  if(arr[0] == ""){
    return obj;
  }
  arr.forEach(item => {
    let kv = item.split("=");
    obj[kv[0]] = kv[1];
  });
  return obj;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 防抖和节流

# 概念

  • 防抖:就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
  • 节流:指连续触发事件但是在 n 秒中只执行一次函数

# 实现

  • 防抖(debounce)

    /**
     * @desc 函数防抖
     * @param func 函数
     * @param wait 延迟执行毫秒数
     * @param immediate true 表立即执行,false 表非立即执行
     */
    function debounce(func,wait,immediate) {
        let timeout;
    
        return function () {
            let context = this;
            let args = arguments;
    
            if (timeout) clearTimeout(timeout);
            if (immediate) {	// 第一次触发事件之后立即执行,在延迟执行毫秒数内触发不会重复执行
                var callNow = !timeout;
                timeout = setTimeout(() => {
                    timeout = null;
                }, wait)
                if (callNow) func.apply(context, args)
            }
            else {	// 最后一次触发事件的延迟执行毫秒数后再执行
                timeout = setTimeout(function(){
                    func.apply(context, args)
                }, wait);
            }
        }
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
  • 节流(throttle):实现方式有事件戳或定时器

    // 时间戳版
    function throttle(func, wait) {
        let prev = 0;
        return function() {
            let now = new Date();
            let context = this;
            let args = arguments;
            if (now - prev > wait) {
                func.apply(context, args);
                prev = now;
            }
        }
    }
    // 定时器版
    function throttle(func, wait) {
        let timeout;
        return function() {
            let context = this;
            let args = arguments;
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args);
                }, wait)
            }
        }
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

# 设计模式

# 设计模式的基本原则

  • 单一职责原则
  • 开放封闭原则
  • 接口隔离原则
  • 里式替换原则
  • 依赖倒置原则
  • 迪米特法原则

# 单例模式

  • 保证一个类只有一个实例,并且提供一个全局的访问点。

  • 适用场景:弹窗,无论点多少次,弹窗只应该被创建一次

class CreateUser {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}
// 代理实现单例模式
var ProxyMode = (function() {
  var instance = null;
  return function(name) {
    if(!instance) {
      instance = new CreateUser(name);
    }
    return instance;
  }
})();
// 测试
var a = new ProxyMode("aaaa"); 
var b = new ProxyMode("bbb");
console.log(a === b); // 输出true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 工厂模式

  • 是一种创建对象的设计模式,不对外暴露创建对象的逻辑,而是把这些逻辑封装在一个函数里
  • 使用场景:请求的封装
function PersonFactory(name) { // 工厂函数
  let obj = new Object();
  obj.name = name;    
  obj.sayName = function(){
      return this.name;
  }
  return obj;
}
let person1 = new PersonFactory("张三");
let person2 = new PersonFactory("李四");

console.log(person1.name); // 张三
console.log(person1.sayName()); // 张三
console.log(person2.name); // 李四
console.log(person2.sayName()); // 李四

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 创建者模式

  • 类似工厂模式,不过更加注重创建对象的细节,可以创建出复杂对象或者复合对象

  • 使用场景:对接口返回的数据进行处理

    // 原数据
    var data = {
        name: 'li si'
    }
    // 创建者模式函数
    function FnData (data) {
        var p = new Person(data)
        p.nameObj = new NameObj(data.name)
        return p
    }
    function Person (data) {
        this.name = data.name
    }
    function NameObj (name) {
        this.fullname = name
        this.firstname = name.split(' ')[0]
        this.secondname = name.split(' ')[1]
    }
    // 测试
    var _data = FnData(data)
    console.log(_data)
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

# 装饰器模式

  • 希望在不改变原对象的基础上,通过对其扩展功能和属性来实现更复杂的逻辑

  • 使用场景:扩展某个对象的功能

    function Person (money) {
        this.money = money
    }
    // 添加收入
    function addMoney (person) {
        person.money += 2;
    }
    // 减少收入
    function reduceMoney (person) {
        person.money -= 10;
    }
    // 测试
    var p = new Person(100)
    addMoney(p)
    reduceMoney(p)
    console.log(p)
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

# 组合模式

  • 用于将多个部分组合成一个整体
  • 适用场景:创建表单,表单的输入框、下拉框等可以自由组合

# 策略模式

  • 对不同的输入采取不同的策略,如果有需求变更,只需要添加或修改策略

  • 使用场景:使用object代替重复的if...else代码

    // if...else
    function showStar (level) {
        if (level === 'A') {
            return '5颗星'
        } else if (level === 'B') {
            return '4颗星'
        } else if (level === 'C') {
            return '3颗星'
        } else {
            return ''
        }
    }
    // 使用策略模式
    function showStarFn (level) {
        const resultMap = {
            A: '5颗星',
            B: '4颗星',
            C: '3颗星',
            de
        }
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

# 观察者模式

  • 观察者模式也称发布订阅模式、消息模式,消息中心是主体,当满足触发条件时,会通知订阅的个体

  • 使用场景:onClick事件绑定方法、vue里的watch

    var msgCenter = (function () {
        var registerList = {}
        return {
            // 订阅消息
            register: function (key, fn) {
                if (typeof fn !== 'function') {
                    console.log('请添加函数');
                    return;
                }
                if (!registerList[key]) {
                    registerList[key] = [];
                }
                registerList[key].push(fn);
            },
            // 发布消息
            trigger: function (key, ...rest) {
                const funList = registerList[key];
                if (!(funList && funList.length)) {
                    return false;
                }
                funList.forEach(fn => {
                    fn.apply(this, rest);
                });
            }
        }
    })()
    // 测试
    msgCenter.register('click', () => { console.log('我订阅了') });
    msgCenter.register('click', () => { console.log('我也订阅了') });
    msgCenter.trigger('click');
    // 输出:我订阅了 我也订阅了
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

# 原型和原型链

# 创建对象

  1. new Object
var p = new Obejct();
p.name = 'hh';
p.age = 18;
p.eat = function () {
    console.log('吃饭');
}

1
2
3
4
5
6
7
  1. 字面量
var p = {
    name: 'hh',
    age: 18,
    eat: function () {
        console.log('吃饭');
    }
}

1
2
3
4
5
6
7
8
  1. 工厂模式
function createP (name, age) {
    var obj = new Obejct();
    obj.name = name;
    obj.age = age;
    obj.eat = function () {
        console.log('吃饭');
    }
}
var pp = createP('hehe', 19);
var ppp = createP('pp', 18);

1
2
3
4
5
6
7
8
9
10
11
  • 缺点:不能判断类型,所有的对象都是Object类型

    • typeof pp 输出Object

    • pp instanceof Object 输出true

  1. 构造函数
function Person (name, age) {
    this.name = name;
    this.age = age;
    this.eat = function () {
    	console.log('吃饭');
    }
}
var p = new Person('hehe', 18);
var p2 = new Person('hehe', 18);

1
2
3
4
5
6
7
8
9
10
  • 构造函数创建对象的过程(new 的时候发生了什么)
    1. 在内存中创建一个空对象
    2. 对象的__proto__属性指向构造函数的prototype
    3. 设置构造函数的this,让this指向刚刚创建好的空对象
    4. 按顺序执行构造函数中的代码(可以执行构造函数中的函数)
  1. 返回这个对象(把this返回)
  • 获取对象的具体类型用instanceof ,不能用typeof

    • typeof p 输出"object"
    • p instanceof Object 输出true
    • p instanceof Person 输出true
    • p.constructor === Person 输出true,但不建议使用,因为构造器可以被改变
  • p 和 p2 的 eat() 方法是不一样的,在不同的内存中存储 p.eat() === p2.eat() 输出false

# 原型链

# 概念

构造函数、实例对象、构造函数的原型对象、Object构造函数、Object原型对象、null

  1. 构造函数和实例对象

    • 通过构造函数创建实例对象
  2. 构造函数和构造函数的原型对象

    • 构造函数里面具有该构造函数的原型对象prototype
    • 构造函数的原型对象的 constructor 指向了构造函数
  3. 实例对象和构造函数的原型对象

    • 实例对象中的 __proto__ 指向了它的构造函数的原型对象 prototype ,即: p.__proto__ === Person.prototype
  4. 构造函数的原型对象和Object原型对象

    • 构造函数的原型对象Person.prototype里面有__proto__属性,说明原型对象也是一个对象,说明是被某个构造函数实例化出来的,这个构造函数就是Object构造函数,所以构造函数的原型对象的__proto__(注意,不是构造函数的__proto__) 指向Object构造函数的原型对象prototype,即:Person.prototype.__proto__ === Object.prototype
  5. Object原型对象和null

    • Object原型对象也是个对象,但是里面没有__proto__属性,所以Object.prototypr.__proto__ === null,即Object原型对象的__proto__指向了null

总结:

  • 实例对象的原型对象等于其构造函数的原型对象,即:p.__proto__ === Person.prototype

  • 构造函数的原型对象的原型对象等于Object构造函数的原型对象,即:Person.prototype.__proto__ === Object.prototype

  • 实例对象的原型对象的原型对象等于Object构造函数的原型对象,即:p.__proto__.__proto__ === Object.prototype

  • Object原型对象的原型对象为null,即:Object.prototype.__proto__ === null

# 属性查找规则

  1. 读取属性

    • 在实例对象本身先查找,如果没有找到,会在原型链上查找,一直找到Object原型
  2. 设置属性:

    • 使用p.test = 'hehe'如果没有这个属性,不会在原型链上查找,直接在这个对象本身设置
  • 例:

    Function.prototype.a = function () {
      console.log(4);
    }
    function Foo () {
      Foo.a = function () {
        console.log(1);
      }
      this.a = function () {
        console.log(2);2
      }
    }
    Foo.prototype.a = function () {
      console.log(3);
    }
    Foo.a(); // 输出4
    var foo = new Foo(); // 会执行构造函数里的代码,给Foo添加实例属性
    Foo.a(); // 输出1
    foo.a(); // 输出
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

# 继承

# 概念

类型和类型之间的关系

# 目的

把子类中的成员提取到父类中,实现代码重用

# 方式

  1. 原型继承
 function Person (name, age) {
     this.name = name;
     this.age = age;
     this.eat = function () {
         console.log('吃饭');
     }
 }
Person.prototype.sleep = function () {
    console.log('睡觉');
}
function Child (sex) {
    this.sex = sex;
}
// 将原型对象设为父类的实例
Child.prototype = new Person();
// 将构造器指向自身的构造函数
Child.prototype.constructor = Child;

var c = new Child('男');
var p = new Person('人类总的', 10);
console.dir(c);
console.dir(p);
console.log(c instanceof Child);
console.log(c instanceof Person);
console.log(c instanceof Object);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • 输出:
  • 缺点:
    • 无法设置父类属性的值
  • 注意:
    • 子类实例对象的原型对象的原型对象 === 父类构造函数的原型对象,所以子类实例对象 instanceof 父类 === true
  1. 借用构造函数

    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.eat = function () {
            console.log('吃饭');
        }
    }
    Person.prototype.sleep = function () {
        console.log('睡觉');
    }
    // name和age是父类的属性,sex是子类的属性
    function Child(name, age, sex) {
        // 借用构造函数,使用call方法
        Person.call(this, name, age);
        this.sex = sex;
    }
    var c = new Child('我是子类', 18, '男');
    var p = new Person('我是父类', 10);
    console.dir(c);
    console.dir(p);
    console.log(c instanceof Child);
    console.log(c instanceof Person);
    console.log(c instanceof Object);
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    • 输出:

  • 缺点:
    • 父类的原型对象的属性和方法无法继承
  • 注意:
    • 父类的非原型对象的属性和方法会直接添加到子类的实例对象上
    • 子类实例对象的原型对象的原型对象 === Object的原型对象,非父类的原型对象,即子类与父类无原型链上的关联,所以子类实例对象 instanceof 父类 === false
  1. 组合继承 (借用构造函数继承 + 原型继承)

    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.eat = function () {
            console.log('吃饭');
        }
    }
    Person.prototype.sleep = function () {
        console.log('睡觉');
    }
    function Child(name, age, sex) {
        // 借用构造函数继承
        Person.call(this, name, age);
        this.sex = sex;
    }
    // 原型继承,不要等于Person.prototype
    Child.prototype = new Person();
    // 添加构造器
    Child.prototype.constructor = Child;
    // 子类的原型对象私有的方法
    Child.prototype.drinknainai = function () {
        console.log('喝奶');
    }
    var c = new Child('我是子类', 18, '男');
    var p = new Person('我是父类', 10);
    console.dir(c);
    console.dir(p);
    console.log(c instanceof Child);
    console.log(c instanceof Person);
    console.log(c instanceof Object);
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
  • 输出:

  • 缺点:
    • __proto__的属性没有用
    • 执行了两次父类构造函数
  • 注意:

    • 在使用原型继承的时候,不用使用子类.prototype = 父类.prototype,如Child.prototype = Person.prototype,因为会和父类的原型对象共用一个地址,导致子类无法在自己的原型对象上添加自己私有的属性和方法,一旦添加,父类的原型对象也会改变,导致混乱
  1. 寄生组合继承

    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.eat = function () {
            console.log('吃饭');
        }
    }
    Person.prototype.sleep = function () {
        console.log('睡觉');
    }
    function Child(name, age, sex) {
        // 借用构造函数继承
        Person.call(this, name, age);
        this.sex = sex;
    }
    // 创造一个无自身属性方法新函数,原型指向父类的原型
    function Fn() {};
    Fn.prototype = Person.prototype;
    // 将子类的原型指向新函数的实例对象
    Child.prototype = new Fn();
    // 添加构造器
    Child.prototype.constructor = Child;
    // 子类的原型对象私有的方法
    Child.prototype.drinknainai = function () {
        console.log('喝奶');
    }
    var c = new Child('我是子类', 18, '男');
    var p = new Person('我是父类', 10);
    console.dir(c);
    console.dir(p);
    console.log(c instanceof Child);
    console.log(c instanceof Person);
    console.log(c instanceof Object);
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    • 输出:

# 网络相关

# HTTP状态码

1xx:1开头是信息状态码

2xx: 2开头是请求成功,如200

3xx: 3开头是重定向:301-永久移动,302-临时移动,307-临时重定向

4xx: 4开头是客户端错误:400-请求语法错误,401-未授权,403-禁止访问,404-找不到,

5xx: 5开头是服务器错误:500-服务端内部错误,502-错误网关

# 跨域

  • 为什么跨域:因为浏览器的同源策略,不能在一个域下访问另一个域的资源,同源是指:协议+域名+端口号相同
  • 解决方法:
    • jsonp:利用html的script标签可以访问外域的原理,通过动态创建script标签,设置标签的src属性,再通过回调获取到数据,缺点是只能使用get请求
    • cors:在后端有一个cors属性,设置成*可以运行所有域访问
    • proxy代理:在webpack设置proxy本地代理,但是只能在开发阶段用,部署到服务器上会失效
    • nginx反向代理:这是最好的一种方式,可以在部署时用,一般在开发阶段用proxy代理,正式生产环境用nginx反向代理

# Vue题目

# MVVM

  • 理解:
    1. Model:数据模型,也可以定义数据的修改和操作的业务逻辑
    2. View:用户操作界面,当ViewModel对Model进行更新的时候,会通过数据绑定更新到View
    3. ViewModel:业务逻辑层,主要功能是给View提供数据响应View的操作,Model for View
    4. 总结:MVVM模式简化了界面和业务的依赖,解决了数据频繁更新,MVVM在使用中,利用双向绑定技术,使得Model变化,ViewModel变化,View跟着变化

# 常用指令

  • 渲染
    • 插值语法
    • v-text,更新innerText
    • v-html,更新innerHTML
  • 条件渲染
    • v-if / v-else-if / v-else
    • v-show
  • 循环语句
    • v-for
  • 属性和事件
    • v-bind
    • v-on
  • 双向绑定
    • v-model
  • 其他
    • v-slot
    • v-pre
    • v-once: 只渲染该元素或组件一次
    • v-clock:用了设置样式,编译结束之后样式会自动移除, 当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会显示出 Vue 源代码。我们可以使用 v-cloak 指令来解决这一问题

# 生命周期

# 完整生命周期

  1. beforeCreate:组件实例创建之初,组件属性集合data生效之前
  2. created:组件实例已创建,data已生效,但是真实的dom还没生成,$el不可用
  3. beforeMount:$el和data都初始化了,相关的render函数首次被调用,编译模板,把data和模板生成html,但是html没有挂载到页面上
  4. mounted:完成html的挂载和渲染
  5. beforeUpdate:数据更新前
  6. updated:数据更新后
  7. activited:keep-alive专属,组件被激活时使用
  8. deactivited:keep-alive专属,组件被销毁时使用
  9. beforeDestory:组件销毁前
  10. destoryed:组件销毁后

# 父子组件生命周期执行顺序

  • 先执行父组件的beforeCreate、created、beforeMount,再执行子组件的beforeCreate、created、beforeMount、mounted,最后再执行父组件的mounted,所以如果要把一些常用的数据传递给子组件,最好在父组件的created和beforeMount传递完成

# vue-router

# 路由传参

  • 使用:参数名传参,页面刷新数据不会丢失

    // 在路由中配置(:参数名)
    {
        path: '/particulars/:id',
        name: 'particulars',
        component: particulars
    }
    // 跳转
    this.$router.push({ path: `/particulars/${id}`,})
    // 获取参数
    this.$route.params.id
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  • 使用params传参,页面刷新数据会丢失

    // 在跳转的时候添加params属性
    this.$router.push({
        name: 'particulars',
        params: {
            id: id
        }
    })
    // 获取参数
    this.$route.params.id
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 使用query传递参数,这样的话传递的参数会显示在url后面,?id=xxx

    // 在跳转的时候添加params属性
    this.$router.push({
        name: 'particulars',
        query: {
            id: id
        }
    })
    // 获取参数
    this.$route.query.id
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

# history和hash模式的区别

  • history模式:地址栏URL中没有#,访问二级页面的时候,在刷新操作,会出现404错误,需要后端做配合重定向到首页路由

  • hash模式:地址栏URL中带有#,#和#后面的内容不会被包含在http请求中,所以在页面刷新的时候不会跳转,不出现404错误

# 导航守卫

  • 全局守卫
    1. beforeEach
    2. beforeResolve
    3. afterEach
  • 路由独享守卫
    1. beforeEnter
  • 组件内守卫
    1. beforeRouteEnter
    2. beforeRouteUpdate
    3. beforeRouteLeave

# router和route

  • router是vue-router的一个实例对象,提供一些方法,比如push、replace、go、back等
  • route是跳转的路由对象,每个路由都有一个route对象,里面有一些name、path、params、query属性

# keep-alive

  • 理解:keep-alive是对组件进行缓存,第一次组件执行初始化之后如果再回到这个组件,这个组件不会再执行created、mounted等生命周期,组件的数据和第一次初始化的数据相同,常用的应用场景比如商品的详情页或者tab页面这些频繁点击且数据不常更新的页面。keep-alive有include和exclude两个属性通过正则匹配去判断是否缓存

# 组件通信

  • 父子组件通信
    • 父组件向子组件传递数据通过props,子组件向父组件传递数据通过$emit
    • 通过、children父链、子链的方式通信
    • 通过$refs获取到组件实例
  • 兄弟组件通信
    • evenBus、vuex,一般是用vuex
  • 跨级通信
    • evenBus、vuex,一般是用vuex

# vuex

  • vuex用作全局数据的状态管理,实现了一个单向数据流
  • state:页面的状态管理对象,全局唯一
  • action:在组件里通过dispatch调用action的异步方法获取到数据
  • mutation:如果要修改数据,可以在action里通过commit调用mutation里的方法来修改state上的数据
  • getters:如果要获取state对象里的数据,可以通过getters读取
  • module:如果使用单一状态树,所以数据都集中在一个对象里,就会显得比较臃肿,所以可以使用module进行模块划分,每个模块都有自己的state、action、mutation、getters

# 自定义指令

  • vue允许注册自定义指令

    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('focus', {
       // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
       bind: function (el) {},
       // 被绑定元素插入父节点时调用
       inserted: function (el) {},
       // 所在组件的 VNode 更新时调用
       update: function (el) {},
       // 指令所在组件的 VNode 及其子 VNode 全部更新后调用
       componentUpdated: function (el) {},
       // 只调用一次,指令与元素解绑时调用
       unbind: function (el) {}
    })
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

# 过滤器

  • filter不会修改原始数据,用于过滤数据,应用场景比如日期格式的美化
  • 过滤器的功能函数:第一个参数是原数据,第二个参数是传入的参数

# watch和computed的区别

  • watch是监听一个数据的变化,是一个数据变化之后的回调,其函数参数有oldValue和newValue,如果要监听复杂数据类型比如对象的话,需要添加deep: true属性
  • computed是一个计算属性,对数据有一个缓存的效果,只有依赖的数据发生改变的时候才会重新求值,里面提供了get和set方法

# vue和angular以及react的区别

# vue与angular的区别
  • angular采用ts开发,vue可以用js和ts
  • angular依赖对数据做脏检查,vue使用基于依赖追踪的观察并且使用异步队列更新,所有数据都是独立触发
  • angular社区完善,vue的学习成本较小
# vue与react的区别
  • vue的组件分为全局注册和局部注册,react都是通过import引用
  • vue有多指令系统,让模板可以实现更丰富的功能,react只能用jsx语法
  • react的设计思想是all in js,通过js生成html,通过js操作css,而vue是把html,css,js组合到一起,用各自的处理方式
  • react是函数式编程,推崇组件化、数据不可变、单向数据流,vue是声明式写法,数据可变,双向绑定
上次更新: 2020/12/06, 21:12:00
nginx笔记

← nginx笔记

最近更新
01
第十章:排序
11-05
02
第九章:查找
11-05
03
第八章:图
11-05
更多文章>
Theme by Vdoing | Copyright © 2020-2021 Liang2uv | 桂ICP备19012079号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式