ES6学习总结

ES6

目标:学习 ES6的新语法;为将来的工作打下基础;

  1. ES6 介绍

  2. let const:定义变量的新途径;

  3. 解构赋值:快速给变量赋值;

  4. 内置对象的扩展:增强功能;

  5. ES 6 降级处理:对不支持es6版本的环境如何处理?

ES6 介绍

为什么要学习ES6

  • 提供了更加方便的新语法弥补 JS 语言本身的缺陷,新增了便捷的语法

  • 给内置对象增加了更多的方法

  • ES6 让 JS 可以开发复杂的大型项目,成为企业级开发语言

  • 新的前端项目中大量使用 ES6 的新语法

ES 6 是什么

  • ECMAScript 6,简称ES6 。它是一种语言标准,6表示版本号。 它是Ecma国际(European Computer Manufacturers Association)于2015年6月正式发布的 JavaScript 语言的下一代标准,正式名为ECMAScript 2015(简写ES2015)。它的目标是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。相比较ES5(2011年发布的),它改进是非常大的,所以在一些场景下ES6也泛指ES2015及之后的新增特性,虽然之后的版本应当称为ES7、ES8等,但统称es6。

  • ECMA的第39号技术专家委员会(Technical Committee 39,简称TC39)负责制订ECMAScript标准组织每年都会发布ECMAScript的版本

  • 与javascript的关系:ECMAScript是一种语言标准,javascript实现了这个标准。javascipt由三部分组成

    • ECMAScript

    • DOM

    • BOM

学习内容

es6新增了很多强大的语法,如下是比较常使用的:

  1. let 和 const

  2. 解构赋值

  3. 函数

  4. 字符串扩展

  5. 数组扩展

  6. 新的定义对象的方式

参考:

  1. 各种环境中对es6的支持程度: http://kangax.github.io/compat-table/es6/

  2. es6电子书: http://es6.ruanyifeng.com/#docs/intro

let 和 const

es5中提供了定义变量的关键字var,但是这个关键字的功能有限,它定义的变量也有很多奇怪的特性,并不能完全满足现在越来越复杂的环境,所以在es6中新增了两个关键字:let,const。

let 变量

使用场景

它用来定义变量,基本使用格式与var关键字一样。在可以在使用var 的地方改成let。

与var的区别

  • 不能重复定义

  • 具有块级作用域

  • 没有变量提升(var定义的变量是有变量提升的),必须先定义再使用

  • 不会附加到window对象的属性中

代码演示

// 1. let 定义变量,变量不可以再次定义,但可以改变其值
let name = 'zhangsan';
name = 'lisi';
console.log(name); // lisi
let name = 'wangwu'; // 再次定义,报错:Identifier 'name' has already been declared
// 2. 具有块级作用域,块就是大括号
{
   let age = 18;
   console.log(age); // 18
}
console.log(age); // 报错,此作用域中没有age的定义

for (let i = 0; i < 10; i++) {
   // i 只能在此范围内使用,因为有块级作用域
}
console.log(i);  // 报错,此作用域中没有age的定义

 

// 3. 没有变量提升,必须先定义再使用
console.log(gender); // 报错,此时还没有定义gender
let gender = '男';

console.log(1); // 不报错,输出undefined
var a = 1;
// 4. let声明的变量不会压到window对象中,是独立的
let hobby = '吃饭';
var a = 1
console.log(window.hobby); // undefined
console.log(window.a); // undefined

如果使用var声明了变量,也不能再次用let声明了,反之也是不行的。原因也是这个变量已经被声明过了。

最佳实践:实际开发要么全部使用var,要么全部使用let。由团队开发规范来定。

const 常量

使用场景

多个程序员共同开发项项目时,会遇到一种场景:有一些数据大家都需要用到,但是都不能修改,即数据是只读的。

举个例子:在开发公司的网站时,公司的基本信息:地址,公司名,电话等等信息可以在多个地方都需要使用,但不允许去修改。 这个时候,就可以把这些数据保存在常量中。

 

语法格式及命名规范

//  格式:
const 常量名 = 常量值;

