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

今天,我们来了解一下生命周期的运行结构;它的核心部分就是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 {...}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,525评论 0 5
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,096评论 0 21
  • 10.29 正在画画的我因为你的一句,最近很冷漠,停下了画笔, 纠结了很久,打下很多话又删掉,最后只留下一个表情和...
    发清genius阅读 346评论 0 0
  • 这样的服饰很少见了,不知道是那个民族的... 我还真以为外国人什么也不怕呢... 李易峰:心中的男神,你这样不好吧...
    朦胧月色阅读 163评论 0 0