• 李炎恢ECMAScript6 / ES6+(一)


    开头

    这是根据李炎恢老师的视频,把es6走了一遍,这是我根据他的讲义整理成md格式的文档,同时贴有代码运行结果图,以及对他的文档整理成合理的目录方便快速找到相关的知识点,有需要的收藏,第二部分我到时候会贴在这里。

    李炎恢ECMAScript6 / ES6+(二)

    01. ECMAScript6 简介和历史

    学习要点:
    1.ES6 简介
    2.ECMAScript 历史
    3.学习和创建 Demo
    本节课我们来开始了解 ECMAScript6(简称 ES6),着重了解它的标准和历史。

    一.ES6 简介

    1.ECMAScript6 简称 ES6,是 JavaScript 语言的下一代标准;

    2.ES6 的目标是为了实现更加复杂的应用,成为企业级的开发语言;

    3.ECMAScript 属于标准制定,而 JavaScript 属于语法实现;

    4.ES6 于 2015 年 6 月发布,正式名称为 ECMAScript2015;

    5.也就是说 ES6 是 ECMAScript 的一个版本,但却没有 6.x 的说法;

    6. ES2016(ES7)、ES2017(ES8)、ES2018(ES9)、ES2019(ES10)版本路线;

    7.初学者可能会蒙圈,到底学哪个版本?这个问题,根本不重要~;

    8.因为它和软件版本不同,需要各大浏览器兼容性保持一致和兼容,超花时间;

    9.我们可以通过这个链接查看 ES6 兼容性情况,并且还有 ES5 和 ES2016+:

    http://kangax.github.io/compat-table/es6/

    10.经过五年多的发展兼容,ES6 大部分标准得以稳定,或者说 ES6 只是一个泛指;

    11.泛指下一代的标准,可以理解为涵盖 ES2015、ES2016、ES2017、ES2018 等;

    12. 即使快到 2020 年,很多 JS 工具为了更好兼容,有 ES6 转换 ES5 的选项;

    二.ECMAScript 历史

    这里,我们给出一张表格,了解一下 ES6 及之前的一些版本情况:

    版本说明
    ES1.01997 年发布
    ES2.01998 年 6 月份发布
    ES3.01999 年 12 月份发布
    ES4.02000 年没发布的了(废弃了)
    ES4.02007 年 10 月草案发布(预计次年 8 月发布正式版)
    ES3.12008 年 7 月发布(吵架把 ES4.0 吵成 3.1 了)
    ES5.02009 年 12 月发布(3.1 改成了 5.0)
    ES5.12011 年 6 月份发布
    ES62013 年 3 月草案冻结
    ES62013 年 12 月草案发布

    三.学习和创建 Demo

    1.课程适合有 JavaScript 基础的同学,比如学过之前 ES5 版本的 149 课时的 JS;

    2.我们这里重点讨论 ES6 或 ES6+的知识,不会讲解 JavaScript 基础;

    3.至于基于 ES6+的 JavaScript 基础课程,后面会分阶段,重新录制,时间不定;

    4.为了后面代码课程的便利,我们把 ES6 的项目搭建好;

    5.在 C 盘创建 ES6 目录,搭建 01 目录,写入标准的 HTML5 和 JS 文件,测试运行;

    02. let 和 const 声明

    学习要点:
    1.let 声明
    2.const 声明
    本节课我们来开始学习 ES6 中的 let 和 const 两种声明方式。

    一.let 声明

    1.ES6 新增了一个新的变量声明:let,它和 var 变量声明非常的类似;

    2.首先创建一个块级区域,分别使用 let 和 var 声明一个变量;

    //块级区域
    {
    var value = 10;
    let count = 20;
    }
    console.log(value); //10
    console.log(count); //引用错误
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    3.上述例子直观表现为:1.var 出了块级区域有效;2.let 出了块级区域无效

    4.var 声明具有变量提升能力,不管在哪里声明,均视为作用域顶部声明;

    5.let 声明不具备变量提升能力,离开区块的作用域后,则变量立刻失效;

    6.那么,哪种更好?let 更适合局部变量,非常容易掌控且不会导致凌乱;

    7.变量提升能力还带来一个区别,就是声明之前使用时,产生的结果不同;

    console.log(value);//undefined
    var value; //变量提升导致逻辑怪异
    
    • 1
    • 2

    8.上面例子对比中,var 在后面声明,前面输出的值从逻辑上较为怪异;

    按道理来说,var value; 应该在console.log前面然后正常输出undefined才对。

    再来看看count

    console.log(count);
    let count;
    
    • 1
    • 2

    在这里插入图片描述

    我们发现这个就对了,符合正常的思维逻辑。

    那我们放到前面再看呢?

    let count;
    console.log(count); //undefined
    
    • 1
    • 2

    在这里插入图片描述

    9.在一个区块内部,只要使用 let 声明,这个区域就形成了封闭的作用域;

    10.如果在 let 声明前使用变量,这段区域被称为“临时死区(或暂时性死区)”;

    if (true) {
    //死区开始
    value = 20;
    console.log(value);
    //死区结束
    let value = 10;
    console.log(value);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    11.“临时死区”简称:TDZ,这段区域使用 typeof 也会报错

    console.log(typeof value);
    let value;
    
    • 1
    • 2

    在这里插入图片描述

    12.一般情况下,typeof 来判断未声明的变量,只会输出 undefined;

    13.var 声明可以重复声明同一个变量,后面会取代前一个变量

    var value = 10;
    var value = 20;
    console.log(value);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    14.let 声明不可以重复声明一个变量,会直接报错,就算其中一个是 var

    let value = 10;
    let value = 20;
    console.log(value);
    
    var value = 10;
    let value = 20;
    console.log(value);
    
    let value = 10;
    var value = 20;
    console.log(value);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    15.当然,如果一个在作用域外部,一个在作用域内部,则可以并存

    let value = 20;
    {
        let value = 10; //不建议相同,会乱的
    }
    console.log(value);//20
    
    • 1
    • 2
    • 3
    • 4
    • 5

    16.在循环中,var 和 let 的区别尤为明显,let 只在循环内部有效;

    for (var i = 0; i < 10; i++) {
        console.log(i);
    }
    console.log(i); //var 声明,则 10;let 声明,报错
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    for (let i = 0; i < 10; i++) {
        console.log(i);
    }
    console.log(i); //var 声明,则 10;let 声明,报错
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    17. 如果在循环体内设置函数方法,体外输出 var 会得到不想要的值

    var list = [];
    for (var i = 0; i < 10; i++) { //把这里改成 let,则会得到想要的值
    list[i] = function () {
    console.log(i);
    }
    }
    list[5](); //这里不管设置多少,结果都是 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    var list = [];
    for (let i = 0; i < 10; i++) { //把这里改成 let,则会得到想要的值
        list[i] = function () {
            console.log(i);
        }
    }
    
    list[5](); //5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    二.const 声明

    1. const 声明的作用是:创建一个只读的常量,一旦声明不可改变;

    2.和 let 声明一样,const 声明的常量无法提升,也存在临时死区;

    3.和 let 不同的是,const 声明后必须立刻赋值,否则会报错;

    const PI = 3.14;
    console.log(PI); //常量约定俗成大写
    
    • 1
    • 2

    03. 块级作用域

    学习要点:
    1.全局作用域
    2.块级作用域
    本节课我们来开始学习全局作用域和块级作用域的问题。

    一.全局作用域

    1.如果是 window 对象的内置属性,则输出默认值,而非内置则是undefined;

    console.log(window.name);//因为name是window的一个属性,打印结果是一个空字符串
    console.log(window.abcd);//它不是window的自带属性,所以打印结果是undefined
    
    • 1
    • 2

    在这里插入图片描述

    2.浏览器环境有一个顶层对象 window,其属性和 var 的全局变量等价;

    console.log(window.name);
    console.log(window.abcd);
    
    
    
    console.log(name);//如果直接使用则还是空字符串
    console.log(abcd);//这里直接使用,它既不是windown对象的属性,也没有声明,则报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    console.log(window.name === name);//得到结果他们是等价的
    
    • 1

    在这里插入图片描述

    再看一个例子,我们此时声名一个非window对象的变量。再看看

    var abcd = 10;
    console.log(abcd);
    console.log(window.abcd);
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    因此更加印证了标题的结论,简单来说,var声明的全局变量 它就是 window 的属性。

    3.var 如果设置了 window 对象的内置属性作为变量,则会直接覆盖;

    var name = 'es6';
    console.log(name);
    console.log(window.name);//被覆盖,所以这里造成了污染
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    4.结论

    1.从上面的例子可以看出,对比现在模块化编程的理念,显得格格不入;
    2. 从 WebStorm 环境中根本无法识别 window,因为它是 Node 环境,不支持对象;
    3.而 Node 环境的顶层对象 global,只不过其它环境均不支持,不深入展开;

    二.块级作用域

    1. ES6 之前只有全局作用域和函数作用域,并没有所谓的块级作用域,

    2.上一节课的循环体和条件体就是块级作用域,也就是两个花括号区域:{}

    3.如果在块级区域不使用 let,就会造成全局变量污染的问题

    4.{{{…}}}块级作用域支持多层嵌套,每一层均为封闭的,只作用于此

    {{{{
    {let value = 10;}
    console.log(value); //报错
    }}}}
    
    • 1
    • 2
    • 3
    • 4

    5.在 ES6 之前,采用自我立即执行匿名函数的方式来防止变量污染

    (function () {
        var value = 10;
    }());
    console.log(value); //报错
    
    //下面这个就把上面给代替了,方便了很多
    {
        let value = 10;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6.ES6 之前函数必须在顶层声明,但违反并不报错,而 ES6 则开始支持

    7.只不过块级作用域内的函数声明,还是可以在全局可访问,并没有封闭

    {
    function fn() {
    console.log('块级函数');
    }
    }
    fn(); //正常访问
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    此时我想做一个只能在块级内部才能访问到的函数,怎么做?

    {
        let fn = function (){
            console.log('块级函数')
        }
    }
    
    fn();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时就找不到了,变成了一个私有函数,它只能在块级作用域内部使用
    let 结合 函数表达式

    {
        let fn = function (){
            console.log('块级函数')
        }
    
        fn();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    04. 数组和对象的解构

    学习要点:
    1.数组解构
    2.对象解构
    本节课我们来开始学习 ES6 中数组和对象解构赋值的方法。

    一.数组解构

    1.ES6 提供了对数组和对象的字面量提取相关数据的方法:解构操作

    2.为何要使用解构操作?是因为 JSON 格式的普及,导致大量数据提取工作

    3.而这种提取过程,在 ES6 的解构语法中,带来了极大的便捷性

    4.数组解构赋值,有两种基本的写法:1.分行解构;2 单行解构;

    1.分行解构
    let info = ['Mr.Lee', 100, '男']; //数组赋值
    let [name, age, gender] = info; //数组解构赋值
    console.log(name);
    console.log(age);
    console.log(gender);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    2.如果作为一个变量来申明的话,可以省略一个 let
    let info = ['Mr.Lee', 100, '男'],[name, age, gender] = info; //数组解构赋值
    console.log(name);
    console.log(age);
    console.log(gender);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    3.单行解构

    这里连变量都省掉了。

    let [name, age, gender] = ['Mr.Lee', 100, '男'];
    console.log(name);
    console.log(age);
    console.log(gender);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    5.从上面的例子分行或单行,都可以确定必须一一完美匹配才可以正确赋值

    let [name, age, gender] = ['Mr.Lee', [100, '男']];
    console.log(name);
    console.log(age);
    console.log(gender);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    数组层次也需要匹配,才能获取到正确的值

    // let [name, age, gender] = ['Mr.Lee', [100, '男']];
    let [name, [age, gender]] = ['Mr.Lee', [100, '男']];
    console.log(name);
    console.log(age);
    console.log(gender);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    6.如果我只需要其中一个值,不需要的变量使用占位符来填充即可

    let [, , gender] = ['Mr.Lee', 100, '男'];
    
    console.log(gender);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    7.在变量解构时,可以在数组的元素中设置一个默认值

    let [name, age, gender = '男'] = ['Mr.Lee', 100];
    console.log(name);
    console.log(age);
    console.log(gender);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    8.还有一种…var 的语法,可以将没有赋值的内容都赋值给这个变量

    let [name, ...other] = ['Mr.Lee', 100, '男'];
    console.log(name);
    console.log(other);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    二.对象解构

    1.对象的解构方式和数组大同小异,定义一个对象字面量,然后解构赋值

    //定义对象字面量
    let obj = {
        name : 'Mr.Lee',
        age : 100,
    };
    //解构对象字变量
    let {name, age} = obj; //或({name, age} = obj);
    console.log(name,age);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    2.如果说,解构的变量名是已经存在的变量,那会导致覆盖

    let obj = {
    name : 'Mr.Lee',
    age : 100,
    }, name = 'Mr.Wang'; //被替代
    ({name, age} = obj);
    console.log(name);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    3.对象变量解构也可以设置一个默认值,在没有赋值时输出默认值

    let obj = {
        name : 'Mr.Lee',
        age : 100,
    };
    //解构对象字变量
    let {name, age,gender='男'} = obj; //或({name, age} = obj);
    console.log(name,age,gender);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    4.如果不想要对象属性名作为解构变量,可以通过键值对的方式更改变量名

    let obj = {
        name: 'Mr.Lee',
        age: 100,
    };
    
    //解构对象字变量
    let {name:Myname, age:Myage, gender = '男'} = obj;
    
    // console.log(name); //失效
    // console.log(age);//失效
    console.log(Myname);
    console.log(Myage);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    5.在对象字面量里,还嵌套了对象,解构时也用相同的方法是解开即可

    let obj = {
        name : 'Mr.Lee',
        age : 100,
        info : {
            id : 1,
            gender : '男'
        }
    };
    let {info : {id, gender}} = obj;
    console.log(info )//此时info失效
    console.log(id)
    console.log(gender)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    6.对象的解构也支持单行的简写模式

    let {name, age} = {name : 'Mr.Lee', age : 100};
    console.log(name)
    console.log(age)
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    05.常用的解构

    学习要点:
    1.其它解构
    本节课我们来开始学习 ES6 中更多类型的解构和常用方法;

    一.其它解构

    1.ES6 除了提供对象和数组解构外,还提供了很多适用的解构方案

    2.如果你想要让个普通变量的值进行交换,不必需要第三个变量参与

    let key = 1;
    let value = '2';
    
    console.log(key);
    console.log(value);
    
    //解构操作,变量互换
    [key, value] = [value, key];
    
    console.log(key);
    console.log(value);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    3.如果函数的返回值是一个数组或对象,直接将函数进行赋值解构

    function fn() {
        return ['Mr.Lee', 100, '男'];
    }
    let [name, age, gender] = fn();
    
    console.log(name,age,gender);
    
    function fn2() {
        return {
            name : 'Mr.Lee',
            age : 100,
            gender : '男'
        }
    }
    let {name:name2, age:age2, gender:gender2} = fn2();
    console.log(name2,age2,gender2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    4.当函数进行参数传递的时候,可以进行数组和对象字面量方式的传参

    function fn([name, age, gender]) {
        console.log(name);
        console.log(age);
        console.log(gender);
    }
    fn(['Mr.Lee', 100, '男']);
    
    
    function fn2({name, age , gender}) {
        console.log(name);
        console.log(age);
        console.log(gender);
    }
    
    fn2({
        name : 'Mr.Lee',
        age : 100,
        gender : '男'
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    5.除了对象和数组可以使用解构,字符串类型的数据也可以解构

    let [x, y, z] = 'ABC';
    console.log(x); //A
    
    //还可以直接解构出字符串的属性
    let {length:len} = 'ABC';
    console.log(len); //2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    6.还有一些常用的结合需要结合后续内容,之后会展开说明

    后面会说明

    06.函数的参数

    学习要点:
    1.参数默认值
    2.name 属性
    本节课我们来开始学习 ES6 中函数传参默认值等问题;

    一.参数默认值

    1.ES6 之前函数是无法给参数设置默认值的,而 ES6 支持了这个特性

    function fn(name,
                age = 100,
                arr = [],
                obj = {},
                callback = function () {
                }) {
        //参数 1 是必须传递;
        //其余参数有默认值,可选传递;
        console.log(arr);
        console.log(obj);
        console.log(callback('hello'));
    }
    
    fn('Mr.Lee', 200, [1,2,3], {key : 1}, function (info) {
        return info+'-es6';
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    2.函数参数的默认值,也可以是另一个函数的返回值

    function pi() {
        return 3.14;
    }
    function fn(r, p = pi()) { //pi()返回值交给 p
        console.log(r * r * p);
    }
    fn(10);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    3.如果只想传递第二往后的参数,参数一保持默认值,可用 undefined 占位

    function fn(name = 'Mr.Lee', age) { //null,空都不行
        console.log(name);
        console.log(age);
    }
    fn(undefined, 100);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    4.支持参数二使用参数一的值作为默认值,反之不可以

    function fn(x, y = x) { //(y = x, x)错误
        console.log(y);
    }
    
    fn(2);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    5.解构变量有不定元素,那么函数的参数也可以有不定参数;

    function fn(name, ...other) { //不定参数之后不可再有参数
        console.log(other);
    }
    fn('Mr.lee', 100, '男');
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    二.name 属性

    1.ES6 提供了一个 name 属性用于获取函数名,以方便开发者

    function fn() {}
    let fn2 = function () {};
    let obj = {
    fn3 : function () {}
    };
    console.log(fn.name);
    console.log(fn2.name);
    console.log(obj.fn3.name);
    console.log((new Function()).name); //匿名函数 anonymous
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    07.箭头函数和 this

    学习要点:
    1.箭头函数
    2.绑定 this
    本节课我们来开始学习 ES6 新增的箭头函数,然后理解一下箭头 this;

    一.箭头函数

    1.ES6 新增了一个使用(=>)箭头符号定义函数的语法特性,先来个最简单的

    let fn = name => name;
    console.log(fn('Mr.Lee'));
    //翻译成函数代码为:
    // let fn = function (name) {
    //     return name;
    // };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    2.箭头函数也可以传递两个或以上的参数,并实现运算后返回

    let fn = (x, y) => x + y;
    console.log(fn(10, 20));
    //翻译成函数代码为:
    // let fn = function (x, y) {
    //     return x + y;
    // }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    3.如果你定义的函数,并不需要传递参数,可以用()括号方式直接返回

    let fn = () => 'Mr.Lee';
    console.log(fn());
    //翻译成函数代码为:
    // let fn = function () {
    //     return 'Mr.Lee';
    // };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    4.如果函数体需要更复杂的操作,可以将箭头符号右边使用传统函数体

    let fn = (x, y) => {
        return x + y;
    };
    console.log(fn(10, 20));
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    5.如果箭头符号右边是对象,返回的是对象,则需要用圆括号包含着

    let fn = name => ({name : name, age : 100});
    console.log(fn('Mr.Lee').name);
    //翻译成函数代码为:
    // let fn = function (name) {
    //     return {
    //         name : name,
    //         age : 100
    //     }
    // };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    6.如果箭头符号左边是对象作为参数,右边是对象的属性运算,也支持

    let fn = ({name, age}) => name + ', ' + age;
    console.log(fn({name : 'Mr.Lee', age : 100}));
    
    • 1
    • 2

    在这里插入图片描述

    7.自我立即执行函数,也可以使用箭头符号来创建,具体如下

    ((name) => {
        console.log(name);
    })('Mr.Lee');
    //翻译成函数代码为:
    // (function (name) {
    //     console.log(name);
    // })('Mr.Lee');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    二.绑定 this

    1.ES6 之前有一个比较头疼的问题,就是 this 指向的问题,比如下面例子

    let obj = {
        name : 'Mr.Lee',
        age : 100,
        fn : function () {
            console.log(this)
            setTimeout(function () {
                console.log(this);
                console.log(this.name + ', ' + this.age);
            }, 500)
        }
    };
    obj.fn();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.上面的例子比较典型,this 全局指向 window,在某个对象内部指向当前对象

    在这里插入图片描述

    3.当 obj 对象下包含了类似 setTimeout 函数内部,这时 this 指向就出现问题了

    在这里插入图片描述

    4.Web 环境下,它指向了 Window,而 node 环境下它指向 setTimeout

    在这里插入图片描述

    5.所以,我们通俗的做法,就是将 this 在 setTimeout 外部进行赋值保存;

    let obj = {
        name : 'Mr.Lee',
        age : 100,
        fn : function () {
            // console.log(this)
            let that = this;
            setTimeout(function () {
                // console.log(this);
                // console.log(this.name + ', ' + this.age);
                console.log(that.name);
            }, 500)
        }
    };
    obj.fn();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    node环境下
    在这里插入图片描述

    浏览器环境
    在这里插入图片描述

    6.箭头函数的出现,彻底解决了 this 在内部指向的问题,直接指向我们所需要

    7.因为,箭头函数中的 this 是最外层定义的函数绑定,不受内部影响

    let obj = {
        name : 'Mr.Lee',
        age : 100,
        fn : function () {
            let that = this;
            setTimeout(() => {
                console.log(this.name + ', ' + this.age);
            }, 500)
        }
    };
    obj.fn();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    08.箭头扩展和尾调用

    学习要点:
    1.箭头扩展
    2.尾调用优化
    本节课我们来开始学习箭头一些别的用法,以及尾调用优化的方法。

    一.箭头扩展

    1.箭头也支持一些内置函数的使用,比如 sort()排序

    // let arr = [3, 1, 2].sort(function (a, b) {
    //     return a - b;
    // });
    // console.log(arr);
    
    
    //es6
    let arr = [3, 1, 2].sort((a, b) => a - b);
    console.log(arr);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    2.箭头函数不支持 arguments 绑定,请直接使用…other 模式(rest 运算符)

    let fn = (x, y) => {
        return arguments[0] + arguments[1]
    }
    
    console.log(fn(10, 20));
    
    let fn2 = (...other) => {
        return other[0] + other[1]
    };
    console.log(fn2(10, 20));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    3.箭头函数和普通函数一样,都可以被 typeof 和 instanceof

    let fn = (...other) => {
        return arguments[0] + arguments[1]
    }
    console.log(typeof fn);//function
    console.log(fn instanceof Function);//true
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    二.尾调用优化

    1.什么是尾调用?即在一个函数的最后可执行的一步调用了其它函数

    function go(x) {
    return x + 20;
    }
    
    let fn = function (x) {
    	//xxx 假设此处有很多代码
    return go(x);//在函数内部最后一步调用了go函数
    };
    console.log(fn(10));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.那?什么又是尾调用优化?为何要优化?因为:每次尾调用都会创建栈帧;

    3.如果尾调次数过多,而内存中的调用栈越来越大,可能就会出现程序问题;

    4.尤其是在递归函数的问题上,尾调用优化适合在这种场景中使用;

    function fn(x) {
    if (x <= 1) {
    return 1;
    }
    return fn(x - 1);
    }
    console.log(fn(10));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5.首先要说明,尾调用优化必须是在 ES6 的严格模式下,‘use strict’;

    只需要开启严格模式就可以尾调用优化了

    'use strict';
    function fn(x) {
    if (x <= 1) {
    return 1;
    }
    return fn(x - 1);
    }
    console.log(fn(10));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.严格模式,可以设置为全局作用域,也可以在函数体内有效;

    这里有个例子,什么叫做严格模式? 它就是规范你的代码的
    在这里插入图片描述
    开启严格模式,智能编辑器它就会报错

    'use strict';
    let public = 5;
    console.log(public);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    7.严格模式对变量、对象和函数做了一些代码规范等等,具体规范可以搜索;

    8.而对于尾调用,必须严格按照三个规则,才能执行严格模式下的优化,如下:

    (1) .尾调用必须 return 返回; // go(x); 错误
    (2) .尾调用 return 返回不得含其它操作 // return go(x) + 1; 错误
    (3) .尾调用 return 返回的不是函数,而是函数赋值的变量,不在尾部;

    09.字符串的扩展改进

    学习要点:
    1.新增方法
    2.模板字符串
    本节课我们来开始学习 ES6 新增的字符串方法以及模板字符串功能

    一.新增方法

    1.对于一些超过两个字符(四字节)的字体,ES6 新增了 codePointAt()方法

    // let text = '𠮷';
    // console.log(text.length); //1
    // console.log(text.charAt(0)); //吉 ,取text这个字符串的第一个字符
    // console.log(text.charCodeAt(0));//21513 取十进制编码
    // console.log(text.charCodeAt(1));//因为吉是单字符,所以第二个就字符就没有,所有是NaN
    
    let text2 = '𠮷';
    console.log(text2.length); //1
    console.log(text2.charAt(0)); // 取个字符串的第一个字符,这就导致取不出来,因为这个字本身是一个字,但是它长度是2,charAt(0)就表示取第一个字符,一个字体的一半所以无法显示
    //es6提供的codePointAt可以解决这个问题
    console.log(text2.codePointAt(0));
    //但是codePointAt得到的只是十进制码点,我们可以通过fromCodePoint方法得到单个字
    console.log(String.fromCodePoint(134071));//𠮷
    console.log(text2.charCodeAt(0));//55362 取十进制编码
    console.log(text2.charCodeAt(1));//57271 因为𠮷是异体字长度是2,所以第二个就字符就能取到
    
    
    
    //此时我们有一个异体字
    // console.log(String.fromCodePoint(134071));
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.对于超过两字符的码点,可以通过 ES6 新增的 String.fromCodePoint()得到

    console.log(String.fromCodePoint(134071));//𠮷
    
    • 1

    3.ES6 提供 normalize()方法用于有音标的符号组合形式进行统一;

    console.log('\u01D1');//Ǒ
    console.log('\u004F');//O
    console.log('\u030C');// ̌
    
    console.log('\u004F\u030C');//Ǒ
    
    console.log('\u004F\u030C' === '\u01D1'); //正常来讲应该要相等的。但是不相等
    console.log('\u004F\u030C'.normalize() === '\u01D1'.normalize());//es6提供的normalize可以解决这个问题
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    4.ES6 提供了三种判断字符串的方法:includes()、startsWith()和 endsWith();

    let text = 'Hello, Mr.Lee!';
    console.log(text.includes('Mr.')); //true,是否找到'Mr.'
    console.log(text.startsWith('ello')); //false,必须从开头找
    console.log(text.endsWith('ee!')); //true,必须从结尾找
    console.log(text.includes('Mr.', 8)); //false,超过位置,第二参数寻找的位置
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    5.repeat()重复字符串,padStart()补全字符串头部,padEnd()补全字符串尾部在这里插入代码片

    console.log('x'.repeat(5));
    console.log('xyz'.repeat(3));
    console.log('Mr.Lee'.repeat(0)); //空
    console.log('x'.padStart(5, 'Mr')); //MrMrx
    console.log('x'.padEnd(5, 'Mr')); //xMrMr
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    二.模板字符串

    1.在 ES6 之前,字符串内夹杂变量,我们总是通过分离和+号连接解决

    let name = 'Mr.Lee',
    age = 100,
    text = '我是' + name + ',今年' + age + '岁';
    console.log(text);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    2.现在可以直接使用(`)反引号配合${var}模版语法格式,直接实现变量解析功能

    let name = 'zhangsan',
        age  = 18;
        text = `我是${name},今年${age}`; // \`转义
        //支持多行操作
        text2 = `我是
        ${name},今年
        ${age}`;
        console.log(text);
        console.log(text2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    3.如果我们想在字符串中插入表达式,也可以使用${a + b}模版语法

    let text = `1+1=${1+1}`;
    console.log(text);
    
    • 1
    • 2

    在这里插入图片描述

    4.${${}}这种模版嵌套的方式,也是支持的

    let flag = true,
        text = `结果:${flag ? `true${1+1}` : 'false'}`;
    
    console.log(text);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    5.可以使用 String.raw 来得到原生字符串

    let text = `我\n是`;
    
    console.log(text);
    console.log(String.raw `我\n是`)
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    10.正则的扩展改进

    学习要点:
    1.正则扩展
    本节课我们来开始学习 ES6 新增的正则表达式的扩展和改进部分。

    一.正则扩展

    1.ES6 提供了 u 修饰符,对占两个字符特殊字进行正则识别

    //𠮷
    
    let result = /吉{2}/.test('吉吉');
    let result2 = /𠮷{2}/.test('𠮷𠮷');
    //es6为了解决这个问题,增加了一个u修饰符
    let result3 = /𠮷{2}/u.test('𠮷𠮷');
    console.log(result);
    console.log(result2);
    console.log(result3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    2.ES6 提供了 y 修饰符,它的作用是当匹配过一次后继续往下匹配

    let text = 'xxx_xx_x_',
        patt = /x+_/;
        patt2 = /x+_/y;
    
    
    console.log(patt.exec(text)); //xxx_
    console.log(patt.exec(text)); //xxx_
    console.log(patt.exec(text)); //xxx_
    
    console.log(patt2.exec(text)); //xxx_
    console.log(patt2.exec(text)); //xx_
    console.log(patt2.exec(text)); //x_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    3.对于 y 修饰符,ES6 提供了 stikcy 属性,用来检测是否存在 y 修饰符

    let text = 'xxx_xx_x_',
        patt = /x+_/;
        patt2 = /x+_/y;
    
    
    console.log(patt.sticky); //false
    console.log(patt2.sticky); //true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    4.ES6 提供了 flags 属性,用于返回正则使用的修饰符名称

    let text = 'xxx_xx_x_',
        patt = /x+_/;
    patt2 = /x+_/y;
    
    
    console.log(patt.flags); //''
    console.log(patt2.flags); //y
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    5. 点.表示匹配所有,除了终止符,比如回车\n 换行\n 等等,使用 s 修饰符匹配

    let text = 'x\nyz',
        patt = /x.+yz/;
        patt2 = /x.+yz/s;
    console.log(patt.test(text));//false
    console.log(patt2.test(text));//true
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    6.ES6 支持修饰符替换,之前的这种写法会直接报错

    //ES6 支持修饰符替换,之前会报错
    let regex = new RegExp(/xyz/iu, 'g');
    console.log(regex.flags); //g
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    11.数值的扩展改进

    学习要点:
    1.数值扩展
    2.Math 扩展
    本节课我们来开始学习 ES6 新增的数值的扩展和改进功能。

    一.数值扩展

    1.ES6 明确二进制、八进制和十六进制分别用 0b、0o、0x 作为前缀

    console.log(Number('0b11'));
    console.log(Number('0o11'));
    console.log(Number('0x11'));
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    2.ES6 提供了 Number.isFinitel()、Number.isNaN()判断无穷大和 NaN

    //非数值为 false,数值为 true
    console.log(Number.isFinite(100));
    console.log(Number.isFinite("100"));
    //NaN 为 true,其余为 false
    console.log(Number.isNaN(NaN));
    console.log(Number.isNaN(100));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    3.ES6 提供了 Number.parseInt()、Number.parseFloat()转换整型和浮点型

    console.log(Number.parseInt('55.55a'));
    console.log(Number.parseFloat('55.555b'));
    
    • 1
    • 2

    在这里插入图片描述

    4.ES6 提供了 Number.isInteger(),来判断参数是否是一个整型

    console.log(Number.isInteger(10));
    
    • 1

    在这里插入图片描述

    5.ES6 提供了一个常量,值特别小,用于判断是否得到正确结果

    Javascript对于一些特别小的数值操作,它有精度问题

    console.log(Number.EPSILON);
    console.log(Number.EPSILON.toFixed(30)); //直观的看
    
    
    console.log(0.1 + 0.2 === 0.3);//false
    
    console.log(0.1 + 0.2 - 0.3 < Number.EPSILON);//true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    6.ES6+新增了一个指数运算符 **,并且可以进行赋值运算

    console.log(2 ** 4); //16,4 个 2 相乘
    let num = 2;
    num **= 5;
    console.log(num); //32,5 个 2 相乘
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    二.Math 扩展

    1.ES6 对 Math 对象新增了一些方法.trunc()、.sign()、cbrt()、clz32()

    2. .imul()、.fround()、.hypot()、expm1()、.log1p()、log10()、log2();

    console.log(Math.trunc(5.55)); //去掉小数部分
    console.log(Math.sign(-5)); //判断是否为正、负、0 还是 NaN
    console.log(Math.cbrt(2)); //求出一个值的立方根
    console.log(Math.clz32(1)); //求一个数的 32 位二进制
    console.log(Math.imul(2,-4)); //两个数整数形式相乘的结果带符号
    console.log(Math.fround(1.555)); //求一个数单精度浮点形式
    console.log(Math.hypot(3, 4)); //求出所有参数平方和的平方根
    console.log(Math.expm1(-1)); //返回 Math.exp(x)-1
    console.log(Math.log1p(1)); //求 ln(1+x),Math.log(1+x)
    console.log(Math.log10(1)); //求 10 为底的 x 的对数
    console.log(Math.log2(3)); //求 2 为底的 x 的对数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    12.数组的扩展改进

    学习要点:
    1.运算符扩展
    2.方法的扩展
    本节课我们来开始学习 ES6 新增的数组的扩展和改进功能。

    一.运算符扩展

    1.ES6 提供了(…)三个点将一个数组转换为逗号分割来进行处理

    function add(x, y) {
        return x + y;
    }
    console.log(add(...[10, 20]));
    
    • 1
    • 2
    • 3
    • 4

    2.既然三点运算符通过逗号分割,那么可以想象的应用场景就随意发挥

    console.log(Math.max(...[1,2,3])); //求最大值
    console.log([...[1,2], ...[3,4]]); //合并数组
    
    • 1
    • 2

    二.方法的扩展

    1.ES6 提供了 Array.of()方法,它的主要目的是弥补 Array()的不足

    //ES5 声明数组,当小于两位,显示长度
    let items = Array(1,2,3);
    let items2 = Array(3);
    console.log(items)
    console.log(items2)//这里竟然是空的,它只是声明了3个长度的一个数组。
    
    //ES6 声明数组,简化版
    let items3 = Array.of(3, 2, 1);
    let items4 = Array.of(3);
    console.log(items3);
    console.log(items4);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    2.ES6 提供了 Array.from()方法,将类似数组的对象或遍历转换成真正的数组

    let obj = {
        0 : 'name',
        1 : 'age',
        2 : 'gender',
        length : 3,
    };
    let items = Array.from(obj);
    console.log(items);
    
    let obj2 = {
        1 : 'name',
        2 : 'age',
        3 : 'gender',
        length : 3,
    };
    let items2 = Array.from(obj2);
    console.log(items2);
    
    let obj3 = {
        'a' : 'name',
        'b' : 'age',
        'c' : 'gender',
        length : 3,
    };
    let items3 = Array.from(obj3);
    console.log(items3);
    
    • 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

    在这里插入图片描述

    可以看出对象转换成数组要求比较严格:
    (1).key 必须是数值或字符串数字;
    (2).length 设置长度,而且 key 在范围内;

    既然要求这么严格,那什么样的场景会产生这种对象?
    (1).DOM 的 NodeList 集合;
    (2).ES6 新增的 Set 和 Map(后续内容);

    //返回的是类似数组的对象

    let nl = document.querySelectorAll('p');
    
    • 1

    这个时候就需要转换一下了

    3.ES6 提供了 find()和 findIndex()方法,用于查找数组中第一个匹配的值

    
    let items = [10, 20, 30, 40, 50];
    //参数是一个回调函数,可以用箭头函数,findIndex 可以得到索引
    console.log(items.find(value => value > 19));//20
    console.log(items.findIndex(value => value > 19));//1
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    4.ES6 提供了 fill()方法,可以填充重写数组中的元素值

    let items = [1, 2, 3, 4, 5];
    items.fill('a');
    console.log(items); //['a', 'a', 'a', 'a', 'a']
    let items2 = [1, 2, 3, 4, 5];
    items2.fill('a', 3, 4); //索引 3 开始,索引 4 结束
    console.log(items2); //[1, 2, 3, 'a', 1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    5.ES6 提供了 copyWithin 方法,从数组内部复制值,然后粘贴指定位置

    let items = [1, 2, 3, 4, 5];
    //从索引 0 开始复制值
    //然后把值从索引 2 开始粘贴
    //参数 3 设置结束粘贴索引值
    items.copyWithin(2, 0);//3换成1
    console.log(items);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    13.对象的简写改进

    学习要点:
    1.简写方案
    2.表达式方案
    本节课我们来开始学习 ES6 新增的对象的扩展和改进功能

    一.简写方案

    1.ES6 可以让对象字面量中属性初始值实现简写,一定程度降低了代码量

    function fn1(name, age) {
    //ES5 的写法
        return {
            name : name,
            age : age
        }
    }
    
    console.log(fn1('Mr.Lee', 'age'));
    
    
    function fn2(name, age) {
    //ES6 的写法
        return {
            name,age
        }
    }
    
    console.log(fn2('Mr.Lee', 'age'));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    2.ES6 还提供了对象字面量中方法的简写方式,也降低了一定的代码量

    let obj1 = {
    //ES5 的写法
        fn : function () {
            return 'ES5 fn';
        }
    };
    
    console.log(obj1.fn());
    
    let obj2 = {
    //ES6 的写法
        fn() {
            return 'ES6 fn';
        }
    };
    console.log(obj2.fn());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    二.表达式方案

    1.ES6 允许对象字面量中,使用表达式进行属性名称的拼装操作

    //拼装组合属性
    let obj = {
        ['user' + 'Name'] : 'Mr.Lee',
    };
    console.log(obj.userName);
    console.log(obj['userName']);
    
    //有空格的情况下
    let obj2 = {
        ['user' + ' Age'] : 100,
    };
    console.log(obj2['user Age']);
    
    //字符串属性
    let obj3 = {
        'user Gender' : '男',
    };
    console.log(obj3['user Gender']);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    2.ES6 提供了在对象字面量中使用可计算(动态)属性名称,具体如下

    //半动态
    //通过变量 myName 动态更改 obj 属性名
    //问题是当变量值更改了,属性名就失效了
    // let myName = 'name';//Mr.Lee
    let myName = 'name1';
    let obj = {
        name : 'Mr.Lee'
    };
    console.log(obj[myName]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    真动态

    //使用[myName]可计算属性名
    //实现了真正的动态计算
    let myName = 'name';
    let obj = {
    [myName] : 'Mr.Lee'
    };
    console.log(obj[myName]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    3.ES6 在对象字面量方法上,也可以使用拼装名称

    let obj = {
        ['f' + 'n']() {
            return 'fn';
        }
    };
    console.log(obj.fn());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    14.对象的新增方法

    学习要点:
    1.新增方法
    本节课我们来开始学习 ES6 新增的对象的扩展和改进功能。

    一.新增方法

    1.ES6 提供了 Object.is()方法来解决“===”中一些恒等中的缺点

    //这两个理解起来没什么问题
    console.log(Object.is(100 ,'100')); //false
    console.log(Object.is({}, {})); //false,指向不同
    
    
    console.log(+0===-0);//true
    console.log(Object.is(+0, -0)); //es6 false
    
    
    console.log(NaN === NaN); //false
    console.log(Object.is(NaN, NaN)); //es6 true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    2.ES6 提供了 Object.assign()方法可以合并指定对象至目标对象内部

    let obj1 = {
        name: 'Mr.Lu',
        age: 100
    }
    let obj2 = {
        name: 'Mr.Wu',
        age: 100
    }
    let obj3 = {
        gender: '男'
    }
    
    
    console.log(Object.assign(obj1,obj2,obj3))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    (1).如果属性有相同,后面的源对象内容会覆盖之前的属性值;
    (2).如果直接传非对象内容,会转换为对象;
    (3).如果传入的是 undefined 和 null 会报错;

    3.ES6 提供了 Object.getPrototypeOf()和 Object.setPrototypeof()方法

    let obj = {
        fn() {
            return 'fn';
        }
    };
    let obj2 = {
        fn() {
            return 'fn2';
        }
    };
    
    //以 obj 对象为原型
    // let f = Object.create(obj);//fn
    let f = Object.create(obj2);//fn2
    
    
    console.log(f.fn());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    /检测是 obj 是否 f 的原型对象

    let obj = {
        fn() {
            return 'fn';
        }
    };
    let obj2 = {
        fn() {
            return 'fn2';
        }
    };
    
    //以 obj 对象为原型
    // let f = Object.create(obj);//fn
    let f = Object.create(obj2);//fn2
    
    
    console.log(f.fn());
    
    console.log(Object.getPrototypeOf(f) === obj2);//true
    console.log(Object.getPrototypeOf(f) === obj);//false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    let obj = {
        fn() {
            return 'fn';
        }
    };
    let obj2 = {
        fn() {
            return 'fn2';
        }
    };
    
    //以 obj 对象为原型
    // let f = Object.create(obj);//fn
    let f = Object.create(obj2);//fn2
    
    
    console.log(f.fn());
    
    console.log(Object.getPrototypeOf(f) === obj2);//true
    console.log(Object.getPrototypeOf(f) === obj);//false
    
    //设置原型对象
    Object.setPrototypeOf(f,obj);
    console.log(f.fn());//fn
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    4.ES6 提供了 super 关键字,用于原型中方法的继承功能

    let obj = {
    fn() {
    return 'fn';
    }
    };
    let f = {
    fn() {
    return super.fn() + ', extend!';
    }
    };
    //设置 obj 是 f 的原型
    Object.setPrototypeOf(f, obj);
    console.log(f.fn());
    //可以再设置以 f 为原型
    let h = Object.create(f);
    console.log(h.fn());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    15.Symbol 类型和属性

    学习要点:
    1.Symbol 类型
    2.Symbol 属性
    本节课我们来开始学习 ES6 新增的 Symbol 类型和作为属性的方法

    一.Symbol 类型

    1.ES6 之前基础数据类型有:字符串、数值、布尔、对象、null 和 undefined

    //注意,不支持 new Symbol()
    let s = Symbol();
    console.log(s); //输出 Symbol()
    console.log(typeof s); //输出 symbol 类型
    
    • 1
    • 2
    • 3
    • 4

    2.ES6 新增了一种叫做 Symbol 的基础数据类型,表示独一无二的值,类似 ID

    let s1 = Symbol(),
        s2 = Symbol();
    console.log(s1 === s2);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    3.创建 Symobl 通过函数 Symbol()完整,可以传递参数,也可以为空

    4.在 Symbol()函数中参数,是对变量的描述,程序无法访问,只能日志打印

    let s1 = Symbol('s1'),
        s2 = Symbol('s2');
    
    console.log(s1);
    console.log(s2);
    console.log(s1 === s2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    5.Symobol 类型变量无法进行隐式转换,需要提前显示转换匹配的类型

    let s1 = Symbol('s1');
    console.log(s1+'a')
    
    • 1
    • 2

    在这里插入图片描述

    支持显示转换

    console.log(s1.toString() + '变量');
    console.log(String(s1) + '变量');
    console.log(!s1); //布尔值
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    一.Symbol 属性

    1.Symbol 类型有哪些应用场景?解决了哪些问题?最常用的一种就是对象属性;

    2.由于 Symbol 类型是独一无二的值,作为对象属性就具有唯一性不出现重名;

    3.对于多模块、多人开发或者拼装属性名的情况下,有可能会出现属性名重复

    4.首先,先故意设置一个相同的对象属性名,看看会出现什么问题?

    //重名的属性名不报错,被覆盖
    let obj = {
        name : 'Mr.Lee',//被下面的覆盖了
        name : 'Mr.Wang'
    };
    console.log(obj);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    连拼装的动态属性名,也会有这个问题

    //拼装的属性名,也被覆盖
    let x = 'Name',
        y = 'Name';
    let obj = {
        ['user' + x] : 'Mr.Lee',
        ['user' + y] : 'Mr.Wang'
    };
    console.log(obj);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    5.那么,Symbol 作为对象属性名,该如何使用呢?具体如下

    let x = Symbol('name');
    let y = Symbol('name');
    let obj = {
    [x] : 'Mr.Lee',
    [y] : 'Mr.Wang'
    };
    //结果:{ [Symbol(name)]: 'Mr.Lee', [Symbol(name)]: 'Mr.Wang' }
    console.log(obj)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    调用
    在这里插入图片描述

    6.方法名也可以使用 Symbol 类型

    let fn = Symbol('fn');
    let obj = {
        [fn]() {
            return 'fn';
        }
    };
    console.log(obj);
    console.log(obj[fn]());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

  • 相关阅读:
    JS正则表达式
    Java技能树-网络-HTTP-HttpURLConnection
    力扣C++学习笔记——C++ 给vector去重
    【Linux】【开发】Linux shell环境下如何产生随机数
    Java常用类(一)
    Ubuntu 安装 Angular8
    PLC编程基础之数据类型、变量声明、全局变量和I/O映射(CODESYS篇 )
    STM32物联网项目-触摸按键
    GameFramework食用指南
    根据上班时间、周末、节假日计算两个时间之间的工时
  • 原文地址:https://blog.csdn.net/qq_35081380/article/details/128113676