const COMPANY_NAME = "XXX公司"
  • 区别于变量名,常量名一般采用全大写的方式

  • 多个单词之间使用_划线分隔。

常见误区

const obj = {a:1};
obj.a = 2;
console.log(obj); // 问题:obj对象的属性值a是否修改了。

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动

  1. 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

  2. 对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心,它的属性是可以修改的

与let相似的特点

  • 具有块级作用域

  • 没有变量提升,必须先定义再使用

  • 常量也是独立的,定义后不会压入到window对象中,不是window对象的属性

小结

关键字变量提升块级作用域初始值更改值通过window调用
let × - Yes No
const × Yes No No
var × - Yes Yes

解构赋值

使用场景,快速从数组或者对象中取出数据。

定义

ES 6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

它有两个动作:

- 解构:意思是把有结构的数据分解开成为一个一个的值;
- 赋值:把解构之后的值保存到变量。

demo

let arr = [1,2,3,4];
// 需求,快速地从数组中取出值来赋值给变量
let a = arr[0];
...
let d = arr[1];
console.log(a,b,c,d)

 

数组的解构赋值

它能够快速从数组中取出值保存到变量中。它的本质是给变量赋值。

内容:

  • 语法格式及解构规则

  • 常规使用:变量个数等于数组长值

  • 非常规使用

    • 变量个数大于数组长度

    • 变量个数小于数组长度

  • 高级使用

    • 用空跳过不需要的值

    • 剩余值

    • 复杂嵌套场景

  • 小面试题

语法格式及解构规则

// 格式:
 let [变量1,变量2,... 变量n ] = [数组元素1,数组元素2.....,数组元素n]
// 规则:按赋值符号两边的数组,下标从小到大,一一对应。

 

场景1,变量个数等于数组长值

// 场景1,变量和值一一对应
let arr = [5, 9, 10];
let [a, b, c] = arr;
console.log(a, b, c); // 输出 5 9 10
// 等价于:
let a = arr[0];
let b = arr[1];
let c = arr[2];

注意:

  • “=”左右两边的格式要统一。

场景2,变量个数大于数组长度

// 场景2,变量多,值少
let arr = [5, 9, 10];
let [a, b, c, d] = arr;
console.log(a, b, c, d); // 输出 5 9 10 undefined
// 结论:没有匹配上的值是undefined

场景3,变量个数小于数组长度

// 场景3,变量少,值多
let arr = [5, 9, 10, 8, 3, 2];
let [a, b] = arr;
console.log(a, b); // 5, 9
// 结论:多余的忽略

场景4,用空跳过不需要的值

// 场景4,按需取值
let arr = [5, 9, 10, 8, 3, 2];
let [, , a, , b] = arr; // 不需要用变量接收的值,用空位占位
console.log(a, b); // 10, 3

场景5,剩余值

// 场景5,剩余值
let arr = [5, 9, 10, 8, 3, 2];
let [a, b, ...c] = arr; // ...c 接收剩余的其他值,得到的c是一个数组
console.log(a, b, c);
// 结果:
// a = 5,
// b = 9,
// c = [10, 8, 3, 2]

注意:

  1. ... 的收集

  2. Rest element must be last element。必须在最后;

 

场景6,复杂嵌套场景

// 场景6,复杂的场景,只要符合模式,即可解构
let arr = ['zhangsan', 18, ['175cm', '65kg']];
let [, , [a, b]] = arr;
console.log(a, b); // 175cm 65kg

一个小面试题

交换两个变量的值?

var a = 1, b = 2;
// 写代码,实现互换a,b的值
// ????

console.info(a,b); // 要求输出 2, 1

 

对象的解构赋值

作用:快速从对象中获取值保存到变量中。它的本质是给变量赋值。

也通过如下几种场景来学习

  • 变量名和属性名一样

  • 变量改名

  • 剩余值

  • 复杂嵌套

使用格式及规则

完整格式:

let {"属性名1":变量名1, "属性名2":变量名2 } = {"属性名1":属性值1,"属性名2":属性值2,...}

解析规则:

右边的"属性名"与左边的“属性名” 一致,则把右边的属性值赋值给左边的变量名。

精简格式:

如果左侧对象中属性名与变量名相同,则可左侧合并:

