一、创建函数还有另外一种非常简单的语法,箭头函数表达式(也称胖箭头函数)相比函数表达式具有较短的语法并以词法的方式绑定this。
二、箭头函数总是匿名的。
三、箭头函数可以像函数表达式一样使用。
【示例1】动态创建一个函数:
let age = prompt("What is your age?", 18);
let welcome = (age < 18) ?
() => alert('Hello') :
() => alert("Greetings!");
welcome();
四、箭头函数:
- 没有this
- 没有arguments
- 不能使用new进行调用
- 它们也没有super,但目前我们还没有学到它。我们将在类继承一章中学习它。
五、箭头函数是针对那些没有自己的“上下文”,但在当前上下文中起作用的短代码的
创建箭头函数
一行的箭头函数
一、语法:
1、不带花括号:
let func = (...args) => expression
(1)右侧是一个表达式:函数计算表达式并返回其结果。
2、带花括号:
let func = (...args) => { body }
花括号允许我们在函数中编写多个语句,但是我们需要显式地return来返回一些内容。
二、下面的代码创建了一个函数func,它接受参数arg1..argN,然后使用参数对右侧的expression求值并返回其结果。
let func = (arg1, arg2, ...argN) => expression
1、换句话说,它是下面这段代码的更短的版本:
let func = function(arg1, arg2, ...argN) {
return expression;
};
【示例1】具体的例子:
let sum = (a, b) => a + b;
/* 这个箭头函数是下面这个函数的更短的版本:
let sum = function(a, b) {
return a + b;
};
*/
alert( sum(1, 2) ); // 3
1、可以看到(a, b) => a + b表示一个函数接受两个名为a和b的参数。在执行时,它将对表达式a + b求值,并返回计算结果。
(1)如果我们只有一个参数,还可以省略掉参数外的圆括号,使代码更短。
let double = n => n * 2;
// 差不多等同于:let double = function(n) { return n * 2 }
alert( double(3) ); // 6
(2)如果没有参数,括号将是空的(但括号应该保留):
let sayHi = () => alert("Hello!");
sayHi();
多行的箭头函数
一、下面的例子从=>的左侧获取参数,然后使用参数计算右侧表达式的值
let sum = (a, b) => a + b;
alert( sum(1, 2) ); // 3
1、但有时我们需要更复杂一点的东西,比如多行的表达式或语句。
(1)我们应该用花括号括起来。然后使用一个普通的return将需要返回的值进行返回。
【示例1】
let sum = (a, b) => { // 花括号表示开始一个多行函数
let result = a + b;
return result; // 如果我们使用了花括号,那么我们需要一个显式的 “return”
};
alert( sum(1, 2) ); // 3
影响引入箭头函数的因素
更简洁的函数
一、【实例1】
var a = [
"Hydrogen",
"Helium",
"Lithium",
"Beryllium"
];
var a2 = a.map(function(s){ return s.length });
console.log(a2); // logs [ 8, 6, 7, 9 ]
var a3 = a.map( s => s.length );
console.log(a3); // logs [ 8, 6, 7, 9 ]
this的词法
一、箭头函数出现之前,每一个新函数都重新定义了自己的this值(在构造函数中是一个新的对象;在严格模式下是未定义的;在作为“对象方法”调用的函数中指向这个对象;等等)
【实例1】
function Person() {
// 构造函数Person()将`this`定义为自身
this.age = 0;
setInterval(function growUp() {
// 在非严格模式下,growUp()函数将`this`定义为“全局对象”,
// 这与Person()定义的`this`不同,
// 所以下面的语句不会起到预期的效果。
this.age++;
}, 1000);
}
var p = new Person();
【实例2】ECMAScript 3/5里,通过把this的值赋值给一个变量可以修复这个问题
function Person() {
var self = this; // 有的人习惯用`that`而不是`self`,
// 无论你选择哪一种方式,请保持前后代码的一致性
self.age = 0;
setInterval(function growUp() {
// 以下语句可以实现预期的功能
self.age++;
}, 1000);
}
【实例3】创建一个约束函数可以似的this值被正确传递给groupUp()函数。
约束函数:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
【实例4】箭头函数捕捉闭包上下文的this值
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // 这里的`this`正确地指向person对象
}, 1000);
}
var p = new Person();
箭头函数没有 “this”
见this#值-箭头函数:https://www.yuque.com/tqpuuk/yrrefz/gcb2wp
不能对箭头函数进行new操作
一、箭头函数不具有this自然也就意味着另一个限制:箭头函数不能用作构造器(constructor)。不能用new调用它们。
箭头函数 VS bind
一、箭头函数=>和使用.bind(this)调用的常规函数之间有细微的差别:
- .bind(this)创建了一个该函数的“绑定版本”。
- 箭头函数=>没有创建任何绑定。箭头函数只是没有this。this的查找与常规变量的搜索方式完全相同:在外部词法环境中查找。
箭头函数没有 “arguments”
一、箭头函数也没有arguments变量。
二、当我们需要使用当前的this和arguments转发一个调用时,这对装饰器(decorators)来说非常有用。
【示例1】defer(f, ms)获得了一个函数,并返回一个包装器,该包装器将调用延迟ms毫秒: ```javascript function defer(f, ms) { return function() { setTimeout(() => f.apply(this, arguments), ms) }; }
function sayHi(who) { alert(‘Hello, ‘ + who); }
let sayHiDeferred = defer(sayHi, 2000); sayHiDeferred(“John”); // 2 秒后显示:Hello, John
1、不用箭头函数的话,可以这么写:
```javascript
function defer(f, ms) {
return function(...args) {
let ctx = this;
setTimeout(function() {
return f.apply(ctx, args);
}, ms);
};
}
(1)在这里,我们必须创建额外的变量args和ctx,以便setTimeout内部的函数可以获取它们。