ES6理论、知识点以及知识点演示代码

目标

学习完 ES6 可以掌握方便后续的开发,未来工作中大量使用 ES6 开发

1. ECMAScript 6 介绍

ES – ECMAScript

ECMA – 欧洲计算机制造商协会

ECMA262标准 – 第一版JS的标准

我们之前学习的是 ES5.1

2015年发布了ES6,并且更名为ES2015。决定以年号为版本号,并且每年发布一个新版本。

  • ES2015
  • ES2016

网上所说的ES7、ES8等等,只是人们推算的,因为官方从未承认什么ES7,ES8。网上所提到的ES7,正式名称应该是ES2016。

  • 每一年,所有人可以给JS提议,提出JS需要哪些改进,并给出解决办法。
  • 如果提议被采纳,进入草案阶段
  • 第二年发布的新版,就会包括前一年的草案

1.1 为什么要学习ES6

  • 提供了更加方便的新语法,弥补 JS 语言本身的缺陷,新增了便捷的语法
  • 给内置对象(Array、String、…)增加了更多的方法。
  • ES6 让 JS 可以开发复杂的大型项目,成为企业级开发语言
  • 新的前端项目中大量使用 ES6 的新语法(今天学完,后面就大量使用了)

1.2 ECMAScript 6 是什么

  • ECMAScript 6 又叫 ES2015,简称 ES6
  • ES6 是继 ES4、ES5 之后的 JS 语言规范
  • ES6 中增加了一些新的特性
  • ES6 的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言
  • 2015年6月发布

1.3 小结

  • ES6 是新的 JS 的代码规范,提供了一些新特性,使我们可以开发大型应用
  • ES6 弥补了 JS 语言本身的缺陷,增加了新语法,扩展了内置对象
  • ES6用起来非常爽。因为语法非常人性化。

2. ECMAScript 6 新增语法

  • let和const关键字
  • 箭头函数
  • 函数参数默认值
  • 函数剩余参数
  • Array对象扩展
  • String对象扩展
  • 新增对象Set
  • 定义对象的简洁方式
  • Promise(最后一天)

2.1 let 和 const

let – 用于声明变量

  • let 定义变量,只要有let参与,不能重复声明变量,会报错。但可以改变其值
let c = 10;
c = 20;
console.log(c);
  • 具有块级作用域
for (let i = 0; i < 3; i++) {
    //只能在这里面打印才有效
    console.log(i);
}
  • 没有变量提升,必须先定义再使用
let a = 10;
console.log(a);
  • let声明的变量,不能通过window调用,调用显示undefined
let b = 300;
console.log(window.b);  //undefined

注意:

  • 如果使用var声明了变量,也不能再次用let声明了,反之也是不行的。
  • 原因也是这个变量已经被声明过了。
  • 不过这只是一种特殊情况了,实际开发要么全部使用var,要么全部使用let。

const – 用于声明常量(值不能改变)

  • 使用const关键字定义常量
  • 常量是不可变的,一旦定义,则不能修改其值
  • 初始化常量时,必须给初始值
  • 具有块级作用域
  • 没有变量提升,必须先定义再使用
  • 常量也是独立的,定义后不会压入到window对象中

代码演示:

// 1. 使用const关键字定义常量,常量名一般大写
const PI = 3.1415926;
// 2. 常量是不可变的,一旦定义,则不能修改其值
const PI = 3.1415926PI = 3.14; // 报错,常用一旦被初始化,则不能被修改
// 3. 初始化常量时,必须给初始值
const PI; // 报错,Missing initializer in const declaration
// 4. 具有块级作用域
// 5. 没有变量提升,必须先定义再使用
// 6. 常量也是独立的,定义后不会压入到window对象中
// 这三条和let变量一样,不再写代码

let 和 const 小结

在这里插入图片描述

2.2 解构赋值

  1. 数组的解构
  2. 对象的解构

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

2.2.1 数组的解构

语法:
let 模式 = 数组   //模式跟数组长得一样
  • 特点1.将数组中的值取出,赋值给变量
let [a, b, c] = [1, 2, 3];
console.log(a,b,c);
  • 特点2.数组的值比变量多
let [d, e, f] = [2, 3, 4, 5, 6];
console.log(d, e, f);  //打印出 2,3,4
  • 特点3.变量的数量比值多
let [g, h, v] = [1, 2];
console.log(g, h, v);  // 1, 2, undefined
  • 特点4.按需取值
let [name, , data] = ['关羽', '美髯公', '青龙偃月刀']; //用空格空出,逗号不可以省略
console.log(name, data);
  • 特点5.剩余值
