ES6系列--箭头函数全解析
栏目: JavaScript · 发布时间: 5年前
内容简介:在 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 */ 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Go Web编程
谢孟军 / 电子工业出版社 / 2013-6-1 / 65.00元
《Go Web编程》介绍如何用Go语言进行Web应用的开发,将Go语言的特性与Web开发实战组合到一起,帮读者成功地构建跨平台的应用程序,节省Go语言开发Web的宝贵时间。有了这些针对真实问题的解决方案放在手边,大多数编程难题都会迎刃而解。 在《Go Web编程》中,读者可以更加方便地找到各种编程问题的解决方案,内容涵盖文本处理、表单处理、Session管理、数据库交互、加/解密、国际化和标......一起来看看 《Go Web编程》 这本书的介绍吧!
图片转BASE64编码
在线图片转Base64编码工具
XML 在线格式化
在线 XML 格式化压缩工具