好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ES6+ 箭头函数

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 展开运算来 获取 当前参数的数组。

查看更多关于ES6+ 箭头函数的详细内容...

  阅读:52次

上一篇

下一篇

第1节:ES6+ 简介    第2节:ES6 环境配置    第3节:ES6+ let    第4节:ES6+ const    第5节:ES6+ 展开语法    第6节:ES6+ 剩余参数    第7节:ES6+ 解构赋值    第8节:ES6+ 模版字符串    第9节:ES6+ 箭头函数    第10节:ES6+ 数值扩展    第11节:ES6+ isFinite()&isNaN()    第12节:ES6+ Number 对象的方法    第13节:ES6+ Math 对象的扩展    第14节:ES6+ includes()    第15节:ES6+ 字符串的扩展    第16节:ES6+ startsWith()    第17节:ES6+ endsWith()    第18节:ES6+ repeat()    第19节:ES6+ padStart()    第20节:ES6+ padEnd()    第21节:ES6+ trim()    第22节:ES6+ Array.from()    第23节:ES6+ of()    第24节:ES6+ find()和findIndex()    第25节:ES6+ copyWithin()    第26节:ES6+ fill()    第27节:ES6+ isArray()    第28节:ES6+ 对象的扩展    第29节:ES6+ flat()    第30节:ES6+ 可选链操作符    第31节:ES6+ Object.is()    第32节:ES6+ Object.assign()    第33节:ES6+ Object.keys()    第34节:ES6+ Object.values()    第35节:ES6+ Object.entries()    第36节:ES6+ 数据结构扩展    第37节:ES6+ Set    第38节:ES6+ WeakSet    第39节:ES6+ Map    第40节:ES6+ WeakMap    第41节:ES6+ Symbol    第42节:ES6+ for...of    第43节:ES6+ 迭代协议    第44节:ES6+ 实现一个简版的 Promise    第45节:ES6+ Promise 基础    第46节:ES6+ Promise 进阶    第47节:ES6+ Generator 基础    第48节:ES6+ Generator 函数应用    第49节:ES6+ async/await    第50节:ES6+ Class 前置知识    第51节:ES6+ Class    第52节:ES6+ Proxy    第53节:ES6+ Reflect(一)    第54节:ES6+ Reflect(二)    第55节:ES6+ 模块化(一)    第56节:ES6+ 模块化(二)    第57节:ES6实战1-实现Vue3 reactive 源码    第58节:ES6实战2-实现 Vue3 effect 源码    第59节:ES6 实战2-封装请求    第60节:ES6+ 实战3-代码整洁之道    第61节:ES6 Map原理分析    第62节:ES6module语法加载importexport    第63节:ES6的循环与可迭代对象示例详解