关于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对象,指的是定义时所在的对象,而不是使用时所在的对象。