let {变量名1,变量名2} = {"属性名1":属性值1,"属性名2":属性值2,...}

解析规则:

右边的"属性名"与左边的变量名 一致,则把右边的属性值赋值给左边的变量名。

 

基本使用

场景1,变量名和属性名一样

// 场景1,默认要求变量名和属性名一样
let { name, age } = {age: 27, name: '阳明'};
console.log(name, age);

let {a, c} = {a: 'hello', b: 'world'};
console.log(a, c); // hello, undefined

注意:

  • “=” 左右两边的格式一致。

  • 对象是属性的无序集合,所以不需要管顺序

场景2,变量改名

// 场景2,可以通过:为变量改名
let {a, b:c} = {name: '王阳明', b: 'world'};
console.log(a, c); // hello, world

 

 

特殊使用

剩余值
// 把其它的属性全收集起来
let obj = {name:'zs', age:20, gender:'男'};
let {name, ...a} = obj;
console.log(name, a);
// 结果:
// name = zs
// a = {age: 20, gender: "男"};

 

复杂嵌套

只要符合模式,即可解构

// 复杂的场景,只要符合模式,即可解构
let obj = {
   name: 'zhangsan',
   age: 22,
   dog: {
       name: '毛毛',
       age: 3
  }
};
let {dog: {name, age}} = obj;
console.log(name, age); // 毛毛 3

实际应用

// 假设从服务器上获取的数据如下
let response = {
   data: ['a', 'b', 'c'],
   meta: {
       code: 200,
       msg: '获取数据成功'
  }
}
// 如何获取到 code 和 msg
let { meta: { code, msg } } = response;
console.log(code, msg); // 200, 获取数据成功

 

函数的拓展

es6对函数的功能进行了一些拓展,补充了很多功能。学习这个部分的内容我们就可以灵活地使用函数。

内容

  • 参数默认值

  • 箭头函数(重点)

  • rest参数

参数的默认值

参数默认值是一个非常实用的功能,学习这个部分我们可以更加地理解api中的默认参数的实现,能写出用户体验更好的函数。

理解默认值

参数的默认值在之前的课程内容已经涉及,例如在xhr.open(type,url,是否异步)方法中,第3个参数默认是true,即表示异步ajax。

默认值的意思是:

  • 如果传入,就用你传的值

  • 如果不传入,就使用某一个特殊的、事先定义好的值。这个值也就是默认值。

ES5的实现

ES6 之前,函数不支持设置参数的默认值(其它大多数编程语言都是支持的)。但虽然在语法层面上不支持,程序员们也会想一些变通的方法。

// ES5 中给参数设置默认值的变通做法
function open(type, url,isAsync) {
   if(isAsync === undefined){
       isAsync = true;
  }
   console.log(type, url, isAsync);
}
// 下面这两句是等价的
open("get","common/get")//
open("get","common/get",true)

open("get","common/get",false)

ES6的实现

格式
function 函数名(参数名1='默认值1',参数名2='默认值3',参数名1='默认值3'){
   
}
示例
// E65 给参数设置默认值
function open(type, url,isAsync=true) {
   console.log(type, url, isAsync);
}

 

思考:能否给type设置默认值,为'get' ?

function open(type='get', url,isAsync=true)

注意:

  • 带默认值的形参放在形参列表的后面

与解构赋值一起使用

let obj1 = { url: "/common/get", type:"get"}

function open(obj){
   console.info(obj.url, obj.get)
}
function open({url,type}){
   console.info(url,type)
}
function open({url,type='get'}){
   console.info(url,type)
}

 

箭头函数

学习箭头函数能让代码更简洁,效率更高;能看懂别人写的代码 ;

let fn3 = x => x * 2;

内容

  • 定义及格式

  • 三种简化原则

  • 三个特点

  • 典型应用场景

什么是箭头函数

ES6 中允许使用箭头函数的方式来定义一个函数。前面学习的定义一个函数有两种方式:

  1. 函数声明式

  2. 函数表达式

现在有了一个新的方式:

3. 箭头函数

格式

let 函数名 = (形参1,...形参n)=>{
   // 函数体
}

 

