javaScript的箭头函数详解


理解使用普通函数基于 this 编程带来的令人沮丧的问题是很重要的,因为这是新的 ES6 箭头函数 => 特性引入的主要动因。

来展示一下与普通函数相比箭头函数是什么样子:

function foo(x,y) { 
 return x + y; 

// 对比
var foo = (x,y) => x + y;
箭头函数定义包括一个参数列表(零个或多个参数,如果参数个数不是一个的话要用 ( .. )包围起来),然后是标识 =>,函数体放在最后。

只有在函数体的表达式个数多于 1 个,或者函数体包含非表达式语句的时候才需要用 { .. }包围。如果只有一个表达式,并且省略了包围的 { .. } 的话,则意味着表达式前面有一个隐含的 return,就像前面代码中展示的那样。

这里列出了几种不同形式的箭头函数:

var f1 = () => 12; 
var f2 = x => x * 2; 
var f3 = (x,y) => { 
 var z = x * 2 + y; 
 y++; 
 x *= 3; 
 return (x + y + z) / 2; 
};
箭头函数总是函数表达式;并不存在箭头函数声明。我们还应清楚箭头函数是匿名函数表达式——它们没有用于递归或者事件绑定 / 解绑定的命名引用

注意:箭头函数支持普通函数参数的所有功能,包括默认值、解构、rest 参数,等等。

可以说这里关于箭头函数的讨论中几乎所有的例子都是简短的单句工具,比如作为回调函数传递给各种工具的那些。举例来说:

var a = [1,2,3,4,5]; 
a = a.map( v => v * 2 ); 
console.log( a ); // [2,4,6,8,10]
但是这里我要提醒你,使用箭头函数语法替代其他普通的多行函数,特别是那些通常会被自然表达为函数声明的情况,是不合理的。=> 箭头函数转变带来的可读性提升与被转化函数的长度负相关。这个函数越长,=> 带来的好处就越小;函数越短,=> 带来的好处就越大。

不只是更短的语法,而是 this

对 => 的关注多数都在于从代码中去掉 function、return 和 { .. } 节省了那些宝贵的盘输入。但是,目前为止我们省略了一个重要的细节。这一节开头提到 => 函数与 this 绑定行为紧密相关。实际上,=> 箭头函数的主要设计目的就是以特定的方式改变 this 的行为特性,解决 this 相关编码的一个特殊而又常见的痛点。

var controller = { 
 makeRequest: function(..){ 
 var self = this; 
 btn.addEventListener( "click", function(){ 
 // .. 
 self.makeRequest(..); 
 }, false ); 
 } 
};
我们使用了 var self = this 这一 hack,然后引用 self.makeRequest(..),因为在我们传入 addEventListener(..) 的回调函数内部,this 绑定和 makeRequest(..) 本身的 this 绑定是不同的。换句话说,因为 this 绑定是动态的,我们通过变量 self 依赖于词法作用域的可预测性。

这里我们终于可以看到 => 箭头函数的主要设计特性了。在箭头函数内部,this 绑定不是动态的,而是词法的。在前面的代码中,如果使用箭头函数作为回调,this 则如我们所愿是可预测的。

var controller = { 
 makeRequest: function(..){ 
 btn.addEventListener( "click", () => { 
 // .. 
 this.makeRequest(..); 
 }, false ); 
 } 
}
前面代码的箭头函数回调中的词法 this 现在与封装的函数 makeRequest(..) 指向同样的值。换句话说,=> 是 var self = this 的词法替代形式。

在通常需要 var self = this(或者换种形式,如函数 .bind(this) 调用)的时候,基于运行原则相同,可以把 => 箭头函数作为一个很好的替代

但是有问题:假使用 => 替代 var self = this 或者 .bind(this) 的情况有所帮助,那么猜一下如果在一个支持 this 的函数中使用 =>,而这个函数不需要 var self = this, 这就会把事情搞乱。

var controller = { 
 makeRequest: (..) => { 
 // .. 
 this.helper(..); 
 }, 
 helper: (..) => { 
 // .. 
 } 
}; 
controller.makeRequest(..);
尽管我们以 controller.makeRequest(..) 的形式调用,this.helper 引用还是会失败,因为这里的 this 并不像平常一样指向 controller。那么它指向哪里呢?它是从包围的作用域词法继承而来的 this。在前面的代码中也就是全局作用域,其中 this 指向那个全局对象。

除了词法 this,箭头函数还有词法 arguments——它们没有自己的 arguments 数组,而是继承自父层—

所以现在我们可以给出一组更详细的 => 适用时机的规则。
 1、如果你有一个简短单句在线函数表达式,其中唯一的语句是 return 某个计算出的值 且这个函数内部没有 this 引用,且没有自身引用(递归、事件绑定 / 解绑定),且不会要求函数执行这些,那么可以安全地把它重构为 => 箭头函数。

2、 如果你有一个内层函数表达式,依赖于在包含它的函数中调用 var self = this hack 或者 .bind(this) 来确保适当的 this 绑定,那么这个内层函数表达式应该可以安全地转换为 => 箭头函数。

3、 如果你的内层函数表达式依赖于封装函数中某种像 var args = Array.prototype.slice.call(arguments) 来保证 arguments 的词法复制,那么这个内层函数应该可以安全地转换为 => 箭头函数。


4、 所有的其他情况——函数声明、较长的多语句函数表达式、需要词法名称标识符(递归等)的函数,以及任何不符合以上几点特征的函数——一般都应该避免 => 函数语法。

底线:=> 是关于 this、arguments 和 super 的词法绑定。这个 ES6 的特性设计用来修正一些常见的问题,而不是 bug、巧合或者错误。

不要相信那些宣传所说的 => 主要甚至绝大多数关注点在于少打字。不管是少打字还是多打字,你应该精确了解自己输入的每个字符的目的所在。

这里用一个可视化的决策图来展示如何 / 为什么采用箭头函数:

 
————————————————
版权声明:本文为CSDN博主「cpc q:2531249502」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43059674/article/details/87603235

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值