let [aa, bb, ...cc] = [1,2, 3, 4, 5, 6];
console.log(aa, bb);   // aa:1; bb:2; cc: 3,4,5,6
console.log(cc);   // aa:1; bb:2; cc: 3,4,5,6
  • 特点6.误区
let [aaa, ...bbb, ccc] = [1, 2, 3, 4, 5 ,6];   // 报错,剩余值,必须是最后一个元素
  • 实际小应用
<body>
    <script>
        // 定义一个函数,函数的参数是一个数组,我们要实现的是把数组的前三个单元加起来
        
        // 第一种方法:
        function sum(arr) {
            let [a, b, c] = arr;
            console.log(a + b + c);
        };
        sum([1, 2, 3, 4, 5]);

        // 第二种较简单方法:
        function sum([a, b, c]) {
            // 形参 = 实参
            // [a, b, c] = [1, 2, 3, 4, 5]
            console.log(a + b + c);
        }
        sum([2, 3, 4, 5, 6]);
    </script>
</body>

2.2.2 对象的解构

意思是把对象中的值取出来,赋值给其他变量

  • 特点1:变量名和属性名一致即可获取到值,不一定要一一对应
let {name, id, nickname} = {id: 1, name: '宋江', nickname: '及时雨'};
console.log(id, name, nickname);
  • 特点2. 值多,变量少
let {id, nickname} = {id: 2, name: '露露', nickname: '玉麒麟'};
console.log(id, nickname);
  • 特点3. 变量多,值少
let {id, name, age} = {id: 3, name: '吴用'};
console.log(id, name, age);
  • 特点4. 剩余值
let {id, age, ...other} = {id:4, name: '林冲', nickname: '豹子头', age: 35};
console.log(id, age);
console.log(other); // {name: '林冲', nickname: '豹子头'}
对象的复杂解构

如果在解构的时候,变量的名字如果有冲突。则可以使用 a:b 的形式,为变量改名

代码演示:

<body>
    <script>
        let person = {
            name: '小明',
            age: 25,
            dog: {
                name: '小黑',
                age: 2
            }
        }

        // 使用对象的解构,把人的名字和小狗的名字解出来
        //如果在解构的时候,变量的名字如果有冲突。则可以使用 a:b 的形式,为变量改名
        let {name:pname, age:page, dog:{name, age}} = person;
        console.log(pname, page, name, age);
    </script>
</body>
对象更加的复杂解构
  • 解构的时候,模式和对象的 结构 是一样的
  • 如果变量名冲突,可以使用 原变量: 新变量 的语法处理

代码演示:

<body>
    <script>
        let person = {
            pname: '小明',
            page: 20,
            dog: {
                name: '小黑',
                age: 4,
                child: {
                    name: '小白',
                    age: 1
                }
            }
        }

        let {
            pname, 
            page, 
            dog: {
                name: dname, 
                age: dage, 
                child: {
                    name, age
                }
            }
        } = person;

        console.log(pname, dname, name);
    </script>
</body>

2.3 函数

2.3.1 箭头函数

ES6 中允许使用箭头定义函数 (=> goes to),目的是简化函数的定义并且里面的this也比较特殊。

回顾之前的函数定义
<body>
    <script>
        // 回顾,之前函数是如何定义的

        function abc () {
            // 函数体
            // 可以有return
        }

        var fn = new Function('x', 'y', 'return x+y');

        
        var fn = function (x, y) {
            return x + y;
        }

        // 自调用函数,为什么要加小括号。
        // 原因是一条语句,不能以function开头
        // 自调用函数,前面可以加 ~ ! + ,而不使用小括号
        ~function (x, y) {
            console.log(x + y);
        }(2, 3);

        var fn = function (x, y) {
            console.log(x + y);
        }
        fn(3, 4);

        (function (x, y) {
            console.log(x + y);
        })(3, 4);
    </script>
</body>
箭头函数的语法
() => {}
(参数列表) => {函数体}

注意事项:

1.() => 之间不能换行
2. => {} 之间可以换行

代码演示:

let fn = (x, y) => {
    return x + y;
}
// 调用
console.log( fn(5, 8) );
箭头函数特点
  • 形参只有一个,可以省略小括号
let fn = (x) => {
    return x * 2;
}
// 等同于
let fn = x => {
    return x * 2;
}
  • 函数体只有一行代码,可以省略大括号,并且表示返回函数体的内容
let fn = (x, y) => {
    return x + y;
}
// 等同于
let fn = (x, y) => x + y;

箭头函数的注意点:

如果函数体仅仅返回一个字面量对象的话。需要给字面量对象加一个小括号
let abc = () => {x: 1}
console.log( abc() );
箭头函数功能上的特点
  • 特点1:箭头函数内部没有 arguments
let fn = () => {
        console.log(arguments); // 报错,arguments is not defined
};
fn(1, 2);
  • 特点2:箭头函数内部的 this 指向外部作用域中的 this ,或者可以认为箭头函数没有自己的 this
let fn = () => {
    console.log(this); // 查找一个变量this、函数内部没有找到,根据作用域链,去函数的外部进行查找,找到的结果为window对象
}
fn();

特点2 代码演示:

var age = 123; // 这里用var声明变量,否则就不能通过 window.age 来调用了
let obj = {
    age: 456,
    fn: function () {
        console.log(this.age);
    },
    fn2: () => {
        console.log(this.age); // window.age
    }
}
obj.fn(); // 456,因为函数中的this表示当前的调用者 obj
obj.fn2(); // 123, 箭头函数中没有this。所以会去外层查找this,所以this是window
  • 特点3: 箭头函数不能作为构造函数
let abcd = () => {
    this.age = 20;
    this.name = 'zs';
}
let p = new abcd(); // 报错,abcd is not a constructor

2.3.2 参数的默认值

ES6 之前函数不能设置参数的默认值

代码演示:

// ES5 中给参数设置默认值的变通做法
function fn(x, y) {
    y = y || 'world';
    console.log(x, y);
}
fn(1)
// ES6 中给函数设置默认值
function fn(x, y = 'world') {
    console.log(x, y);
}
fn(2)
fn(2,3)
  • 我们实际传递给函数的实参,优先级大于默认值。如果我们调用的时候,没有传递实参,则会使用默认值;如果调用函数的时候,传递了实参,则使用传递的实参
  • 有默认值的参数,应该放到没有默认值的参数的后面。这样才会有意义
  • 任何函数,都可以为参数设置默认值

2.3.3 rest 参数

rest 参数:剩余参数,以 … 修饰最后一个参数,把多余的参数都放到一个数组中。可以替代 arguments 的使用
  • 接收剩余参数
let abc = (a, b, ...c) => {
    console.log(a, b);
    console.log(c);
}
abc(1, 2, 3, 4, 5);
  • 直接使用剩余参数,一次性接收到所有的实参。解决了箭头函数内部不能使用arguments的问题
let abc = (...val) => {
    console.log(val);
}
abc(3, 4, 5, 6, 7);
  • 注意:因为要求剩余参数,必须是参数列表中的最后一个参数

3. 内置对象的扩展

  1. Array 的扩展
  2. String 的扩展
  3. Number 的扩展
  4. Set

3.1 Array 的扩展

  • 扩展运算符

    • 官网:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax

    • 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;

      • 可以在函数调用时, 将数组表达式在语法层面展开

        let abc = (a, b, c) => {
            console.log(a, b, c);
        }
        
      • 调用函数时,数组类型的实参,可以使用 … 展开

        abc(...[1, 2, 3 ,4, 5]); // ======= abc(1, 2, 3, 4, 5);
        
      • 可以在函数调用时, 将string在语法层面展开

        let abc = (a, b, c) => {
            console.log(a, b, c)
        };
        abc(...'hello'); // =====  abc('h', 'e', 'l', 'l', 'o');
        
      • 可以在数组构造时, 将数组表达式在语法层面展开

        let arr1 = [1, 2, 3];
        let arr2 = [4, 5, 6];
        let arr3 = [...arr1, ...arr2, 7, 8];
        console.log(arr3);
        
      • 可以在数组构造时, 将string在语法层面展开

        let arr4 = [...'hello']; // 将字符串转成数组
        console.log(arr4);
        
    • 还可以在构造字面量对象时, 将对象表达式按key-value的方式展开

      // ------  什么样的对象,能够使用 ...
      // ------  - 只有能够遍历的对象,才能使用 ...
      let obj1 = { id: 1, name: 'zs' };
      let obj2 = { nickname: 'lisi', age: 20 };
      let fn = function () {
          this.sayHi = function () {
              console.log('sayHi');
          };
      this.height = '178cm';
      }
      let obj4 = new fn();
      let obj3 = {...obj1, ...obj2, ...obj4};
      console.log(obj3);
      
  • Array.from()

    • 把伪数组转换成数组
    • 伪数组必须有length属性,没有length将得到一个空数组
    • 转换后的数组长度,是根据伪数组的length决定的
let fakeArr = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

let arr = Array.from(fakeArr);
console.log(arr); // ['a', 'b', 'c']