定义一个箭头函数

// 1. 函数声明式
function fu1(x){
   return x * 2;
}
// 2. 函数表达式
let fn2 = function (x) {
   return x * 2;
}
// 3. 箭头函数
let fn3 = (x) => {
   return x * 2;
}

第一眼看到这个箭头函数时,会觉得很奇怪。如果从函数表达式的格式出发, 经过如下2步演化步骤就可以得到。

  1. 把function 关键字 后移动到 ()和 {} 中间

  2. 把function 改写成 =>

注意:

- `=>`是一个整体,不要加空格
- 箭头函数只在定义上有些区别,但在函数调用格式上,是没有区别的。

 

三种简化场景

  • 当形参有且只有一个,可以省略小括号

  • 当函数体只有一条语句,可以省略大括号;

  • 当函数体只有一条语句,并且就是return语句,则可以省略return

 

//  完整箭头函数
let fn = (x) => {
   return x * 2;
}
// 参数只有一个,省略小括号
let fn = x => {
   return x * 2;
}
// 函数体中只有一个返回语句,可以省略大括号
let fn = x => x*2

 

箭头函数的特点

它与普通函数的区别

  • 内部没有arguments

  • 内部没有this

  • 不能作为构造器

没有 arguments
let fn = (a,b) => {
   console.log(arguments); // 报错,arguments is not defined
};
fn(1, 2);
内部的this对象,就是定义时所在的对象,而不是使用时所在的对象。
var name = 'lisi'; // 测试时,这里必须用var,因为用let声明的变量不能使用window调用
let obj = {
    name: 'zhangsan',
    fn : () => {
        console.log(this); // window对象
        console.log(this.name); // lisi
    }
};
obj.fn();
箭头函数不能作为构造函数
let Person = () => {
	
};
let obj = new Person(); // 报错,Person is not a constructor
// 换个角度理解,箭头函数中都没有自己的this,怎么处理成员,所以不能当构造函数

典型应用场景

  1. 定义函数

  2. 回调函数

  3. 事件响应函数

var arr = [1,2,3]
arr.sort(function(a,b){ return a - b});
// 简化
arr.sort((a,b)=>a-b)

 

rest 参数

rest: 其它的,剩余的; rest 参数 用于获取函数多余参数,把它们放在一个数组中。

语法格式

在定义函数时,在最后一个参数前面加上..., 则这个参数就是剩余参数;

let fn = function(参数1,参数2,...rest参数){}

let fn = (参数1,参数2,...rest参数)=>{ }

只是在定义函数时,在形参列表中区别一下,而在调用函数时并无区别。

示例

回答如下问题

function f1 (x,y){
    console.log(x,y)
}
f1(1,2);
f1(2,3,4);

function f2 (x,...y){
    console.log(x,y)
}
f2(1,2);
f2(2,3,4);

应用实践--代替arguments

问题:编写一个函数,求所有参数之和;

方法一:arguments

方法二:rest参数

 

function getSum (){
    //  在这里写你的代码
    var sum = 0 ; 
    for(var i = 0; i < arguments.length; i++){
        console.info( arguemnts[i])
        sum += arguments[i];
    }
}

 

如果以箭头函数 的方式去定义这个函数,则内部不可以使用arguments这个对象了。此时,我们就可以使用

rest 参数,它可以替代 arguments 的使用。 代码如下:

// 参数很多,不确定多少个,可以使用剩余参数
const  getSum = (...values) => {
    var sum = 0 ; 
    for(var i = 0; i < values.length; i++){
        console.info( values[i])
        sum += values[i];
    }
}
// 调用
console.log(fn(6, 1, 100, 9, 10));

 

数组的扩展

数组对象是js中非常重要的对象,它本身提供了非常多的方法:sort,push,pop,unshift, splice,concat.... 。由于前端的主要工作内容之一是与后端进行数据交互,而数据交互的载体大多是数组,所以我们对数组的操作要求也非常高。

曾经有一道面试题:写出10个你用过的与数组相关的方法。

这一小节的学习会让我们多掌握几个数组的方法。

扩展运算符

功能:它的作用是把数组中的元素一项项地展开:把一个整体的数组拆开成单个的元素。

