尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

深入 JS Tips 第 14 期:ES6 箭头函数(Fat Arrow Functions)的语法精简与词法 this 绑定

深入 JS Tips 第 14 期:ES6 箭头函数(Fat Arrow Functions)的语法精简与词法 this 绑定 教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载本篇文章基于 jstips 仓库 第 14 期英文原文及其 中文译本展开系统讲解 ES6 箭头函数的两大核心能力以更少的代码行完成函数书写以及从词法上下文捕获this。读完本文你将掌握箭头函数的完整语法形态、在数组高阶函数中的实战写法并理解为什么在定时器、回调函数等场景下它比function关键字更安全。从名字说起为什么叫 Fat Arrow箭头函数fat arrow functions是 ES6 引入的新特性名字来源于它的语法符号——相比普通的瘦箭头-它是一个胖箭头。许多从 Haskell 等函数式语言转来的程序员会把它对应到lambda 表达式或匿名函数箭头函数没有描述性的函数名因此它本质上是匿名函数的一种形式。在 jstips 仓库的 POST_TEMPLATE.md 中可以看到每期 tip 通过 front matter 记录标题、期号、作者等信息第 14 期由 pklinger 撰写其tip-tldr一句话概括正是用更少的行写更多的代码。两大核心收益语法Syntax更少的代码行fewer LOC不再需要一遍又一遍地敲function关键字语义Semantics从周围上下文捕获this关键字而不是在调用时动态决定。这两点分别对应了箭头函数写起来更短和用起来更安全两个层面的价值下文逐一展开。语法速览与实操示例箭头函数的一般语法非常直观// 箭头函数的一般语法 param expression // 也可以用括号包裹参数 // 多参数时括号是必需的 (param1 [, param2]) expression原文档用一段Array.prototype.map对比了传统函数与箭头函数的写法差异二者完成完全相同的工作// 使用 function 关键字 var arr [5,3,2,9,1]; var arrFunc arr.map(function(x) { return x * x; }); console.log(arr); // 使用箭头函数 var arr [5,3,2,9,1]; var arrFunc arr.map((x) x*x); console.log(arr);可以看到箭头函数省去了function关键字、参数括号单参数时可省略以及return关键字单表达式写法会隐式返回计算结果。原文档作者特别给出了一个实用建议始终为参数写括号。因为当参数多于一个时括号是必需的如(x,y) xy养成总写括号的习惯可以避免在不同使用场景下忘记加括号当然x x*x这样的单参数写法同样合法。至此这些还只是语法层面的精简带来的收益是更少的代码行和更好的可读性。从仓库中其他期数的代码可以看到这种精简在数组高阶函数中体现得尤为充分。例如 第 37 期数组去重 用一行箭头函数完成去重var deduped [ 1, 1, a, a ].filter( (el, i, arr) arr.indexOf(el) i);第 26 期字符串列表的过滤与排序 更是直接展示了箭头函数对回调式代码的改写效果ES6 版本比传统写法简洁得多const filteredAndSortedKeywords keywords .filter((keyword, index) keywords.lastIndexOf(keyword) index) .sort((a, b) a b ? -1 : 1);类似的用法还出现在 第 33 期一行创建 0..N 范围数组Array.from(new Array(N),(val,index)index)、第 41 期数组平均值与中位数reduce与sort中的(previous, current) ...、(a, b) a - b、第 58 期函数式循环中的 break/continueconst isBiggerThan10 numb numb 10;以及 第 65 期tapping 快速调试tap(3, x x 2)等期数中。词法绑定this四个计数器对比语法精简只是箭头函数的一半价值另一半是this上下文的处理。这是另一个使用箭头函数的好理由。在传统函数中this的值取决于函数如何被调用。当函数作为回调例如传给setInterval执行时this往往不再指向你期望的对象。为此开发者曾经不得不使用.bind(this)或者var that this之类的变通手段。箭头函数则完全消除了这个负担——它没有自己的this而是从词法上的外层作用域继承this值。原文档用一个经典的计数器示例原文配有可运行的演示对比了四种写法完整代码如下// 全局定义 this.i this.i 100; var counterA new CounterA(); var counterB new CounterB(); var counterC new CounterC(); var counterD new CounterD(); // 不好的例子 function CounterA() { // CounterA 的 this 实例!! 调用时被忽略了 this.i 0; setInterval(function () { // this 指向全局对象而不是 CounterA 的 this // 因此从 100 开始计数而不是 0本地的 this.i this.i; document.getElementById(counterA).innerHTML this.i; }, 500); } // 手动绑定 that this function CounterB() { this.i 0; var that this; setInterval(function() { that.i; document.getElementById(counterB).innerHTML that.i; }, 500); } // 使用 .bind(this) function CounterC() { this.i 0; setInterval(function() { this.i; document.getElementById(counterC).innerHTML this.i; }.bind(this), 500); } // 箭头函数 function CounterD() { this.i 0; setInterval(() { this.i; document.getElementById(counterD).innerHTML this.i; }, 500); }逐项拆解这段代码CounterA错误示范setInterval的回调是普通函数调用时其this指向全局对象在浏览器中即window因此this.i操作的是全局的this.i 100计数器从 100 而非 0 开始结果完全错误CounterBthat this 变通在构造函数内先用var that this保存实例引用回调中改用that.i通过闭包绕过了this丢失问题CounterC.bind(this) 显式绑定在回调函数上调用.bind(this)将this永久绑定为当前实例同样可行但多了一次方法调用、代码也略显笨重CounterD箭头函数回调写成() { this.i; ... }箭头函数不绑定自己的this直接继承CounterD构造函数的词法作用域因此this天然就是当前实例从 0 开始正确计数既不需要that变量也不需要.bind()。这正是原文档所说的语义semantics层面的收益你不需要再担心.bind(this)也不用再设置that this因为箭头函数从词法外围拾取this上下文。需要说明的是this的词法继承也意味着箭头函数不适合需要动态this的场景——例如作为对象方法、需要访问arguments对象、或者需要用new调用的构造函数时箭头函数没有自己的arguments也没有prototype不能用作构造函数。从源码结构可以推断仓库中箭头函数的大量应用都集中在数组高阶函数map/filter/reduce/sort和纯函数式工具如 第 70 期对象属性的 pick/reject 中keys.map(k k in obj ? {[k]: obj[k]} : {})上这些场景恰好与箭头函数的特性天然契合。箭头函数的其他语法形态原文档在结尾提示更多语法选项可进一步查阅结合仓库中其他期数的代码箭头函数还有几种值得掌握的形态参数默认值与箭头函数组合。第 12 期ES6 函数中的伪必选参数 展示了箭头函数可以像普通函数一样使用默认参数const getSum (a _err(a is not defined), b _err(b is not defined)) a b多行函数体需要显式return。当箭头函数体是语句块花括号包裹时不再有隐式返回必须写return这一点在仓库各期代码的reduce、sort多行回调中反复出现见 第 41 期。与解构、展开运算符等 ES6 特性协同。第 70 期 中map(k Object.assign({}, {[k]: obj[k]}))展示了箭头函数与计算属性名、Object.assign的组合使用。使用建议与小结综合原文档与仓库中的实战代码可以总结出以下实践建议优先用括号包裹参数单参数虽可省略括号但多参数时括号必需统一写法可避免遗漏单表达式省略return简洁的表达式体写法如x x*x能最大化代码密度回调场景放心用箭头函数定时器、事件监听、forEach/map/filter/reduce/sort等回调中箭头函数通过词法捕获this避免that this和.bind(this)等变通手段需要动态this时回归普通函数对象方法、构造函数、依赖arguments的函数不应使用箭头函数。jstips 仓库中这一期 tip 提供了 英文版、简体中文版、繁体中文版 与 西班牙语版 等多语言版本而其后的多期 tip 也持续以箭头函数作为示例语法——从 数组去重 到 过滤排序可以看到箭头函数已经成为这套 JavaScript 技巧集合中最常用的基础语法之一。掌握它的语法与this语义是阅读和理解仓库内绝大多数 ES6 期数代码的前提。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐jstips 第 14 期精讲ES6 箭头函数Fat Arrow Functions的语法精简与 this 词法绑定实战jstips 第 14 期精讲ES6 箭头函数Fat Arrow Functions的语法精简与 this 词法绑定实战 本篇技术指南基于开源项目 jst教程jstips 实战ES6 箭头函数Fat Arrow Functions语法与词法 this 绑定完全指南jstips 实战ES6 箭头函数Fat Arrow Functions语法与词法 this 绑定完全指南 本文是 jstips 项目 Tip 14 西教程ES6函数箭头函数与this绑定gh_mirrors/es/es6features项目解析ES6函数箭头函数与this绑定gh_mirrors/es/es6features项目解析 你是否还在为JavaScript中的this绑定问题头疼是否经常创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表