首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ECMAScript 6 中的函数增强-2

ECMAScript 6 中的函数增强-2

展开运算符展开运算符(Spread operator)在某些方面与剩余参数的概念正好相反。剩余参数将会收集传入某个给定调用的一些可选值,展开运算符获取一个值数组并 “展开”        它们,基本上讲,就是解构它们以用作被调用的函数的各个参数。
展开运算符的最简单用例是将各个元素串联到一个数组中:
清单 6. 使用展开运算符进行串联
let arr1 = [0, 1, 2];
let arr2 = [...arr1, 3, 4, 5];
console.log(arr2); // prints 0,1,2,3,4,5




如果没有展开运算符语法,您需要提取第一个数组中的每个元素并附加到第二个数组,然后才添加剩余元素。
也可以在函数调用中使用展开运算符;事实上,这是您最有可能使用它的地方:
清单 7. 函数调用中的展开运算符
function printPerson(first, last, age) {
  console.log(first, last age);
}
let args = ["Ted", "Neward", 45];
printPerson(...args);




请注意,不同于剩余参数,展开运算符是在调用点上使用,而不是在函数定义中使用。
函数语法和语义除了参数更改之外,ECMAScript 6 在函数语法和语义上也进行了重大改动。本节将介绍最重要的更新。只需记住,JavaScript        程序中的原始语法仍然可行。如果您最初感觉这种新语法不方便或不够直观,您可以逐步适应它的使用。
箭头函数随着 Scala 和 F# 等新函数语言被大众接受,旧语言已开始采用它们的一些优秀功能。其中一项功能是箭头函数语法,这是一种用于创建函数字面量的速记符号。从 ECMAScript 6        开始,您可以使用所谓的粗箭头(与细箭头相对)创建函数字面量,就像这样:
清单 8. 创建函数字面量的箭头语法
let names = ["Ted","Jenni","Athen"];
names.forEach((n) => console.log(n));




如果尝试过使用 C#、Java 8、Scala 或 F#        进行函数编程,您可能非常熟悉这种语法。即使您不熟悉它,箭头函数也很容易理解:箭头前的括号将参数捕获到函数主体,箭头本身表示函数主题的开头。如果主体仅包含一条语句或表达式,则不需要使用花括号。如果主体包含多条语句或表达式,那么可以通过在箭头后输入花括号来表示它们:
清单 9. 表示多条语句或表达式
let names = ["Ted","Jenni","Athen"];
names.forEach((n) => {
  console.log(n)
});




如果只有一个参数,您可以选择完全省略括号,如下所示。(就个人而言,我甚至在只有一个参数时也使用括号,但这只是仁者见仁,智者见智的的审美偏好。)
清单 10. 单个参数
names.forEach(n => console.log(n));




箭头函数不能直接取代函数关键字。一般而言,您应该继续使用 function          定义方法(即与一个对象实例关联的函数)。为与对象无关的场景保留箭头函数,比如 Array.forEach 或 Array.map          调用的主体。因为箭头函数对待 this 的方式与普通函数不同,所以在方法定义中使用它们可能导致意料之外的结果。

另请注意,如果箭头函数的主体是只有一个值的单个表达式,则无需显式返回,而是应该将单一表达式隐式返回给箭头函数的调用方。但是,如果主体不只一条语句或表达式,则必须使用花括号,而且所有返回的值都必须通过常用的        “return” 语法发回给调用方。
‘this’ 的新定义在开始设计 ECMAScript 6 之前很长一段时间,程序员很难确定 ECMAScript 的 this 参数指向哪里。从表面上看,与其他 C          族语言一样,this 参数引用的对象上会调用一个方法,如下所示:
清单 11. ‘this’        引用一个对象实例
let bob = {
  firstName: "Bob",
  lastName: "Robertson",
  displayMe: function() {
    for (let m in this) {
      console.log(m,"=",this[m]);
    }
  }
};
bob.displayMe();




上面的参数显然引用了实例 bob,而且忠实地打印出 firstName、lastName 和          displayMe 方法(因为它也是该对象的成员)的名称和值。
当从一个存在于全局范围的函数引用 this 时,情况会变得有点怪异:
清单 12. ‘this’        引用一个全局范围对象
let displayThis = function() {
  for (let m in this) {
    console.log(m);
  }
};
displayThis();




对于缺乏经验的开发人员,ECMAScript 将全局范围定义为一个对象,所以当在全局范围内的函数使用时,this        引用全局范围对象,在上面的情况中,它忠实地打印出全局范围的每个成员,包括顶级全局变量、函数和对象(比如上面的示例中的 “console”)。
出于这个原因,我们也可以在两种不同的上下文中重用该函数,知道它每次将或多或少执行一些我们期望的操作:
清单 13. 重用全局范围函数
let displayThis = function() {
  for (let m in this) {
    console.log(m);
  }
};
displayThis(); // this == global object
let bob = {
  firstName: "Bob",
  lastName: "Robertson",
  displayMe: displayThis
};
bob.displayMe(); // this == bob




可能此语法有点奇怪,但只要您理解了规则,就不是问题。直到您尝试使用 ECMAScript 构造函数作为对象类型时,情况才会真正偏离主题:
清单 14. 一个过度使用的        ‘this’function Person() {
  // The Person() constructor defines "this" as an instance
  // of itself
  this.age = 0;

  setInterval(function growUp() {
    // In non-strict mode, the growUp() function defines "this"
    // as the global object; thus, "this.age" refers to a global
    // "age" value, not the one defined on the instance of Person
    this.age++;
  }, 1000);
}
var p = new Person();
// Every second, p.age is supposed to go up by one.
// But because the "this" in the "growUp" function literal
// refers to the global object, and not "p", p.age will
// never change from 0.
返回列表