格式:...数组

基本用法

console.info(...[1,2,3]);

应用1: 数组合并

从把一个数组中的值全取出来,放在另一个数组中的

var arr0 = ['a','b'];
var arr1 = [1,2,3];
var arr2 = [4, ...arr1];
var arr3 = [..arr0 ,...arr1];

应用2:Math.max()

Math.max(1,3,4,6);
var arr = [1,3,4,6];
Math.max(...arr);

Array.from()

功能:把其它非数组的对象转成数组。

格式: 数组 = Array.from(非数组对象)

它的实参有三种情况:

  1. 自定义的,特殊格式的对象

let fakeArr = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};
  1. arguments对象

  2. DOM 操作返回的 NodeList 集合

find

在实际的开发中,我们经常会遇到一种场景:从一个数组中找出符合条件的元素。我们要的讨论的重点是如何从数组中找出符合条件的元素,当然,我们可以通过手写循环的方式来实现这个功能,但是现在es6中提供了现成的功能。find/findIndex

作用:从数组中找出我们符合条件的第一个元素(或者是下标)。

格式

find和findIndex的格式是一致的。

let result = [].find(function(item,index,self){ 
    //.... 
    // 如果满足查找的条件
    return true;
})
  • 回调函数有三个参数,分别表示:数组元素的值、索引及整个数组

  • 如果某次循环返回的是true,find和findIndex方法的返回值就是满足这个条件的第一个元素或索引

执行流程

  • find和findIndex方法,会遍历传递进来的数组

  • 如果在回调函数体内,某个时刻return true,则表示查找过程结果,返回值就是本轮循环中的元素(或者是下标);如果全部的循环结束,也没有返回true,则表示没有找到。

  • findIndex 找到数组中第一个满足条件的成员并返回该成员的索引,如果找不到返回 -1

let arr = [1, 2, 4, 0, -4, 3, -2, 9];
arr.find(function (item, index, self) {
    console.log(item); // 数组中的每个值
    console.log(index); // 数组中的每个索引/下标
    console.log(self); // 当前的数组
});

简单示例

// 用法:找数组中第一个小于0的数字
let arr = [1, 2, 4, 0, -4, 3, -2, 9];
let result = arr.find(function (item) {
    return item < 0; //遍历过程中,根据这个条件去查找
});
console.log(result); // -4

注意通过箭头函数来简化代码。

实践应用

从一个复杂的对象数组中找出符合条件的对象。

let data = [
    {id:2,name:'严高',age:15},
    {id:3,name:'徐阶',age:17},
    {id:4,name:'高拱',age:18},
    {id:1,name:'张居正',age:12},
]

 

findIndex

findIndex 的使用和 find 类似,只不过它查找的不是数组中的元素,而是元素的下标。

 

includes()

功能:判断数组是否包含某个值,返回 true / false

格式:数组.includes(参数1,参数2)

  • 参数1,必须,表示查找的内容

  • 参数2,可选,表示开始查找的位置,0表示从第一个元素开始找。默认值是0。

示例:

let arr = [1, 4, 3, 9];
console.log(arr.includes(4)); // true
console.log(arr.includes(4, 2)); // false, 从2的位置开始查,所以没有找到4
console.log(arr.includes(5)); // false

字符串也有这个方法,功能也是相似的。

String的扩展

es6中对字符串提供了新的特性,我们介绍其中几个方法:

  • 模板字符串

  • includes

  • startsWith

  • endWith

  • repeat

模板字符串

在做字符串拼接时,使用+来拼接复杂内容是很麻烦的,而模板字符串可以解决这个问题。

格式:`${变量} ${表达式}`

语法:

  • 模板字符串使用反引号 ` 把内容括起来,类似于普通字符串的""。

  • ${}充当界定符的作用,其中可以写变量名,表达式等。

  • 允许字符串内部进行换行,代码更好读更好的体验

示例:

let name = 'zs';
let age = 18;
// 拼接多个变量,在模板字符串中使用占位的方式,更易懂
let str = `我是${name},今年${age}`;

// 内容过多可以直接换行
let obj = [{name: 'flex', age: 20},{name: 'james', age: 21}];

let arr = ['175cm', '60kg'];
let html = `
	<div>
		<ul>
			<li>${obj.name}</li>
			<li>${obj.age}</li>
			<li>${arr[0]}</li>
			<li>${arr[1]}</li>
		</ul>
	</div>

 

 

