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编程

Go Web编程

谢孟军 / 电子工业出版社 / 2013-6-1 / 65.00元

《Go Web编程》介绍如何用Go语言进行Web应用的开发,将Go语言的特性与Web开发实战组合到一起,帮读者成功地构建跨平台的应用程序,节省Go语言开发Web的宝贵时间。有了这些针对真实问题的解决方案放在手边,大多数编程难题都会迎刃而解。 在《Go Web编程》中,读者可以更加方便地找到各种编程问题的解决方案,内容涵盖文本处理、表单处理、Session管理、数据库交互、加/解密、国际化和标......一起来看看 《Go Web编程》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具