ES6核心特性(二)

ES6核心特性

前言

本文将在上文的基础上,继续介绍ES6核心特性:箭头函数、rest参数、扩展运算符、解构赋值以及模板字符串,希望对大家有些许帮助!

如果你想了解块作用域、promise、class以及ES6环境配置,请猛戳ES6核心特性(一)

一、箭头函数

ES6 允许使用“箭头”(=>)定义函数。它主要有两个作用:缩减代码和改变this指向,接下来我们详细介绍:

1. 缩减代码

const double1 = function(number){
   return number * 2;   //ES5写法
}
const double2 = (number) => {
 return number * 2;    //ES6写法
}
const double4 = number => number * 2; //可以进一步简化

多个参数记得加括号

 const double6 = (number,number2) => number + number2;

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回

 const double = (number,number2) => {
   sum = number + number2 
   return sum;
 }

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错

// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报
let getTempItem = id => ({ id: id, name: "Temp" });

此外还有个好处就是简化回调函数

// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});
// 箭头函数写法
[1,2,3].map(x => x * x);//[1, 4, 9]

2. 改变this指向

长期以来,JavaScript 语言的this对象一直是一个令人头痛的问题,在对象方法中使用this,必须非常小心。箭头函数”绑定”this,很大程度上解决了这个困扰。我们不妨先看一个例子:

const team = {
  members:["Henry","Elyse"],
  teamName:"es6",
  teamSummary:function(){
    return this.members.map(function(member){
      return `${member}隶属于${this.teamName}小组`;    // this不知道该指向谁了
    })
  }
}
console.log(team.teamSummary());//["Henry隶属于undefined小组", "Elyse隶属于undefined小组"]

teamSummary函数里面又嵌了个函数,这导致内部的this的指向发生了错乱。
那如何修改:

方法一、let self = this

const team = {
  members:["Henry","Elyse"],
  teamName:"es6",
  teamSummary:function(){
    let self = this;
    return this.members.map(function(member){
      return `${member}隶属于${self.teamName}小组`;
    })
  }
}
console.log(team.teamSummary());//["Henry隶属于es6小组", "Elyse隶属于es6小组"]

方法二、bind函数

const team = {
  members:["Henry","Elyse"],
  teamName:"es6",
  teamSummary:function(){
    return this.members.map(function(member){
      // this不知道该指向谁了
      return `${member}隶属于${this.teamName}小组`;
    }.bind(this))
  }
}
console.log(team.teamSummary());//["Henry隶属于es6小组", "Elyse隶属于es6小组"]

方法三、 箭头函数

const team = {
  members:["Henry","Elyse"],
  teamName:"es6",
  teamSummary:function(){
    return this.members.map((member) => {
      // this指向的就是team对象
      return `${member}隶属于${this.teamName}小组`;
    })
  }
}
console.log(team.teamSummary());//["Henry隶属于es6小组", "Elyse隶属于es6小组"]

3.使用注意点

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

二、rest 参数

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。

rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
我们举个例子:如何实现一个求和函数?

传统写法:

function addNumbers(a,b,c,d,e){
  var numbers = [a,b,c,d,e];
  return numbers.reduce((sum,number) => {
    return sum + number;
  },0)
 }
 console.log(addNumbers(1,2,3,4,5));//15

ES6写法:

 function addNumbers(...numbers){
  return numbers.reduce((sum,number) => {
    return sum + number;
  },0)
 }
 console.log(addNumbers(1,2,3,4,5));//15

也可以与解构赋值组合使用

var array = [1,2,3,4,5,6];
var [a,b,...c] = array;
console.log(a);//1
console.log(b);//2
console.log(c);//[3, 4, 5, 6]

rest 参数还可以与箭头函数结合

const numbers = (...nums) => nums;
numbers(1, 2, 3, 4, 5)// [1,2,3,4,5]  

注意:①每个函数最多只能声明一个rest参数,而且 rest参数必须是最后一个参数,否则报错。

②rest参数不能用于对象字面量setter之中

let object = {
    set name(...value){   //报错
        //执行一些逻辑
    }
}

三、展开运算符

与剩余参数关联最密切的就是扩展运算符。剩余参数允许你把多个独立的参数合并到一个数组中;而扩展运算符则允许将一个数组分割,并将各个项作为分离的参数传给函数。

当用在字符串或数组前面时称为扩展运算符,个人觉得可以理解为rest参数的逆运算,用于将数组或字符串进行拆解。有些时候,函数不允许传入数组,此时使用展开运算符就很方便,不信的话,咱们看个例子:Math.max()方法,它接受任意数量的参数,并会返回其中的最大值。