includes()

  • 格式:str.includes(searchString, [position])

  • 功能:返回布尔值,表示是否找到了参数字符串

    • position: 从当前字符串的哪个索引位置开始搜寻子字符串,默认值为0。

startsWith()

  • 格式:str.startsWidth(searchString, [position])

  • 功能:返回布尔值,表示参数字符串是否在原字符串的头部或指定位置

    • position: 在 str 中搜索 searchString 的开始位置,默认值为 0,也就是真正的字符串开头处。

endsWith()

  • 格式:str.endsWith(searchString, [len])

  • 功能:返回布尔值,表示参数字符串是否在原字符串的尾部或指定位置.

    • len:可选。作为 str 的长度。默认值为 str.length

repeat()

repeat方法返回一个新字符串,表示将原字符串重复n次。

语法:str.repeat(n)

let html = '<li>itheima</li>';
html = html.repeat(10);

Number的扩展

ES6 将全局方法parseInt()parseFloat(),移植到Number对象上面,行为完全保持不变。

  • Number.parseInt()

  • Number.parseFloat()

Set对象

Set是集合的意思。是ES6 中新增的内置对象,它类似于数组,但是成员的值都是唯一的,即没有重复的值。使用它可以方便地实现用它就可以实现数组去重的操作。

如何创建一个set

  • 创建空set;

  • 根据已有数组创建set

// 1. 基本使用
let set = new Set();
// 得到一个空的Set对象

let set = new Set([1,2,3])

 

Set 的成员方法

  • size:属性,获取 set 中成员的个数,相当于数组中的 length

  • add(value):添加某个值,返回 Set 结构本身。

  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。

  • has(value):返回一个布尔值,表示该值是否为Set的成员。

  • clear():清除所有成员,没有返回值。

  • 遍历for of

 

数组去重

let arr = [1,1,2,3,3];
console.info([...new Set(arr)])

 

4. 定义对象的简洁方式

  • 对属性名的简化

  • 对方法的简化

let name = 'zhangsan', age = 20, gender = '女';
let obj = {
    name: name, // 原来的写法
    age, // 对象属性和变量名相同,可以省略后面的 “:age”,下面的gender同理
    gender,
    fn1:function(){  // 常规写法
        console.log(123);
    },
    fn2 () { // 可以省略 
        console.log(456);
    }
};
console.log(obj.age); // 20
obj.fn2(); // 456

ECMAScript 6 降级处理(演示)

ES 6 的兼容性问题

  • ES6 (2015年10月)虽好,但是有兼容性问题,IE7-IE11 基本不支持 ES6

    ES6 兼容性列表

  • 在最新的现代浏览器、移动端、Node.js 中都支持 ES6

  • 后续我们会讲解如何处理 ES6 的兼容性

ES 6 降级处理

因为 ES 6 有浏览器兼容性问题,可以使用一些工具进行降级处理,例如:babel

  • 降级处理 babel 的使用步骤

    1. 安装 Node.js

    2. 命令行中安装 babel

    3. 配置文件 .babelrc

    4. 运行

  • 安装 Node.js

    官网

  • 项目初始化(项目文件夹不能有中文)

    npm init -y
    
  • 在命令行中,安装 babel babel官网

    npm install  @babel/core @babel/cli @babel/preset-env
    
  • 配置文件 .babelrc (手工创建这个文件)

    babel 的降级处理配置

    {
      "presets": ["@babel/preset-env"]
    }
    
  • 在命令行中,运行

    # 把转换的结果输出到指定的文件
    npx babel index.js -o test.js
    # 把转换的结果输出到指定的目录
    npx babel 包含有js的原目录 -d 转换后的新目录
    

参考:babel官网

6. 扩展阅读

ES 6 扩展阅读

 

posted @ 2019-08-01 20:43  麋鹿先生1314  阅读(257)  评论(0编辑  收藏  举报