// 转数组的对象必须有length值,因为得到的数组的成员个数是length指定的个数
// 上例中,如果length为2,则得到的数组为 ['a', 'b']

为什么要把它转成数组呢?因为伪数组不能调用数组方法

let arr = Array.from(obj);
console.log(arr); // ["apple", "banana", "pear"]
  • 数组实例的 includes()
    • 判断数组是否包含某个值,返回 true / false
    • 参数1,必须,表示查找的内容
    • 参数2,可选,表示开始查找的位置,0表示开头的位置
    • 语法:
       [].includes(search, [position])
      
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
  • 下面介绍一组语法比较类似的方法

    • forEach() – 遍历数组
    • filter() – 遍历数组,找到满足条件的单元
    • find() – 遍历数组,遍历的过程中,找到满足条件的第一个单元
    • findIndex() – 遍历数组,遍历的过程中,找到满足条件的第一个索引(下标)
    • some() – 遍历数组的过程中,判断数组中是否有满足条件的单元
    • every() – 遍历数组的过程中,判断数组中的单元是否全部满足条件
    • map() – 遍历数组的过程中,使用一个函数来处理数组的每个单元
  • 上述方法的语法:

[].method(function (item, i, self) {
    // item表示数组的单元
    // i 表示数组的下标
    // self 表示当前的数组
});
let arr1 = [8, 2, 7, 10, 5, 9, 4];

filter() – 遍历数组,找到满足条件的单元

// 找到数组中大于5的所有单元
let arr2 = arr1.filter(function (item, i) {
     // return 条件
     return item > 5;
});
console.log(arr2);

find() – 遍历数组,遍历的过程中,找到满足条件的第一个单元

// 查找数组中小于5的第一个值(单元)
let result = arr1.find(item => item < 5);
let result = arr1.find(function (item, i) {
    return item < 5;
});
console.log(result);

findIndex() – 遍历数组,遍历的过程中,找到满足条件的第一个下标

let result = arr1.findIndex(function (item, i) {
    return item < 5;
});
console.log(result);

some() – 遍历数组的过程中,判断数组中是否有满足条件的单元

// 判断一下,数组中是否有大于5的值,如果有,返回true;没有返回false
let result = arr1.some(function (item, i) {
    // return '条件'
    return item > 5
});
console.log(result);

every() – 遍历数组的过程中,判断数组中的单元是否全部满足条件

判断一下,数组中的值,是否全部大于5,如果是,返回true;如果不是,返回false
let result = arr1.every(function (item, i) {
    // return '条件'
    return item > 5
});
console.log(result);

map() – 遍历数组的过程中,使用一个函数来处理数组的每个单元

遍历数组,并且将数组中的每个单元的平方放到一个新数组中
let result = arr1.map(function (item) {
    return item * item;
});
console.log(result);
console.log(arr1);

reduce() – 遍历数组的过程中,累加数组的每个单元

let result = [1, 2, 3, 4].reduce(function (a, b) {
    // console.log(a); // a就是每次累加的结果
    // console.log(b); // 代表数组中的每个单元
    return a * b;
});
/*
起始值: 没有指定起始值,则 a 使用数组的第一个元素 ,所以 a = 1 
第1次循环: a = 1, b = 2; 循环结束后, a = a + b; a = 3;
第2次循环: a = 3, b = 3; 循环结束后, a = a + b; a = 6;
第3次循环: a = 6; b = 4, 循环结束后, a = a + b; a = 10
*/
console.log(result);

// reduce() 的起始值是可以设定的
// [1, 2, 3, 4].reduce(fn, [起始值]);
// let result = [1, 2, 3, 4].reduce(function (a, b) {
//     return a + b;
// }, 100);
// console.log(result);

3.2 String的扩展

  • 模板字符串
    • 模板字符串解决了字符串拼接不便的问题
    • 模板字符串使用反引号 ` 括起来内容
    • 模板字符串中的内容可以换行
    • 变量在模板字符串中使用 ${name} 来表示,不用加 + 符号
let name = 'zs';
let age = 18;
// 拼接多个变量,在模板字符串中使用占位的方式,更易懂
let str = `我是${name},今年${age}`;
// 内容过多可以直接换行
let obj = {name: 'zhangsan', age: 20};
let arr = ['175cm', '60kg'];
let html = `
	<div>
		<ul>
			<li>${obj.name}</li>
			<li>${obj.age + 2}</li>
			<li>${arr[0]}</li>
			<li>${arr[1]}</li>
		</ul>
	</div>
