美文网首页
Vue-06-生命周期-箭头函数

Vue-06-生命周期-箭头函数

作者: OrangeQjt | 来源:发表于2018-10-01 11:09 被阅读0次
    今天,我们来了解一下生命周期的运行结构;它的核心部分就是mounted,下面就是它的图解:
    [图片上传中...(360截图20181001105915688.jpg-d881fe-1538362800251-0)] 360截图20181001105915688.jpg

    Vue提供的可以注册的钩子都在上图片的红色框标注。 他们是:

    beforeCreate
    在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。

    created
    实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

    beforeMount
    在挂载开始之前被调用:相关的 render 函数首次被调用。

    mounted
    el 被新创建的 vm.el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.el 也在文档内。

    beforeUpdate
    数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。

    updated
    由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

    当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。

    该钩子在服务器端渲染期间不被调用。

    beforeDestroy
    实例销毁之前调用。在这一步,实例仍然完全可用。

    destroyed

    Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。

    接下来我们做一个例子,看一下Vue中所有的生命周期怎么用的。

    
    <!DOCTYPE html> 
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Vue入门之生命周期</title>
      <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
      <div id="app">
        <p>{{ number }}</p>
        <input type="text" name="btnSetNumber" v-model="number">
      </div>
      <script>
        var app = new Vue({         
          el: '#app',               
          data: {                   
            number: 1
          },
          beforeCreate: function () {
            console.log('beforeCreate 钩子执行...');
            console.log(this.number)
          },
          cteated: function () {
            console.log('cteated 钩子执行...');
            console.log(this.number)
          },
          beforeMount: function () {
            console.log('beforeMount 钩子执行...');
            console.log(this.number)
          },
          mounted: function () {
            console.log('mounted 钩子执行...');
            console.log(this.number)
          },
          beforeUpdate: function () {
            console.log('beforeUpdate 钩子执行...');
            console.log(this.number)
          },
          updated: function () {
            console.log('updated 钩子执行...');
            console.log(this.number)
          },
          beforeDestroy: function () {
            console.log('beforeDestroy 钩子执行...');
            console.log(this.number)
          },
          destroyed: function () {
            console.log('destroyed 钩子执行...');
            console.log(this.number)
          },
        });
      </script>
    </body>
    </html>
    再看一个综合的实战的例子,可能涉及到ajax和组件,不过先看一下vue的生命周期的例子的用法:
    
    import Axios from 'axios'       // 这是一个轻量级的ajax库,import是es6模块导入的语法。
    export default {                // 这是一个vue的模块,后面讲奥。
      name: 'app',
      components: {
      },
      data: function () {
        return {
          list: []
        }
      },
      mounted: function () {          // 挂在完成后的生命周期钩子注册。
        this.$nextTick(function () {  // 等待下一次更新完成后执行业务处理代码。
          Axios.get('/api/menulist', {// 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新
            params: {
            }
          }).then(function (res) {
            this.list = res.data
          }.bind(this))
        })
      }
    }
    
    B.箭头函数:

    前言

    this 指向问题是入坑前端必须了解知识点,现在迎来了ES6时代,因为箭头函数的出现,所以感觉有必要对 this 问题梳理一下,遂有此文

    在非箭头函数下, this 指向调用其所在函数的对象,而且是离谁近就是指向谁(此对于常规对象,原型链, getter & setter等都适用);构造函数下,this与被创建的新对象绑定;DOM事件,this指向触发事件的元素;内联事件分两种情况,bind绑定, call & apply 方法等, 容以下一步一步讨论。箭头函数也会穿插其中进行讨论。

    全局环境下

    在全局环境下,this 始终指向全局对象(window), 无论是否严格模式;

    console.log(this.document === document); // true
    
    // 在浏览器中,全局对象为 window 对象:
    console.log(this === window); // true
    
    this.a = 37;
    console.log(window.a); // 37
    

    函数上下文调用

    函数直接调用

    普通函数内部的this分两种情况,严格模式和非严格模式。

    非严格模式下,this 默认指向全局对象window

    function f1(){
      return this;
    }
    
    f1() === window; // true
    

    而严格模式下, this为undefined

    function f2(){
      "use strict"; // 这里是严格模式
      return this;
    }
    
    f2() === undefined; // true
    

    对象中的this

    对象内部方法的this指向调用这些方法的对象,

    1. 函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
    2. 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。
    //1
    var o = {
      prop: 37,
      f: function() {
        return this.prop;
      }
    };
    console.log(o.f());  //37
    var a = o.f;
    console.log(a()):  //undefined
    
    var o = {prop: 37};
    
    function independent() {
      return this.prop;
    }
    
    o.f = independent;
    
    console.log(o.f()); // logs 37
    
    //2
    o.b = {
      g: independent,
      prop: 42
    };
    console.log(o.b.g()); // logs 42
    

    原型链中this

    原型链中的方法的this仍然指向调用它的对象,与以上讨论一致;看个例子,

    var o = {
      f : function(){ 
        return this.a + this.b; 
      }
    };
    var p = Object.create(o);
    p.a = 1;
    p.b = 4;
    
    console.log(p.f()); // 5
    

    可以看出, 在p中没有属性f,当执行p.f()时,会查找p的原型链,找到 f 函数并执行,但这与函数内部this指向对象 p 没有任何关系,只需记住谁调用指向谁。

    以上对于函数作为getter & setter 调用时同样适用。

    构造函数中this

    构造函数中的this与被创建的新对象绑定。

    注意:当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this。

    function C(){
      this.a = 37;
    }
    
    var o = new C();
    console.log(o.a); // logs 37
    
    function C2(){
      this.a = 37;
      return {a:38};
    }
    
    var b = new C2();
    console.log(b.a); // logs 38
    

    以上两个例子内部的this都指向对象o, 看到这里的你不妨在控制台执行下以上代码,看看对象 o 和 b ,这些是属于构造函数的内容了,此处不多做介绍。(C2函数中的this.a = 37 对整个过程完全没有影响的, 可以被忽略的)。

    call & apply

    当函数通过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。

    例子:

    function add(c, d){
      return this.a + this.b + c + d;
    }
    
    var o = {a:1, b:3};
    
    add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
    
    add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
    
    function tt() {
      console.log(this);
    }
    // 返回对象见下图(图1)
    tt.call(5);  // Number {[[PrimitiveValue]]: 5} 
    tt.call('asd'); // String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}
    
    image

    bind 方法

    bind方法在ES5引入, 在Function的原型链上, Function.prototype.bind。通过bind方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

    function f(){
      return this.a;
    }
    
    var g = f.bind({a:"azerty"});
    console.log(g()); // azerty
    
    var o = {a:37, f:f, g:g};
    console.log(o.f(), o.g()); // 37, azerty
    

    DOM 事件处理函数中的 this & 内联事件中的 this

    DOM事件处理函数

    1. 当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)
      // 被调用时,将关联的元素变成蓝色
        function bluify(e){
          //在控制台打印出所点击元素
          console.log(this);
          //阻止时间冒泡
          e.stopPropagation();
          //阻止元素的默认事件
          e.preventDefault();      
          this.style.backgroundColor = '#A5D9F3';
        }
    
        // 获取文档中的所有元素的列表
        var elements = document.getElementsByTagName('*');
    
        // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
        for(var i=0 ; i<elements.length ; i++){
          elements[i].addEventListener('click', bluify, false);
        }
    
    

    以上代码建议在网页中执行以下,看下效果。

    内联事件
    内联事件中的this指向分两种情况:

    1. 当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
    2. 当代码被包括在函数内部执行时,其this指向等同于 ****函数直接调用****的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined
    image

    页面的代码块

    image

    在浏览器内显示三个按钮

    image

    依次点击上边的三个按钮后在控制台的输出结果,

    建议自己操作一遍以便于更好的理解。

    setTimeout & setInterval

    对于延时函数内部的回调函数的this指向全局对象window(当然我们可以通过bind方法改变其内部函数的this指向)
    看下边代码及截图

    //默认情况下代码
    function Person() {  
        this.age = 0;  
        setTimeout(function() {
            console.log(this);
        }, 3000);
    }
    
    var p = new Person();//3秒后返回 window 对象
    ==============================================
    //通过bind绑定
    function Person() {  
        this.age = 0;  
        setTimeout((function() {
            console.log(this);
        }).bind(this), 3000);
    }
    
    var p = new Person();//3秒后返回构造函数新生成的对象 Person{...}
    
    image image

    箭头函数中的 this

    由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值,

    1. 所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。
    2. 考虑到 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略。(可以忽略是否在严格模式下的影响)

    因为箭头函数可以捕获其所在上下文的this值 所以

    function Person() {  
        this.age = 0;  
        setInterval(() => {
            // 回调里面的 `this` 变量就指向了期望的那个对象了
            this.age++;
        }, 3000);
    }
    
    var p = new Person();
    

    以上代码可以得到我们所以希望的值,下图可以看到,在setTimeout中的this指向了构造函数新生成的对象,而普通函数指向了全局window对象

    image
    var adder = {
      base : 1,
    
      add : function(a) {
        var f = v => v + this.base;
        return f(a);
      },
    
      addThruCall: function inFun(a) {
        var f = v => v + this.base;
        var b = {
          base : 2
        };
    
        return f.call(b, a);
      }
    };
    
    console.log(adder.add(1));         // 输出 2
    console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3,其内部的this并没有因为call() 而改变,其this值仍然为函数inFun的this值,指向对象adder
    

    bind() & apply() 读者可以自行测试

    对于是否严格模式示例代码(可以复制进控制台进行验证)

    var f = () => {'use strict'; return this};
    var p = () => { return this};
    console.log(1,f() === window);
    console.log(2,f() === p());
    //1 true
    //2 true
    
    image

    以上的箭头函数都是在方法内部,总之都是以非方法的方式使用,如果将箭头函数当做一个方法使用会怎样呢?
    上例子

    var obj = {
      i: 10,
      b: () => console.log(this.i, this),
      c: function() {
        console.log( this.i, this)
      }
    }
    obj.b();  // undefined window{...}
    obj.c();  // 10 Object {...}
    

    相关文章

      网友评论

          本文标题:Vue-06-生命周期-箭头函数

          本文链接:https://www.haomeiwen.com/subject/zufnoftx.html