箭头函数:this的指向问题

关于typescript中函数的定义,有提到过它的定义方式(详见:函数的定义及特性),当时提到typescript中的'=>'不是ES6中的箭头函数的意思。什么是ES6的箭头函数?代码如下:

var fnc = v => v;

第一次看到这个,你肯定心里在想:what ' s this!!!!!!!!!!!!!解释一下,上述代码表现形式就相当于:

var fnc = function(v) {
    return v
}

看到这里,我们对箭头函数也就有了一个初步的印象,箭头函数简化了我们常规函数的书写方式,当然了,它的简化还有以下几种情况:

// 1.包含单个参数传递
var fnc = v => v;

var fnc = function (v) {
    return v
};


// 2.包含多个参数或者不包含参数
var f = () => 5;
// 等同于
var f = function () {
    return 5
};

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function (num1, num2) {
    return num1 + num2;
};


// 3.如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错
var getTempItem = id => ({
    id: id,
    name: "Temp"
});

// 4.变量解构方式
var full = ({
    first,
    last
}) => first + ' ' + last;
// 等同于
function full(person) {
    return person.first + ' ' + person.last;
}

箭头函数的定义我们就介绍到这里,那么我们为什么要使用箭头函数呢?难道仅仅是因为写法相对于比较简单?当然不是了,查看ES6的官方文档,我们可以知道,箭头函数具有以下特性:

  • 函数体内的this对象,指的是定义时所在的对象,而不是使用时所在的对象;
  • 箭头函数不可以当作构造函数,也就是说不可以使用new命令,否则会抛出错误;
  • 不可以使用arguments对象,这个对象在函数体内是不存在的;
  • 不可以使用yield命令,也就是说箭头函数不能用作generator函数;

其它的特性我们暂且放一边,有兴趣的小伙伴可以自己尝试下,我们主要要说的就是this的指向问题。常说箭头函数解决了this的指向问题,那么到底它解决的时什么问题?我们先看代码:

<script>
    function fnc() {
        setTimeout(function () {
            console.log(this.id)    // 这里打印的是1
        }, 1000)
    };
    var id = 1;
    fnc.call({
        id: 2
    });
</script>

很明显,我们看到函数fnc内部包含一个定时函数,1秒后执行,在普通函数的定义中,函数fnc内的this只得就是全局的window对象,所以这里打印的id值是1而不是2。如果我们想打印2呢?常规的解决办法如下:

<script>
    function fnc() {
        var that = this;
        setTimeout(function () {
            console.log(that.id)   // 这里打印值为2
        }, 1000)
    };
    var id = 1;
    fnc.call({
        id: 2
    });
</script>

常规的解决方式,就是定义一个值来改变this的指向,这样虽然可以达到我们的目的,但是很麻烦,而且很容易就忘记了,导致我们在使用this的时候,很难去判断此时的this指向的是谁,但是箭头函数很好的解决了这个问题:函数体内的this对象,指的是定义时所在的对象,而不是使用时所在的对象,如何理解呢?请看代码:

<script>
    function fnc() {
        setTimeout(() => {
            console.log(this.id);   // 这里打印值为2
        }, 1000);
    };
    var id = 1;
    fnc.call({
        id: 2
    });
</script>

这里的箭头函数中的this,指的就是我们在定义fnc的本身。我们再看一个例子来看下箭头函数跟普通函数的区别,箭头函数到底干了啥:

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);

看上面的代码,运行结果是:在3.1秒的延时后,分别打印s1:3和s2:0。根据结果,我们可以很明显的看到,箭头函数内的this指的是绑定定义时所在的作用域(即Timer函数),所以在3.1秒的延时内,timer函数内的s1被自加了三次,所以结果是3,而普通函数内的this是全局的window对象,并没有触及到timer内的s2,所以在3.1秒的延时内,timer函数内的s2不会有任何变化。我们再看一个例子:

function foo() {
  return () => {
    return () => {
      return () => {
        console.log('id:', this.id);
      };
    };
  };
}

var f = foo.call({id: 1});

var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1

我们可以看到,三次打印全部是1,这就说明了上面代码之中,this统统指向了一个对象,就是定义的函数foo,不管你嵌套了多少内层函数,都是指向最外层的foo函数的this,因为你嵌套的内层函数是箭头函数,它们木有自己的this,所以这一点就验证了之前提到的箭头函数的特性:函数体内的this对象,指的是定义时所在的对象,而不是使用时所在的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值