ES6系列--箭头函数全解析
栏目: JavaScript · 发布时间: 6年前
内容简介:在 ES6 中,箭头函数是其中最有趣也最受欢迎的新增特性。顾名思义,箭头函数是一种使用 (=>) 定义函数的新语法,它与传统的 ES5 函数有些许不同。这是一个用 ES5 语法编写的函数:有了 ES6 的箭头函数后,我们可以用箭头函数这样表示:
在 ES6 中,箭头函数是其中最有趣也最受欢迎的新增特性。顾名思义,箭头函数是一种使用 (=>) 定义函数的新语法,它与传统的 ES5 函数有些许不同。
这是一个用 ES5 语法编写的函数:
function addTen(num){
return num + 10;
}
timesTwo(5); // 15
复制代码
有了 ES6 的箭头函数后,我们可以用箭头函数这样表示:
var addTen = num => num + 10 addTen(5); // 15 复制代码
箭头函数的写法短的多!由于隐式返回,我们可以省略花括号和 return 语句。
与常规 ES5 函数相比,了解箭头函数的行为方式非常重要。
箭头函数的特点
更短的语法
基础语法如下:
(参数)=> { statements }
复制代码
接下来,拆解一下箭头函数的各种书写形式:
当没有参数时,使用一个圆括号代表参数部分
let f = ()=> 5; f(); // 5 复制代码
当只有一个参数时,可以省略圆括号。
let f = num => num + 5; f(10); // 15 复制代码
当有多个参数时,在圆括号内定义多个参数用逗号分隔。
let f = (a,b) => a + b; f(1,2); // 3 复制代码
当箭头函数的代码块部分多余一条语句,就需要使用大括号括起来,并且使用 return 语句。
// 没有大括号,默认返回表达式结果
let f1 = (a,b) => a + b
f1(1,2) // 3
// 有大括号,无return语句,没有返回值
let f2 = (a,b) => {a + b}
f2(1,2) // undefined
// 有大括号,有return语句,返回结果
let f3 = (a,b) => {return a + b}
f3(1,2) // 3
复制代码
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
//报错
let f1 = num => {num:num}
//不报错
let f2 = num => ({num:num})
复制代码
不能通过 new 关键字调用
箭头函数没有[[Construct]]方法,所以不能被用作构造函数。
let F = ()=>{};
// 报错 TypeError: F is not a constructor
let f = new F();
复制代码
没有原型
由于不可以通过 new 关键字调用,因而没有构建原型的需求,所以箭头函数不存在 prototype 这个属性。
let F = ()=>{};
console.log(F.prototype) // undefined
复制代码
没有 this 绑定
在 ES5 函数表达式中,this关键字根据调用它的上下文绑定到不同的值。但是,对于箭头函数,它this是词法绑定的。
箭头函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。
window.name = 'window_name'
let obj = {
name:'obj_name',
f1:function(){
return this.name
},
f2:()=>{
return this.name
}
}
obj.f1(); // obj_name
obj.f2(); // window_name
复制代码
上面代码中,obj.f1 是一个普通函数,obj.f2 是一个箭头函数。
当调用 obj.f1() 时,obj.f1 中 this 的指向的是 f1 函数的调用者,也就是 obj,所以返回 'obj_name'。
当调用 obj.f2() 时,由于 obj.f2 是箭头函数,所以 obj.f2 中this 指向的是定义 obj.f2 时的 this 指向,也就是 window,所以返回 'window_name'。
对箭头函数使用 call、apply、bind 时,不会改变 this 指向,只会传入参数
window.name = 'window_name';
let f1 = function(){return this.name}
let f2 = ()=> this.name
let obj = {name:'obj_name'}
f1.call(obj) // obj_name
f2.call(obj) // window_name
f1.apply(obj) // obj_name
f2.apply(obj) // window_name
f1.bind(obj)() // obj_name
f2.bind(obj)() // window_name
复制代码
上面代码中,声明了普通函数 f1,箭头函数 f2。
普通函数的 this 指向是动态可变的,所以在对 f1 使用 call、apply、bind 时,f1 内部的 this 指向会发生改变。
箭头函数的 this 指向在其定义时就已确定,永远不会发生改变,所以在对 f2 使用 call、apply、bind 时,会忽略传入的上下文参数。
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this
没有 arguments、super、new.target
箭头函数中是没有 arguments、super、new.target 的绑定,这些值由外围最近一层非箭头函数决定。
以 arguments 为例,看如下代码:
let f = ()=>console.log(arguments); //报错 f(); // arguments is not defined 复制代码
由于在全局环境下,定义箭头函数 f,对于 f 来说,无法获取到外围非箭头函数的 arguments 值,所以此处报错。
再看一个例子:
function fn(){
let f = ()=> console.log(arguments)
f();
}
fn(1,2,3) // [1,2,3]
复制代码
上面的代码,箭头函数 f 内部的 arguments,其实是函数 fn 的 arguments 变量。
若想在箭头函数中获取不定长度的参数列表,可以使用 ES6 中的 rest 参数解决:
let f = (...args)=>console.log(args) f(1,2,3,4,5) // [1,2,3,4,5] 复制代码
不能用作 Generator 函数
在箭头函数中,不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
关于箭头函数的题目
在面试中关于箭头函数的考察,主要集中在 arguments 关键字的指向和箭头函数的this指向上,下面几道题目,供大家参考一下。
先上题目,由浅入深,答案后面给出。
题目1
function foo(n) {
var f = () => arguments[0] + n;
return f();
}
let res = foo(2);
console.log(res); // 4
复制代码
题目2
function A() {
this.foo = 1
}
A.prototype.bar = () => console.log(this.foo)
let a = new A()
a.bar()
复制代码
题目3
let res = (function() {
return [
(() => this.x).bind({ x: 'inner' })()
];
}).call({ x: 'outer' });
console.log(res)
复制代码
题目4
window.name = 'window_name';
let obj1 = {
name:'obj1_name',
print1:function(){
console.log(this.name)
},
print2:()=>console.log(this.name),
print3:function(){
return function(){
console.log(this.name)
}
},
print4:function(){
return ()=>console.log(this.name)
}
}
let obj2 = {name:'obj2_name'}
obj1.print1()
obj1.print1.call(obj2)
obj1.print2()
obj1.print2.call(obj2)
obj1.print3()()
obj1.print3().call(obj2)
obj1.print3.call(obj2)()
obj1.print4()()
obj1.print4().call(obj2)
obj1.print4.call(obj2)()
复制代码
答案如下:
// 题目1:4 // 题目2:undefined // 题目3:["outer"] /** * 题目4: * obj1.print1() --obj1_name * obj1.print1.call(obj2) --obj2_name * obj1.print2() --window_name * obj1.print2.call(obj2) --window_name * obj1.print3()() --window_name * obj1.print3().call(obj2) --obj2_name * obj1.print3.call(obj2)() --window_name * obj1.print4()() --obj1_name * obj1.print4().call(obj2) --obj1_name * obj1.print4.call(obj2)() --obj2_name */ 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Python
Paul Barry / O'Reilly Media / 2010-11-30 / USD 49.99
Are you keen to add Python to your programming skills? Learn quickly and have some fun at the same time with Head First Python. This book takes you beyond typical how-to manuals with engaging images, ......一起来看看 《Head First Python》 这本书的介绍吧!