• 【前端】ECMAScript6从入门到进阶


    【前端】ECMAScript6从入门到进阶

    1.ES6简介及环境搭建

    1.1.ECMAScript 6简介

    在这里插入图片描述

    (1)ECMAScript 6是什么

    ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

    (2)ECMAScript 和 JavaScript 的关系

    ECMAScript是JavaScript的标准,JavaScript是ECMAScript的实现。换句话说,如果说JavaScript是一门语言的话,那么ECMAScript就是这门语言遵循的语法书。

    (3)ES6 与 ECMAScript 2015 的关系

    2011年的时候,ECMAScript 5.1版本发布,ECMA组织就开始准备6.0版本了。但因为这个版本引入的语法功能太多了,所以不可能通过一个版本就将所有功能涵盖。所以,标准委员会决定,标准在每年的6月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,直到下一年的6月份,草案就自然变成了新一年的版本。这样一来,就不需要以前的版本号了,只要用年份标记就可以了。

    就这样ES6的第一个版本就在2015.6正式发布了,正式名称就是《ECMAScript 2015标准》(简称ES2015)。

    1.2.babel工具搭建ES6环境

    采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

    • 首先确保环境中有node
    node安装:http://nodejs.cn/download/
    
    • 1
    • 初始化工程项目
    // 使用默认配置初始化项目
    npm init -y
    
    • 1
    • 2
    • 安装对应的依赖包
    // 本地安装babel-cli及对应的转化规则
    npm install --save-dev babel-cli babel-preset-es2015
    
    // 阿里巴巴定制的镜像源
    npm install -g cnpm --registry=https://registry.npm.taobao.org
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 创建项目目录

      • src目录用于存放编写的es6代码

      • dist目录用于存放由es6转化后的代码

    • 配置babel

    新建.babelrc文件

    // 配置用于转化当前代码的规则集
    {
      "presets": ["es2015"]
    }
    
    • 1
    • 2
    • 3
    • 4

    babel的基本用法

    // -o 参数指定输出文件
    node_modules/.bin/babel src/index.js -o dist/index.js
    
    // -d 参数指定输出目录
    node_modules/.bin/babel src -d dist
    
    • 1
    • 2
    • 3
    • 4
    • 5

    配置package.json文件实时编译

    // 配置启动脚本的命令
    "scripts": {
      // 监听index.js文件,一发生变化就执行babel转译的命令
      "dev": "babel src -w -d dist",
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.新的声明及数据赋值方式

    2.1.变量声明let与const

    作用域就是变量的有效范围,之前只有全局作用域和函数作用域,现在新增块级作用域。es6中新增let和const两种变量声明方式。

    (1)let和const的相同点

    • 只在声明的代码块内有效
    if (true) {
      var a = "a";
    }
    console.log(a);
    // let声明变量,const同理
    if (true) {
      let b = "b";
    }
    console.log(b);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    • 在同一作用域内不允许重复声明

    在这里插入图片描述

    • 没有变量提升,在声明变量前,不能使用该变量
    console.log(a);
    var a = 'a';
    
    console.log(b);
    let b = '1';
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    用var声明的变量会存在变量提升的问题,如果用let或者const就会消除变量提升问题,在遇到未定义的变量直接抛错。

    (2)let和const的区别

    • const用来声明一个只读的变量
    const x = 10;
    x = 13;
    console.log(x);
    
    • 1
    • 2
    • 3

    注意:const声明的变量同时必须立即赋值,如声明的是简单类型的数据,变量的值不可改变。

    在这里插入图片描述

    2.2.ES6新数据类型Symbol

    在ES6之前JavaScript的原始数据类型有Number、String、Boolean、Null、Undefined。ES6中增加新的Symbol独一无二的类型。

    对象的属性名容易产生命名冲突,为保证键名的唯一性,故es6引入Symbol这种新的原始类型数据,确保创建的每个变量都是独一无二的。

    • Symbol类型的数据是类似字符串的数据类型。
    • 由于Symbol函数返回的值是原始类型的数据,不是对象,故Symbol函数前不能使用new命令,否则会报错。
    let s = Symbol();
    console.log(typeof s);
    
    • 1
    • 2

    在这里插入图片描述

    let s1 = Symbol();
    let s2 = Symbol();
    console.log(s1===s2);
    
    let l1 = Symbol('lixiang');
    let l2 = Symbol('lixiang');
    console.log(l1===l2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    定义对象的唯一属性名

    // 在对象里用Symbol作为属性名的三种写法
    let s = Symbol();
    
    // 第一种方式: 借助数组读取s变量,此时不能用点运算符,点运算符默认后面的参数是字符串
    let a = {};
    a[s] = 'lixiang'
    
    // 第二种方式: 构造时声明
    let a = {
      [s]: 'lixiang'
    }
    
    // 第三种 Object.defineProperty
    let a = {};
    Object.defineProperty(a, s, { value: 'lixiang' });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    定义常量

    const s = Symbol("李祥");
    
    • 1

    在这里插入图片描述

    2.3.解构赋值详解

    (1)什么是解构赋值

    解构赋值可以理解为赋值操作的语法糖,它是针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。代码书写上言简意赅,语义明确,也方便了对象数组的读取操作。

    ES6中只要某种数据可以循环迭代,都可以进行解构赋值。

    (2)数组解构

    // 变量多时,对应不上的变成undefined
    let [a, b, c] = [1, 2];
    console.log(a, b, c);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    // 变量默认值,声明变量时将c默认成6
    let [a, b, c = 6] = [1, 2];
    console.log(a, b, c);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    // 分割数组,将1赋值给a,2,3成一个新数组
    let [a, ...other] = [1, 2, 3];
    console.log(a, other);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    // 空内容,将a赋值为1,b赋值为3
    let [a,,b] = [1, 2, 3];
    console.log(a, b);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    (3)对象解构

    //1赋值为a,2赋值为b
    let { a, b } = { a: 1, b: 2 };
    console.log(a, b);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    //重命名
    let { a: aa, b: bb } = { a: 1, b: 2 };
    console.log(aa, bb);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    (4)读取接口返回的数据

    function fun() {
      return {
        name: "张三",
        hobby: [
          {
            title: "篮球",
          },
          {
            title: "唱",
          },
          {
            title: "RAP",
          },
          {
            title: "跳",
          },
        ],
      };
    }
    let {
      name,
      hobby: [{ title }],
    } = fun();
    console.log(name, title);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.ES6新增的数据操作方法

    3.1.ES6提供的新的字符串方法

    (1)新增的API

    方法描述
    includes(string, index)判断字符串中是否包含指定字符串,返回值是布尔值
    startsWith(string, index)判断字符串的开头是否包含指定字符串,返回值是布尔值
    endsWith(string, index)判断字符串的尾部是否包含指定字符串,返回值是布尔值
    repeat(n)repeat() 方法返回一个新字符串,表示将原字符串重复n 次。
    padStart(length, str)字符串补齐,用于头部补全
    padEnd(length, str)字符串补齐,用于尾部补全
    //判断str是否包含an
    let str = 'lixiang';
    console.log(str.includes('an'));
    //从下标为5的字符开始判断是否含an
    console.log(str.includes('an',5));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    //判断str是否以l开头
    let str = 'lixiang';
    console.log(str.startsWith('l'));
    //从下标为3的字符开始判断是否以l开头
    console.log(str.startsWith('l',3));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    //判断str是否以g结尾
    let str = 'lixiang';
    console.log(str.endsWith('g'));
    //从下标为3的字符开始判断是否以g结尾
    console.log(str.startsWith('g',3));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    //入参数字为2,重复两次
    let str = 'lixiang';
    console.log(str.repeat(2));
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    //在lixiang前面补a,补够10位
    let str = 'lixiang';
    console.log(str.padStart(10, 'a'));
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    //在lixiang后面补a,补够10位
    let str = 'lixiang';
    console.log(str.padEnd(10, 'a'));
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    (2)模板字符串

    在ES5的时候拼接字符串我们往往这样写。

    const name = '李祥';
    const age = 18;
    const hobbies = '写代码';
    
    • 1
    • 2
    • 3
    const str = '我叫'+name+',今年'+age+'岁,'+'喜欢'+hobbies+'。'
    
    • 1

    在ES6中新引入的模版字符串,写法如下。

    const str = `我叫${name},今年${age}岁,喜欢${hobbies}`
    
    • 1
    console.log(str);
    
    • 1

    在这里插入图片描述

    (3)使用模板字符串的注意事项

    • 使用模板字符串表示多行字符串时,所有的空格和缩进都会被保留在输出之中。
    • 模板字符串中引入变量,要用 ${变量名} 这样的形式引入才可以。
    • 模板字符串中的${…} 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算、可以引用对象属性、可以调用函数、可以甚至还能嵌套,甚至还能调用自己本身。
    3.2.ES6扩展运算符的使用

    (1)深拷贝一维数组

    const list = [1, 2, 3, 4, 5];
    const listCopy = [...list];
    console.log(listCopy);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    (2)分割数组

    const list = [1, 2, 3, 4, 5];
    const [, ...list1] = list;
    console.log(list1);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    (3)将数组转化成参数传递给函数

    const list = [1, 2];
    function fun(a, b) {
      console.log(a + b);
    }
    fun(...list);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    3.3.ES6数组的扩展方法

    (1)fill:替换数组中的元素,会改变原数组。想要不改变原数组的值,可以采用深拷贝。

    const list = [1, 2, 3, 4, 5];
    //全部替换成6
    const list1 = [...list].fill(6);
    //下标从1开始到下表为4之间左闭右开,全部替换成6
    const list2 = [...list].fill(6, 1, 4);
    console.log(list);
    console.log(list1);
    console.log(list2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    (2)find:查询数组中符合条件的元素。

    const list = [
      { name: "李祥", age: 15 },
      { name: "张三", age: 10 },
      { name: "李四", age: 19 },
      { name: "王武", age: 20 },
    ];
    const result = list.find(function (item) {
      return item.name === "李祥";
    });
    console.log(result);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    (3)findIndex:查询数组中符合条件的元素的索引。

    const result = list.findIndex(function (item) {
      return item.name === "李祥";
    });
    console.log(result);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    (4)flat:用于合并数组。

    const list = [1, 2, 3, [4, 5, 6, [ 7, 8]]];
    const list2 = list.flat(2);
    console.log(list2);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    (5)filter:过滤出符合条件的元素,与find不同的是filter返回一个数组。

    const result = list.filter(function (item) {
      return item.name === "李祥";
    });
    console.log(result);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    3.4.ES6数组中map方法

    map用于将一个类型的数字转换成另外一个类型。

    const list = [
      { name: "李祥", age: 15 },
      { name: "张三", age: 10 },
      { name: "李四", age: 19 },
      { name: "王武", age: 20 },
    ];
    //遍历集合中每一项,创建obj对象,将原对象属性复制到新的obj中
    //然后给obj增加一个属性state
    const mapList = list.map(function (i) {
      let obj = {};
      //对象拷贝
      Object.assign(obj, i);
      obj.sex = 0;
      return obj;
    });
    console.log(mapList);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    3.5.ES6对象的新特性

    创建对象

    const a = {
      name: 'lixiang',
      age: 21,
      address: {
        city: 'BeiJing',
        town: 'ChangYang'
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (1)深拷贝简单对象

    const b = { ...a };
    console.log(b);
    
    • 1
    • 2

    在这里插入图片描述

    (2)给对象设置默认值

    const b = { ...a, name: 'zhangsan' };
    console.log(b);
    
    • 1
    • 2

    在这里插入图片描述

    (3)合并对象

    const b = { sex:'0' };
    const c = {...a,...b}
    console.log(c);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    (4)属性初始化、方法的简写

    在这里插入图片描述

    (5)Object新增的方法

    • Object.is:判断两个对象是否相等
    let res = Object.is({name:'lx'}, {name:'lx'});
    console.log(res);
    let res1 = Object.is(NaN, NaN);
    console.log(res1);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    • Object.assign:对象复制
    let a = { name: 'lx', age: 24 };
    let b = {};
    let c = Object.assign(b, a);
    console.log(c);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    • Object.keys:获取对象所有的key
    let a = { name: 'lx', age: 24 };
    const arr = Object.keys(a);
    console.log(arr);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    • Object.values:获取对象所有的value
    let a = { name: 'lx', age: 24 };
    const arr = Object.values(a);
    console.log(arr);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    • Object.entries:获取key和value
    let a = { name: 'lx', age: 24 };
    const arr = Object.entries(a);
    console.log(arr);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    3.6.ES6新增Map与WeakMap

    JavaScript中的对象,实质就是键值对的集合,但是在对象里却只能用字符串作为键名。在一些特殊的场景里就满足不了我们的需求了,正因为此,Map这一数据提出了,它是JavaScript中的一种更完善Hash结构。

    Map对象:用于保存键值对,任何值(对象或者原始值)都可以作为一个键名或一个值。

    • 属性及方法
    属性/方法作用例子
    size返回键值对的数量m.size
    clear()清除所有键值对m.clear()
    has(key)判断键值对中是否有指定的键名,返回值是布尔值m.has(key)
    get(key)获取指定键名的键值,如不存在则返回undefinedm.get(key)
    set(key, value)添加键值对,如键名已存在,则更新键值对m.set(key, value)
    delete(key)删除指定键名的键值对m.delete(key)

    (1)创建一个Map

    //创建一个空map
    let map = new Map();
    //创建一个带有默认值的map
    let mapDef = new Map([
        ['name','lx'],
        ['age',12]
    ]);
    console.log(map);
    console.log(mapDef);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    (2)API演示

    //创建一个空map
    let map = new Map();
    //map中增加一个元素
    map.set('name','lx');
    map.set('age',20);
    console.log(map);
    //map中修改一个元素
    //map中set方法如果有key则覆盖,没有则新增
    map.set('name','zs');
    console.log(map);
    //返回键值对的数量
    console.log(map.size);
    //判断是否有某个key
    console.log(map.has('name'));
    //获取某个key的value
    console.log(map.get('name'));
    //删除某个key
    map.delete('name');
    console.log(map);
    //清空
    map.clear();
    console.log(map);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    (3)遍历器生成函数

    const keys = map.keys();
    const values = map.values();
    const entries = map.entries();
    console.log(Array.from(keys));
    console.log(Array.from(values));
    console.log(Array.from(entries));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    WeakMap:只接受对象作为键名,而且无法遍历

    const weakMap = new WeakMap([[{ name: 'lx' ,age: 21},{id:1,hobby:'唱、跳、rap、篮球'}]]);
    console.log(weakMap);
    
    • 1
    • 2

    在这里插入图片描述

    在这里插入图片描述

    3.7.ES6新增Set与WeakSet

    Set是ES6给开发者提供的一种类似数组的数据结构,可以理解为值的集合。它和数组的最大的区别就在于: 它的值不会有重复项。

    Set保证成员值唯一,用于集合去重。

    • 属性及方法
    属性/方法作用例子
    add新增元素s.add(key)
    size返回成员个数s.size
    clear()清除所有成员s.clear()
    has(value)判断键值对中是否有指定的值,返回值是布尔值s.has(key)
    delete(value)删除指定值s.delete(key)

    (1)创建一个Set

    const a = { name: 'lx' };
    const set = new Set([a]);
    console.log(set);
    
    const list = new Set([1, 2, 3, 4]);
    console.log(list);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    (2)API演示

    const set = new Set([1, 2, 3, 4]);
    console.log(set);
    //获取set长度
    console.log(set.size);
    //判断是否存在2元素
    console.log(set.has(2));
    //删除2元素
    set.delete(2);
    console.log(set.has(2));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    WeakSet:数组成员必须是对象

    • WeakSet结构也提供了add( ) 方法,delete( ) 方法,has( )方法给开发者使用,作用与用法跟Set结构完全一致。
    • WeakSet 结构不可遍历。因为它的成员都是对象的弱引用,随时被回收机制回收,成员消失。所以WeakSet 结构不会有keys( ),values( ),entries( ),forEach( )等方法和size属性。
    3.8.Array与Set的转换
    // 数组转set
    const list = [1, 2, 3];
    const set = new Set(list);
    console.log(set);
    
    // set转数组
    const arr = Array.from(set);
    console.log(arr);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    3.9.Object与Map的转换
    // 对象转map
    const obj = { nane: 'lx', age:24 };
    const map = new Map(Object.entries(obj));
    console.log(map);
    
    // map转对象
    const obj1 = Object.fromEntries(map);
    console.log(obj1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.ES6新增高阶知识点

    4.1.ES6中新增代理Proxy

    (1)Proxy简介

    正如Proxy的英译"代理"所示,Proxy是ES6为了操作对象引入的API。它不直接作用在对象上,而是作为一种媒介,如果需要操作对象的话,需要经过这个媒介的同意。

    (2)使用方式

    /* @params
    ** target: 用Proxy包装的目标对象
    ** handler: 一个对象,对代理对象进行拦截操作的函数,如set、get
    */
    let p = new Proxy(target, handler)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (3)案例实战

    const house = {
      name: '三室一厅-次卧',
      price: 1000,
      phone: '18823139921',
      id: '20230131',
      state: '**',
    };
    
    const handle = {
      get: function (obj, key) {
        switch (key) {
          case 'price':
            return obj[key] + 500;
          case 'phone':
            return obj[key].substring(0, 3) + '****' + obj[key].substring(7);
          default:
            return obj[key];
        }
      },
      set: function (obj, key, value) {
        if (key === 'state') {
          obj[key] = value;
        }
      },
    };
    
    const houseproxy = new Proxy(house, handle);
    console.log(houseproxy.id);
    console.log(houseproxy.phone);
    console.log(houseproxy.price);
    houseproxy.state='****';
    console.log(houseproxy.state);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    4.2.ES6中新增反射Refect

    (1)Reflect简介

    与Proxy相同,ES6引入Reflect也是用来操作对象的,它将对象里一些明显属于语言内部的方法移植到Reflect对象上,它对某些方法的返回结果进行了修改,使其更合理,更具语义化,并且使用函数的方式实现了Object的命令式操作。

    • 属性及方法
    属性/方法作用
    Reflect.apply(target, thisArg, args)对一个函数进行调用操作,同时可以传入一个数组作为调用参数。
    Reflect.construct(target, args)对构造函数进行 new 操作,相当于执行 new target(…args)。
    Reflect.get(target,name, receiver)获取对象身上某个属性的值,类似于 target[name]。如果没有该属性,则返回undefined。
    Reflect.set(target, name,value, receiver)Reflect.defineProperty方法基本等同于Object.defineProperty,直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,不同的是,Object.defineProperty返回此对象。而Reflect.defineProperty会返回布尔值
    Reflect.has(target,name)判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
    Reflect.ownKeys(target)返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable影响, Object.keys返回所有可枚举属性的字符串数组).
    Reflect.isExtensible(target)判断一个对象是否是可扩展的(是否可以在它上面添加新的属性),类似于 Object.isExtensible()。返回表示给定对象是否可扩展的一个Boolean 。(Object.seal 或 Object.freeze 方法都可以标记一个对象为不可扩展。)
    Reflect.preventExtensions(target)让一个对象变的不可扩展,也就是永远不能再添加新的属性。
    4.3.Proxy实现数据双向绑定

    (1)需求

    实现一个双向的数据绑定。

    在这里插入图片描述

    (2)实现

    • 编写html代码
    <body>
        请输入内容:<input type="text" id = "input"/><br/>
        实时内容展示:<span id = "span">span>
        <script src="./js/index.js">script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 编写js代码
    // 获取dom节点
    const input = document.getElementById("input");
    const span = document.getElementById("span");
    //定义双向绑定的对象
    let obj = {};
    
    //定义代理对象的handle方法
    const handle = {
      get: function (target, key) {
        return target[key];
      },
      set: function (target, key, value) {
        if (key === "text" && value) {
          span.innerHTML = value;
          return (target[key] = value);
        }
      },
    };
    
    //创建代理对象
    const proxy = new Proxy(obj, handle);
    
    //创建键盘的监听事件
    input.addEventListener("keyup", function (e) {
      proxy.text = e.target.value;
      console.log(proxy.text);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    5.函数的扩展、类及模块化

    5.1.函数参数的扩展

    (1)函数参数可设置默认值

    //求和方法,当a和b都不传值时,默认都为1
    function sum(a = 1, b = 1) {
      return a + b;
    }
    console.log(sum());
    console.log(sum(3));
    console.log(sum(3,5));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    (2)rest参数,可变参数

    //求和方法,可变参数
    function sum(...rest) {
        let num = 0;
        rest.forEach((e)=>{
            num+=e;
        })
      return num;
    }
    console.log(sum(...[1,2]));
    console.log(sum(...[1,2,4]));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    5.2.ES6新增箭头函数

    (1)箭头函数简介

    ES6中允许使用=>来定义函数。箭头函数相当于[匿名函数,并简化了函数定义。

    箭头函数在语法上比普通函数简洁多。箭头函数就是采用箭头=>来定义函数,省去关键字function。

    无参:()=>{},等同于:function (){}
    有参:(a,b)=>{},等同于:function (a,b){}
    
    • 1
    • 2

    (2)箭头函数不绑定this

    //箭头函数this指当前块级作用域
    const obj = {
      num: 10,
      sum() {
        setTimeout(() => {
          console.log(this.num);
        }, 1000);
      },
    };
    obj.sum();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    如果不是箭头函数,setTimeout()函数调用指的是当前window。

    const obj = {
      num: 10,
      sum() {
        setTimeout(function (){
          console.log(this);
        }, 1000);
      },
    };
    obj.sum();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    (3)什么情况下不能箭头函数

    • 定义对象的方法
    const obj = {
      num: 10,
      sum:() => {
        setTimeout(() => {
          console.log(this.num);
        }, 1000);
      },
    };
    obj.sum();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    • 箭头函数没有arguments
    const fun = () => {
      console.log(arguments);
    };
    fun();
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    • 定义构造函数
    const Car = () => {
      console.log(this);
    };
    let car = new Car();
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    • 定义DOM事件的回调函数
    const span = document.getElementById("span");
    span.addEventListener("click", () => {
      console.log(this);
      this.innerHTML = "触发事件";
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    在这里插入图片描述

    const span = document.getElementById("span");
    span.addEventListener("click", function () {
      console.log(this);
      this.innerHTML = "触发事件";
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    5.3.ES6中新引入类的概念

    ES6之前javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。

    (1)定义类

    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
      sayHello() {
        console.log(`我是${this.name},今年${this.age}`);
      }
    }
    const person = new Person("张三", 18);
    person.sayHello();
    console.log(person);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    (2)类的继承,重写父类的方法

    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
      hello() {
        console.log(`我是${this.name},今年${this.age}`);
      }
    }
    
    class Student extends Person {
      //子类重写父类属性
      constructor(name, age, sex) {
        super(name, age);
        this.sex = sex;
      }
      hello() {
        console.log(`我是${this.name},今年${this.age}岁,性别:${this.sex === '1'?'男':'女'}`);
      }
    }
    
    const person = new Student('张三', 18,'1');
    person.hello();
    console.log(person);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    (3)静态方法和静态属性

    //静态方法和静态属性只能由类名进行调用
    class Person {
      static eyes = '眼睛';
      static hello(){
        console.log(`我是${this.name}`);
      }
    }
    
    console.log(Person.eyes);
    Person.hello();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    5.4.ES6新增模块化开发

    ES6之前是没有类的概念的,也就没有模块这一说法。理想情况下,开发者应该只注重核心业务的开发,对于其他有一定通用性的业务可以直接引入,也就是模块。多人开发,本应如此。

    • CommonJS:Commonjs是作为Node中模块化规范以及原生模块面世的。
    • AMD和RequireJs:AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成之后(前置依赖),这个回调函数才会运行。

    Import 和 export案例

    • export.js
    const name = '李祥';
    
    function hello(){
      console.log('hello word');
    }
    
    class Car{
      constructor(name){
        this.name=name;
      }
      run(){
        console.log(this.name+'跑起来了');
      }
    }
    
    export default{
      name,
      hello,
      Car,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • Import.js
    import test from './export.js';
    console.log(test.name);
    test.hello();
    
    • 1
    • 2
    • 3
    • html中js引入要改成module类型
    <script src="./js/import.js" type="module"></script>
    
    • 1

    在这里插入图片描述

    6.ES6改进异步编程

    6.1.Promise简介及案例

    (1)什么是回调地狱

    当异步操作想要有顺序时,只能在一个异步成功以后的回调函数里面嵌套另一个异步的操作,如果嵌套的层数过多就形成了回调地狱。

    回调地狱的弊端:后期代码维护比较困难。

    promise就是用来解决回调地狱。

    promise封装了异步操作。创建一个promise对象,写一个函数作为参数,这个函数参数有两个参数,分别是resolve和reject。函数内部写异步操作,成功调resolve,失败调reject。这时promise对象就可以知道异步操作的状态。p.then(成功执行)p.catch(失败执行)。

    promise本质就是一个状态机,记录异步内部操作的状态。

    在es6之前写法代码耦合,出错时,无法排除。

    function request() {
      axios.get("a.json").then((res) => {
        if (res && res.data.code === 0) {
          console.log(res.data.data.data);
          axios.get("b.json").then((res) => {
            if (res && res.data.code === 0) {
              console.log(res.data.data.data);
              axios.get("c.json").then((res) => {
                console.log(res.data.data.data);
              });
            }
          });
        }
      });
    }
    
    request();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 简单说Promise就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
    • 从语法上说,Promise 是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。
    • Promise 是一个构造函数,提供统一的 API,Promise里不仅可以存放着异步的代码,也可以放同步的代码。
    // 准备阶段
    new Promise((resolve, reject) => {})
    
    // 成功状态
    new Promise((resolve, reject) => {
      resolve('成功'); // 同步代码
    }).then((res) => {
      console.log(res);
    });
    
    // 失败状态
    new Promise((resolve, reject) => {
      reject('失败');
    }).catch((err) => {
      console.log(err);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    • Promise对象的状态不受外界影响

      • pending 初始状态

      • resolve 成功状态

      • rejected 失败状态

        Promise 有以上三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态

    • Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成resolve或者由pending变成rejected

    (2)Promise解决回调地狱案例

    //先定义三个函数
    function requestA() {
      return new Promise((resolve, reject) => {
        axios.get("a.json").then((res) => {
          resolve(res);
        });
      });
    }
    
    function requestB() {
      return new Promise((resolve, reject) => {
        axios.get("b.json").then((res) => {
          resolve(res);
        });
      });
    }
    
    function requestC() {
      return new Promise((resolve, reject) => {
        axios.get("c.json").then((res) => {
          resolve(res);
        });
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    function request() {
      requestA().then((res) => {
          console.log(res);
          return requestB();
        }).then((res) => {
          console.log(res);
          return requestC();
        }).then((res) => {
          console.log(res);
        });
    }
    request();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (3)Promise.all方法

    • Promise.all 实际上是一个函数,它接受一个 promise 数组并返回一个 promise。然后当所有的 promise 都完成时会得到结果数组或者当其中一个被拒绝时会抛出错误。
    • 返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
    function requestAll() {
      Promise.all([requestA(), requestB(), requestC()])
        .then((res) => {
          console.log(res);
        })
        .catch((err) => {
          console.log(err);
        });
    }
    requestAll();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (4)Promise.race方法

    Promse.race就是赛跑的意思,传入的promise 数组里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

    function requestRace() {
      Promise.race([requestA(), requestB(), requestC()])
        .then((res) => {
          console.log(res);
        })
        .catch((err) => {
          console.log(err);
        });
    }
    requestRace();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    6.2.优雅的异步编程async

    (1)什么是async

    async是异步的简写,Generator(生成器)的语法糖,用于声明一个函数是异步函数。

    async function sum(a,b) {
      await console.log(a+b);
    }
    sum(1,2);
    
    • 1
    • 2
    • 3
    • 4

    async 写在函数前,返回一个Promise对象。

    async await改造promise.then异步调用。

    async function request() {
      try {
        const a = await requestA();
        const b = await requestB();
        const c = await requestC();
        console.log(a, b, c);
      } catch (err) {
        console.log(err);
      }
    }
    request();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    机器学习 l2正则化--岭回归
    Three.js 绘制动态模型
    用Python写了一个水果忍者小游戏
    misc刷题记录2[陇剑杯 2021]
    Spring AOP
    写给儿子的一封信
    /system/bin/sh: disable-verity: not found
    vscode用密钥文件连接ssh:如果一直要输密码怎么办
    vertx的学习总结4之异步数据和事件流
    百度AI给出MFC使用进度条的例子
  • 原文地址:https://blog.csdn.net/weixin_47533244/article/details/133282741