`;
  • includes(), startsWith(), endsWith()
    • includes(str, [position]) 返回布尔值,表示是否找到了参数字符串
    • startsWidth(str, [position]) 返回布尔值,表示参数字符串是否在原字符串的头部或指定位置
    • endsWith(str, [length]) 返回布尔值,表示参数字符串是否在原字符串的尾部或指定位置。
console.log('hello world'.includes('e', 2)); // false 从位置2开始查找e,没有找到
console.log('hello world'.includes('e')); // true

console.log('hello world'.startsWith('h')); // 未指定位置,看开头是否是h,返回true
console.log('hello world'.startsWith('l', 2)); // 指定位置的字符是l,返回true

console.log('hello world'.endsWith('d')); // 未指定位置,结尾是d,返回true
console.log('hello world'.endsWith('r', 9)); // 先截取9个字符,然后看这9个字符串的结尾是不是r。返回true
  • repeat()
    repeat方法返回一个新字符串,表示将原字符串重复n次。
let html = '<li>itheima</li>';
html = html.repeat(10);
  • trim()
    trim() 方法可以去掉字符串两边的空白
console.log('    hello        '.trim()); // hello
console.log('    hello        '); //

3.3 Number的扩展

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

  • Number.parseInt()
  • Number.parseFloat()
console.log(parseInt('123abc'));
// ES6中,将parseInt移植到了Number对象上
console.log(Number.parseInt('123abc'));

3.4 Set

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

  • Set本身是一个构造函数,用来生成 Set 数据结构。
  • Set的特点就是该对象里面的成员不会有重复。
// 1. 基本使用
let s = new Set();
// 得到一个空的Set对象
// 调用add方法,向s中添加几个值
s.add(3);
s.add(7);
s.add(9);
s.add(7); // Set对象中的成员都是唯一的,前面添加过7了,所以这里添加无效

console.log(s.size);
console.log(s); // {3, 7, 9}
  • Set 的成员
    • size:属性,获取 set 中成员的个数,相当于数组中的 length
    • add(value):添加某个值,返回 Set 结构本身。
    • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
    • has(value):返回一个布尔值,表示该值是否为Set的成员。
    • clear():清除所有成员,没有返回值。
// 将一些重复的值加入到Set对象中,看看效果
const s = new Set();
// 使用forEach遍历前面的数组,然后将数组中的每个值都通过Set对象的add方法添加到Set对象中
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
// s = {2, 3, 5, 4}
// 遍历Set对象,发现重复的值只有一份
// for...in  循环中的 i 表示数组的下标,或对象的属性名
// for...of  循环中的 i 表示数组的值,或对象的值
for (let i of s) {
  console.log(i);
}
// 2 3 5 4

另外初始化Set的时候,也可以为其传入数组或字符串,得到的Set对象中的成员不会有重复。

根据这个特点可以完成数组或字符串去重。

// Set 可以通过一个数组初始化
let set = new Set([1, 2, 1, 5, 1, 6]);
console.log(set); //Set(4) {1, 2, 5, 6}
// 数组去重
let arr = [...set]; // 方式一
console.log(Array.from(set)); // from是将伪数组变为数组;方式二
console.log(arr); // [1, 2, 5, 6]

// 完成字符串去重
let str = [...new Set('ababbc')].join('');
console.log(str); // abc

4. 定义对象的简洁方式

let id = 1;
let name = 'zs';
let age = 20;

// 之前定义对象的方案
// let obj = {
//     // 属性: 值
//     id: id,
//     name: name,
//     age: age,
//     fn: function () {
//         console.log(this.age);
//     }
// };

// obj.fn();


// ES6的新方案
let obj = {
    id,  // 属性名id和前面的变量id名字相同,则可以省略 :id
    name,
    nianling: age,
    // 下面的函数是上面函数的简化写法,可以省略 :function  。但是注意这里仅仅是上面函数的简化,不是箭头函数
    fn () {
        console.log(this.name);
    }
};
obj.fn();

5. ECMAScript 6 降级处理 (保留)

5.1 ES 6 的兼容性问题

  • ES6 虽好,但是有兼容性问题,IE7-IE11 基本不支持 ES6
    ES6 兼容性列表
  • 在最新的现代浏览器、移动端、Node.js 中都支持 ES6
  • 后续我们会讲解如何处理 ES6 的兼容性

5.2 ES 6 降级处理

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

  • 降级处理 babel 的使用步骤

    1. 安装 Node.js
    2. 命令行中安装 babel
    3. 配置文件 .babelrc
    4. 运行
  • 安装 Node.js
    官网:https://nodejs.org/en/

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

npm init -y
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 扩展阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值