ES6+ 箭头 函数
1. 前言
在编程中使用最多的就是 函数 ,在 ES5 中是用 function 关键字来定义 函数 的,由于历史原因 function 定义的 函数 存在一些问题,如 this 的指向、 函数 参数 arguments 等。
ES6 规定了可以使用 “箭头” => 来定义 一个 函数 ,语法更加简洁。它没有自己的 this 、 arguments 、 super 或 new.target ,箭头 函数 表达式更适用于那些本来需要匿名 函数 的地方,但它不能用作构造 函数 。
2. this 指向
在 JavaScript 中,要说让人最头疼的知识点中,this 绑定绝对算 一个 ,这是因为 this 的绑定 ‘难以捉摸’,出错的时候还往往不知道为什么,相当反逻辑。下面我们来看 一个 示例:
var title = "全局 标题 " ; var imooc = { title : "网 ES6 Wiki" , getTitle : function ( ) { console . log ( this . title ) ; } } ; imooc . getTitle ( ) ; // 网 ES6 Wiki var bar = imooc . getTitle ; bar ( ) ; // 全局 标题
通过上面的小例子的打印结果可以看出 this 的问题,说明 this 的指向是不固定的。
这里简单说明一下 this 的指向, this 指向的是 调用 它的对象 。例子中的 this 是在 getTitle 的 函数 中的,执行 imooc.getTitle() 这个 方法 时, 调用 它的对象是 imooc ,所以 this 的指向是 imooc 。
之后把 imooc.getTitle 方法 赋给 bar ,这里要注意的是,只是把地址赋值给了 bar ,并没有 调用 。 而 bar 是全局对象 window 下的 方法 ,所以在执行 bar 方法 时, 调用 它的是 Window 对象,所以这里打印的结果是 window 下的 title——“全局 标题 ”。
TIPS: 上面的示例只是简单的 this 指向问题,还有很多更加复杂的,在面试中经常会被问到,所以还不清楚的同学可以去研究一下 this 的问题。
ES6 为了规避这样的问题,提出了箭头 函数 的 解决方 案,在箭头 函数 中没有自己的 this 指向,所有的 this 指向都指向它的上一层 this ,这样规定就比较容易理解了。下面看使用箭头 函数 下的 this 指向:
var title = "全局 标题 " ; var imooc = { title : "网 ES6 Wiki" , getTitle : ( ) => { console . log ( this . title ) ; } } ; imooc . getTitle ( ) ; // 全局 标题 var bar = imooc . getTitle ; bar ( ) ; // 全局 标题
上面的打印结果可以看出来,所有的 this 指向都指向了 window 对象下的 title,本身的 imooc 对象下没有了 this ,它的上一层就是 window。
3. 语法详解
3.1 基本语法
箭头 函数 的使用很简单,使用 => 来定义 函数 ,下面对比 ES5 和 ES6 定义 函数 的对比。
// ES5 var sum = function ( ) { // t odo } ; // ES6 var sum = ( ) => { // t odo }
3.2 有返回值
当 函数 体内有返回值时,ES6 的箭头 函数 可以省略大括号:
var sum = ( num1 , num2 ) => num1 + num2 ;
当传递的参数只有 一个 时,圆括号也可以省略:
var sum = num => num + ;
下面看个使用 map 求和的例子:
// ES5 [ , , ] . map ( function ( x ) { return x * x ; } ) ; // 等同于ES6 [ , , ] . map ( x => x * x ) ;
对比 ES5 可以看出箭头 函数 的简洁表达,更加准确明了。
3.3 返回值是对象
如果 函数 体返回对象字面量表达式,可以省略大括号,使用圆括号的形式包裹对象。
var getimooc = ( ) => ( { a : , b : } ) ; getimooc ( ) // {a: 1, b: 2}
3.4 默 认参数
在定义 函数 时,往往需要给参数 添加 默 认值,ES6 中可以直接在圆括号中进行赋值。
var sum = ( num1 , num2 = ) => num1 + num2 ; console . log ( sum ( ) ) // 3
在使用 function 关键字定义 函数 时,如果要给传递的参数设置 默 认参数,只能在 函数 体内进行赋值操作,ES6 简化了 默 认参数的赋值过程。
3.5 剩余参数
函数 在接收不定参数时,可以使用剩余运算符把 调用 函数 时传入的参数聚拢起来成为 一个 参数数组(类似 function 中的 arguments 对象,但 arguments 不是数组,不能直接使用)。
下面是剩余参数的例子:
var fun = ( p ara m1 , p ara m2 , ... rest ) => { console . log ( p ara m1 ) console . log ( p ara m2 ) console . log ( rest ) } ; fun ( , , , , ) ; // 1 // 2 // [3, 4, 5]
4. 没有 this
箭头 函数 不会创建自己的 this ,它只会从自己的作用域链的上一层继承 this , setTimeout 会改变 this 的指向,看下面的示例:
// 在构造 函数 中 function Person ( ) { this . age = ; setTimeout ( function ( ) { console . log ( this ) ; } , ) } var p = new Person ( ) ; // Window: {parent: Window, opener: null, top: Window, length: 0, frames: Window, …} function Person ( ) { this . age = ; setTimeout ( ( ) => { console . log ( this ) ; } , ) ; } var p = new Person ( ) ; // Person: {age: 0}
第 一个 例子中的 setTimeout 的回调 函数 使用 function 来定义的,从打印的结果可以看出 this 的指向是 window 对象也就是全局作用域。而第二个示例中 setTimeout 的回调 函数 使用箭头 函数 来定义,打印的结果可以看到, this 的指向是 Person .
一个 实例: 定义为 一个 构造 函数 Person ,在 函数 中定义 一个 imooc 对象,使用 function 关键字和箭头 函数 的方式给 imooc 上 添加 getValue 方法 ,最后返回 imooc 对象,这时候我们来观察 getValue 内的 this 指向问题。
function Person ( ) { var imooc = { } ; imooc . num = ; imooc . getValue = ( ) => { console . log ( this ) } return imooc ; } var p = new Person ( ) ; p . getValue ( ) // person {}
上面的示例中,构造 函数 中 imooc.getValue 方法 使用的是箭头 函数 定义的,所以 getValue 方法 不会有 this 的指向,它会根据作用域链向上查找到 Person 构造 函数 ,所以这里的 this 的指向是 Person 。
function Person ( ) { var imooc = { } ; imooc . num = ; imooc . getValue = function ( ) { console . log ( this ) } return imooc ; } var p = new Person ( ) ; p . getValue ( ) // {num: 10, getValue: ?} this指向的是 p 的返回值
上面的示例中,构造 函数 中 imooc.getValue 方法 是使用 function 定义的,所以 getValue 中 this 的指向是动态的,指向 调用 它的那个对象。在 new Person() 时,会返回 imooc 对象赋给实例 ,在使用 p 去 调用 getValue() 时 this 的指向就是 p 实例。
总结: 箭头 函数 的 this 永远指向的是父级作用域。
5. 不绑定 arguments
箭头 函数 不绑定 Arguments 对象。所以在使用箭头 函数 定义的 函数 体内是取不到 arguments 的。
var fun = function ( ) { console . log ( arguments ) } ; fun ( , , ) ; // Arguments(3) [1, 2, 3, callee: ?, Symbol(Symbol.i tera tor): ?] var fun = ( ) => { console . log ( arguments ) } ; fun ( , , ) ; // Uncaught ReferenceError: arguments is not defined
上面的示例中,对比两种定义 函数 的 方法 可以明显的看出,在箭头 函数 中去取 arguments 时会报引用 错误 ,没有定义的 arguments 。
arguments 的主要作用是 获取 所有 调用 函数 时所需要传入的参数,在箭头 函数 中使用剩余参数 ...args ,在 函数 内可以直接使用。
function foo ( ... args ) { console . log ( args ) } foo ( ) ; // [1] foo ( , , ) ; // [1, 2, 3]
6. 其他注意点
6.1 不能用作构造器
箭头 函数 不能用作构造器,和 new 一起用会抛出 错误 。
var Foo = ( ) => { } ; var foo = new Foo ( ) ; // TypeError: Foo is not a constructor
6.2 没有 prototype 属性
箭头 函数 没有 prototype 属性 。
var Foo = ( ) => { } ; console . log ( Foo . prototype ) ; // undefined
6.3 不能使用 yield 命令
yield 关键字通常不能在箭头 函数 中使用,因此箭头 函数 不能用作 Generator 函数 。
7. 小结
本节主要讲解了 ES6 的箭头 函数 ,总结了以下几点:
更短的 函数 ,优雅简洁; 箭头 函数 不会创建自己的 this,它只会从自己的作用域链的上一层继承 this; 不能绑定 arguments, 只能使用 ...args 展开运算来 获取 当前参数的数组。
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did91766