let value1 = 25,                
let value2 = 50;
console.log(Math.max(value1, value2));  //  50

但若想处理数组中的值,此时该如何找到最大值?Math.max()方法并不允许你传入一个数组。其实你可以像使用rest参数那样在该数组前添加...,并直接将其传递给 Math.max()

let values = [25,50,75, 100]
//等价于console.log(Math.max(25,50,75,100));
console.log(Math.max(...values));   //100

扩展运算符还可以与其他参数混用

let values = [-25,-50,-75,-100]
console.log(Math.max(...values,0)); //0

扩展运算符拆解字符串与数组

var array = [1,2,3,4,5];
console.log(...array);//1 2 3 4 5
var str = "String";
console.log(...str);//S t r i n g

还可以实现拼接

var defaultColors = ["red","greed"];
var favoriteColors = ["orange","yellow"];
var fallColors = ["fire red","fall orange"];
console.log(["blue","green",...fallColors,...defaultColors,...favoriteColors]
//["blue", "green", "fire red", "fall orange", "red", "greed", "orange", "yellow"]

四、解构赋值----更方便的数据访问

ES6 新增了解构,这是将一个数据结构分解为更小的部分的过程。

1.解构为何有用?

在ES5及更早版本中,从对象或数组中获取信息、并将特定数据存入本地变量,需要书写许多并且相似的代码。例如:

 var expense = {
   type: "es6",
   amount:"45"
 };
 var type = expense.type;
 var amount = expense.amount;
 console.log(type,amount);

此代码提取了expense对象的type与amount值,并将其存在同名的本地变量上。虽然 这段代码看起来简单,但想象一下若有大量变量需要处理,你就必须逐个为其赋值;并且若有一个嵌套的数据结构需要遍历以寻找信息,你可能会为了一点数据而挖掘整个结构。

这就是ES6为何要给对象与数组添加解构。当把数据结构分解为更小的部分时,从中提取你要的数据会变得容易许多。

2.对象

上个例子中如果采用对象解构的方法,就很容易获取expense对象的type与amount值。

const { type,amount } = expense;
console.log(type,amount);

我们再来看个例子:

let node = {type:"Identifier",  name:"foo"},    
type = "Literal",name = 5;
({type,name}= node);//  使用解构来分配不同的值 
console.log(type); //   "Identifier" 
console.log(name); //   "foo"

注意:你必须用圆括号包裹解构赋值语句,这是因为暴露的花括号会被解析为代码块语句,而块语句不允许在赋值操作符(即等号)左侧出现。圆括号标示了里面的花括号并不是块语句、而应该被解释为表达式,从而允许完成赋值操作。

默认值:
可以选择性地定义一个默认值,以便在指定属性不存在时使用该值。若要这么做,需要在 属性名后面添加一个等号并指定默认值,就像这样:

let node = {
  type: "Identifier",
  name: "foo"
};
let {
  type,
  name,
  value = true
} = node;
console.log(type); //   "Identifier" 
console.log(name); //   "foo" 
console.log(value); //  true

嵌套对象解构:
使用类似于对象字面量的语法,可以深入到嵌套的对象结构中去提取你想要的数据。

let node = {
  type: "Identifier",
  name: "foo",
  loc: {
    start: {
      line: 1,
      column: 1
    },
    end: {
      line: 1,
      column: 4
    }
  }
};
let { loc: { start }} = node;
console.log(start.line); // 1 
console.log(start.column); //   1

本例中的解构模式使用了花括号,表示应当下行到node对象的loc属性内部去寻找start属性。

必须传值的解构参数

function setCookie(name, value, {
  secure,
  path,
  domain,
  expires
}) {
  //    设置cookie的代码 
}
  setCookie("type", "js");//报错

在此函数内,name与value参数是必需的,而secure、path、domain与expires则不是。默认情况下调用函数时未给参数解构传值会抛出错误。像上例中如果setCookie不传第三个参数,就会报错。若解构参数是可选的,可以给解构的参数提供默认值来处理这种错误。

function setCookie(name, value, {
  secure,
  path,
  domain,
  expires
} = {}) {}
setCookie("type", "js");//不会报错

3.数组

const names = ["Henry","Bucky","Emily"];
const [name1,name2,name3] = names;
console.log(name1,name2,name3);//Henry Bucky Emily
const [name,...rest] = names;//结合展开运算符
console.log(rest);//["Bucky", "Emily"]

用{}解构返回数组个数

const {length} = names;
console.log(length);//3

数组解构也可以用于赋值上下文,但不需要用小括号包裹表达式。这点跟对象解构的约定不同。

let colors = ["red", "green", "blue"],
  firstColor = "black",
  secondColor = "purple";
[firstColor, secondColor] = colors;
console.log(firstColor); // "red" 
console.log(secondColor);   // "green"

默认值:数组解构赋值同样允许在数组任意位置指定默认值。当指定位置的项不存在、或其值为undefined,那么该默认值就会被使用。

let colors = ["red"];
let [firstColor, secondColor = "green"] = colors;
console.log(firstColor); // "red" 
console.log(secondColor);// "green"

与rest参数搭配

在ES5中常常使用concat()方法来克隆数组,例如:

//在ES5中克隆数组 
var colors = ["red", "green", "blue"];
var clonedColors = colors.concat();
console.log(clonedColors); //"[red,green,blue]"

在ES6中,你可以使用剩余项的语法来达到同样效果

//在ES6中克隆数组 
let colors = ["red", "green", "blue"];
let [...clonedColors] = colors;
console.log(clonedColors); //[red,green,blue]

接下我们看个例子:如何将数组转化为对象

const points = [
  [4,5],
  [10,1],
  [0,40]
];
//期望得到的数据格式如下,如何实现?
// [
//   {x:4,y:5},
//   {x:10,y:1},
//   {x:0,y:40}
// ]
let newPoints = points.map(pair => {
  const [x,y] = pair;
  return {x,y}
})
//还可以通过以下办法,更为简便
let newPoints = points.map(([x,y]) => {
  return {x,y}
})
console.log(newPoints);

混合解构

const people = [
  {name:"Henry",age:20},
  {name:"Bucky",age:25},
  {name:"Emily",age:30}
];
//es5 写法 
var age = people[0].age;
console.log(age);
//es6 解构
const [age] = people;
console.log(age);//第一次解构数组 {name:"Henry",age:20}
const [{age}] = people;//再一次解构对象
console.log(age);//20

4.注意点

当使用解构来配合var、let、const来声明变量时,必须提供初始化程序(即等号右边的值)。下面的代码都会因为缺失初始化程序而抛出语法错误:

var { type, name };//   语法错误! 
let { type, name };//   语法错误!
const { type, name };// 语法错误!

五、模板字符串(template string)

模板字符串是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
模板字符串中嵌入变量和函数,需要将变量名写在${}之中。

let name = "Henry";
function makeUppercase(word){
  return word.toUpperCase();
}
let template = 
  `
  <h1>${makeUppercase('Hello')}, ${name}!</h1>//可以存放函数和变量
  <p>感谢大家收看我们的视频, ES6为我们提供了很多遍历好用的方法和语法!</p>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
  </ul>
  `;
document.getElementById('template').innerHTML = template;
image

再举个例子,工作中常用到ElementUI库,在自定义一个弹出框时,使用模板字符串就很方便:

   await this.$alert(
          `<p><strong>确认是否升级${
            this.lectureName
          }</strong><br>(若已存在讲义套件,升级后请重新生成)</p>`,
          {
            dangerouslyUseHTMLString: true
          }
        )

如果觉得文章对你有些许帮助,欢迎在我的GitHub博客点赞和关注,感激不尽!

参考文章

ECMAScript 6 入门

深入理解ES6

ES6的rest参数和扩展运算符

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 三,字符串扩展 3.1 Unicode表示法 ES6 做出了改进,只要将码点放入大括号,就能正确解读该字符。有了这...
    eastbaby阅读 1,510评论 0 8
  • [TOC] 参考阮一峰的ECMAScript 6 入门参考深入浅出ES6 let和const let和const都...
    郭子web阅读 1,768评论 0 1
  • 一、ES6简介 ​ 历时将近6年的时间来制定的新 ECMAScript 标准 ECMAScript 6(亦称 ...
    一岁一枯荣_阅读 6,055评论 8 25
  • 今晚接触到了俩歌手:原子邦尼,周兴哲。 邦尼的电音听着是摇滚的治愈,不同于以往失恋的慢情歌。有点像分手后的...
    X_390a阅读 208评论 0 1
  • 昨天看朱丽姐写得 《和自己和解》,我泪流满面,因为从她的描述中我看到了自己的影子!当朱丽姐写到当别人说她的...
    盼盼_9ba9阅读 441评论 2 1