ECMAScript

Stone大约 24 分钟

ECMAScript

ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。

ES 5

严格模式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>01_严格模式</title>
</head>
<body>
<!--
    1. 理解:
      * 除了正常运行模式(混杂模式),ES5 添加了第二种运行模式:"严格模式"(strict mode)。
      * 顾名思义,这种模式使得 Javascript 在更严格的语法条件下运行
    2.  目的/作用
      * 消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为
      * 消除代码运行的一些不安全之处,为代码的安全运行保驾护航
      * 为未来新版本的 Javascript 做好铺垫
    3. 使用
      * 在全局或函数的第一条语句定义为: 'use strict';
      * 如果浏览器不支持, 只解析为一条简单的语句, 没有任何副作用
    4. 语法和行为改变
      * 必须用 var 声明变量
      * 禁止自定义的函数中的 this 指向 window
      * 创建 eval 作用域
      * 对象不能有重名的属性
-->

<script type="text/javascript">
    'use strict';
    var username = 'stone';
    console.log(username);

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }

    new Person('stone', 26);

    //* 创建 eval 作用域
    var str = 'NBA';
    eval('var str = "CBA";alert(str)');
    console.log(str);

    var obj = {
        name : 'stone',
        name : 'box'
    };
    console.log(obj);
</script>

</body>
</html>

JSON 对象

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_JSON 对象</title>
</head>
<body>
<!--
    1. JSON.stringify(obj/arr)
      * js 对象(数组)转换为 json 对象(数组)
    2. JSON.parse(json)
      * json 对象(数组)转换为 js 对象(数组)

-->
<script type="text/javascript">
    var obj = {username: 'stone'};
    obj = JSON.stringify(obj);
    console.log(typeof obj);
    obj = JSON.parse(obj);
    console.log(typeof obj);
</script>
</body>
</html>

Object 扩展

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>03_Object 扩展</title>
</head>
<body>
<!--
    ES5 给 Object 扩展了一些静态方法, 常用的 2 :
    1. Object.create(prototype, [descriptors])
      * 作用: 以指定对象为原型创建新对象
      * 为新对象指定新属性, 并对属性进行描述
        - value : 指定值
        - writable : 标识当前属性值是否可修改, 默认为 false
        - configurable : 标识当前属性是否可删除 默认为 false
        - enumerable: 标识当前属性是否能用 for in 枚举 默认为 false
    2. Object.defineProperties(object, descriptors)
      * 作用: 为指定对象定义扩展多个属性
      * get :用来获取当前属性值得回调函数
      * set :修改当前属性值得触发的回调函数,并且实参即为修改后的值
      * 存取器属性:setter,getter 一个用来存值,一个用来取值
-->
<script type="text/javascript">
    var obj = {username: 'stone', age: 26};
    var obj1 = {};
    obj1 = Object.create(obj, {
        sex: {
            value: '男',
            writable: true,
            configurable: true,
            enumerable: true
        }
    });
    console.log(obj1.sex);
    obj1.sex = '女';
    console.log(obj1.sex);
    // delete obj1.sex;
    // console.log(obj1);

    for (var i in obj1) {
        console.log(i);
    }

    // Object.defineProperties(object, descriptors)

    var obj2 = {firstName: 'stone', lastName: 'box'};
    Object.defineProperties(obj2, {
        fullName: {
            get: function () {// 获取扩展属性的值. 获取扩展属性值 get 方法自动调用
                console.log('get()');
                return this.firstName + ' ' + this.lastName;
            },
            set: function (data) {// 监听扩展属性,当扩展属性发生变化的时候会自动调用. 自动调用后会将变化的值作为实参注入到 set 函数
                console.log('set()', data);
                var names = data.split(' ');
                this.firstName = names[0];
                this.lastName = names[1];
            }
        }
    });

    console.log(obj2);
    console.log(obj2.fullName);
    obj2.fullName = 'time duncan';
    console.log(obj2.fullName);
</script>
</body>
</html>

Array 扩展

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>04_Array 扩展</title>
</head>
<body>
<!--
    1. Array.prototype.indexOf(value) : 得到值在数组中的第一个下标
    2. Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
    3. Array.prototype.forEach(function(item, index){}) : 遍历数组
    4. Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组,返回加工之后的值
    5. Array.prototype.filter(function(item, index){}) : 遍历过滤出一个新的子数组, 返回条件为 true 的值
-->
<script type="text/javascript">
    /*
     需求:
     1. 输出第一个 6 的下标
     2. 输出最后一个 6 的下标
     3. 输出所有元素的值和下标
     4. 根据 arr 产生一个新数组,要求每个元素都比原来大 10
     5. 根据 arr 产生一个新数组, 返回的每个元素要大于 4
     */

    var arr = [1, 4, 6, 2, 5, 6];
    console.log(arr.indexOf(6));// 2
    // Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
    console.log(arr.lastIndexOf(6));// 5

    // Array.prototype.forEach(function(item, index){}) : 遍历数组
    arr.forEach(function (item, index) {
        console.log(item, index);
    });

    // Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组,返回加工之后的值
    var arr1 = arr.map(function (item, index) {
        return item + 10;
    });
    console.log(arr, arr1);

    // Array.prototype.filter(function(item, index){}) : 遍历过滤出一个新的子数组, 返回条件为 true 的值
    var arr2 = arr.filter(function (item, index) {
        return item > 4;
    });
    console.log(arr, arr2);


</script>
</body>
</html>

Function 扩展

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>05_Function 扩展</title>
</head>
<body>
<!--
    1. Function.prototype.bind(obj) :
      * 作用: 将函数内的 this 绑定为 obj, 并将函数返回,通常用于回调函数
    2. 面试题: 区别 bind()call()apply()?
      * 都能指定函数中的 this
      * call() / apply() 是立即调用函数
      * bind() 是将函数返回
-->
<script type="text/javascript">
    var obj = {username: 'kobe'};

    function foo(data) {
        console.log(this, data);
    }

    // 传入参数的形式
    // foo.call(obj, 33);// 直接从第二个参数开始,依次传入
    // foo.apply(obj, [33]);// 第二个参数必须是数组,传入的数据放在数组里面

    // bind 的特点:绑定完 this 不会立即调用当前的函数,而是将函数返回
    // var bar = foo.bind(obj);
    // console.log(bar);

    // bind 传参的方式同 call 一样
    foo.bind(obj, 33)();

    // 使用 bind 修改定时器回调函数的 this 为 obj
    setTimeout(function () {
        console.log(this);
    }.bind(obj), 1000);
</script>
</body>
</html>

ES 6

let 关键字

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>01_let 关键字</title>
</head>
<body>

<button>测试 1</button>
<br>
<button>测试 2</button>
<br>
<button>测试 3</button>
<br>
<!--
    ***let
    1. 作用:
      *var 类似, 用于声明一个变量
    2. 特点:
      * 在块作用域内有效
      * 不能重复声明
      * 不会预处理, 不存在变量提升
    3. 应用:
      * 循环遍历加监听
      * 使用 let 取代 var 是趋势
-->
<script type="text/javascript">
    // console.log(username);
    let username = 'chen';
    // let username = 'eason';
    console.log(username);

    let btns = document.getElementsByTagName('button');
    for (let i = 0; i < btns.length; i++) {
        var btn = btns[i];
        btn.onclick = function () {
            alert(i);
        }
    }

</script>
</body>
</html>

const 关键字

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>02_const 关键字</title>
</head>
<body>
<!--
    1. 作用:
      * 定义一个常量
    2. 特点:
      * 不能修改
      * 其它特点同 let
    3. 应用:
      * 保存不用改变的数据
-->
<script type="text/javascript">
    const KEY = 'NBA';
    console.log(KEY);

</script>
</body>
</html>

变量的解构赋值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>03_变量的解构赋值</title>
</head>
<body>
<!--
    1. 理解:
      * 从对象或数组中提取数据, 并赋值给变量(多个)
    2. 对象的解构赋值
      let {n, a} = {n:'tom', a:12}
    3. 数组的解构赋值
      let [a,b] = [1, 'atguigu'];
    4. 用途
      * 给多个形参赋值
-->
<script type="text/javascript">
    let obj = {username: 'chen', age: 26};
    // let username = obj.username;
    // let age = obj.age;

    let {username, age} = obj;

    console.log(username, age);

    let arr = [1, 3, 5, 'abc', true];
    let [, a, b] = arr;
    console.log(a, b);

    function foo({username, age}) { // {username, age} = obj
        console.log(username, age);
    }

    foo(obj);

</script>
</body>
</html>

模板字符串

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>04_模板字符串</title>
</head>
<body>
<!--
    1. 模板字符串 : 简化字符串的拼接
      * 模板字符串必须用 `` 包含
      * 变化的部分使用 ${xxx} 定义
-->
<script type="text/javascript">
    let obj = {username: 'chen', age: 26};
    let str = `我的名字叫:${obj.username},年龄 ${obj.age}`;
    console.log(str);
</script>
</body>
</html>

简化的对象写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>05_简化的对象写法</title>
</head>
<body>
<!--
    简化的对象写法
    * 省略同名的属性值
    * 省略方法的 function
    * 例如:
      let x = 1;
      let y = 2;
      let point = {
        x,
        y,
        setX (x) {this.x = x}
      };
-->
<script type="text/javascript">
    let username = 'chen';
    let age = 26;

    let obj = {
        username,// 同名的属性可以省略不写
        age,
        getName() { // 可以省略函数的 function
            return this.username;
        }
    };

    console.log(obj);
    console.log(obj.getName());
</script>
</body>
</html>

箭头函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>06_箭头函数</title>

</head>
<body>
<button id="btn1">测试箭头函数 this_1</button>
<button id="btn2">测试箭头函数 this_2</button>


<!--
    * 作用: 定义匿名函数
    * 基本语法:
      * 没有参数: () => console.log('xxxx')
      * 一个参数: i => i+2
      * 大于一个参数: (i,j) => i+j
      * 函数体不用大括号: 默认返回结果
      * 函数体如果有多个语句, 需要用{}包围,若有需要返回的内容,需要手动返回
    * 使用场景: 多用来定义回调函数

    * 箭头函数的特点:
        1、简洁
        2、箭头函数没有自己的 this,箭头函数的 this 不是调用的时候决定的,而是在定义的时候处在的对象就是它的 this
        3、扩展理解: 箭头函数的 this 看外层的是否有函数,
            如果有,外层函数的 this 就是内部箭头函数的 this,
            如果没有,则 this 是 window。
-->
<script type="text/javascript">
    // let fun = function () {
    //     console.log('我是箭头函数');
    // };

    let fun = () => console.log('我是箭头函数');
    fun();

    // 形参的情况
    // 1、没有形参的时候
    let fun1 = () => console.log('我是箭头函数');
    fun1();
    // 2、只有一个形参的时候 () 可以省略
    // let fun2 = (a) => console.log(a);
    let fun2 = a => console.log(a);
    fun2('aaa');

    // 3、两个及两个以上的形参的时候 () 不能省略
    let fun3 = (x, y) => console.log(x, y);
    fun3(23, 36);

    // 函数体的情况
    // 1、函数体只有一条语句或者表达式的时候 {} 可以省略 ---> 会自动返回语句执行的结果或者是表达式的结果
    // let fun4 = () => {console.log('我是箭头函数')};
    // let fun4 = (x, y) => x + y;
    let fun4 = (x, y) => {
        return x + y
    };
    console.log(fun4(23, 36));

    // 2、函数体不止一条语句或者表达式的时候 {} 不可以省略
    let fun5 = (x, y) => {
        console.log(x, y);
        return x + y;
    };
    console.log(fun5(23, 33));

    // 测试箭头函数的 this
    let btn1 = document.getElementById('btn1');
    let btn2 = document.getElementById('btn2');
    btn1.onclick = function () {
        console.log(this);
    };
    // btn2.onclick = () => {
    //     console.log(this);
    // };

    // let obj = {
    //     name: '箭头函数',
    //     getName: function () {
    //         btn2.onclick = () => {
    //             console.log(this);
    //         };
    //     }
    // };
    // obj.getName();

    // 指向 window
    let obj = {
        name: '箭头函数',
        getName: () => {
            btn2.onclick = () => {
                console.log(this);
            };
        }
    };
    // 这样理解
    // obj.getName = () => {
    //
    // };

    obj.getName();

</script>
</body>
</html>

3 点运算符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>07_3 点运算符</title>
</head>
<body>
<!--
    * 用途
    1. rest(可变)参数
        * 用来取代 arguments 但比 arguments 灵活,只能是最后部分形参参数
        function fun(...values) {
            console.log(arguments);
            arguments.forEach(function (item, index) {
                console.log(item, index);
            });
            console.log(values);
            values.forEach(function (item, index) {
                console.log(item, index);
            });
        }
        fun(1,2,3);
    2. 扩展运算符
      let arr1 = [1,3,5];
      let arr2 = [2,...arr1,6];
      arr2.push(...arr1);
-->
<script type="text/javascript">
    function foo(a, ...value) {
        console.log(arguments);
        // arguments.callee();

        console.log(value);
        // arguments.forEach(function (item,index) {
        //     console.log(item,index);
        // });
        value.forEach(function (item, index) {
            console.log(item, index);
        });
    }

    foo(2, 66, 33, 86);

    let arr = [1, 6];
    let arr1 = [2, 3, 4, 5];
    arr = [1, ...arr1, 6];
    console.log(arr);
    console.log(...arr);

</script>
</body>
</html>

形参默认值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>08_形参默认值</title>
</head>
<body>
<!--
    * 形参的默认值----当不传入参数的时候默认使用形参里的默认值
    function Point(x = 1,y = 2) {
        this.x = x;
        this.y = y;
    }
-->
<script type="text/javascript">
    // 定义一个点的坐标的构造函数
    function Point(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }

    let point = new Point(23, 35);
    console.log(point);

    let point1 = new Point();
    console.log(point1);

</script>
</body>
</html>

Promise 对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>11_Promise 对象</title>
</head>
<body>
<!--
    1. 理解:
      * Promise 对象: 代表了未来某个将要发生的事件(通常是一个异步操作)
      * 有了 promise 对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称 '回调地狱'* ES6 的 Promise 是一个构造函数, 用来生成 promise 实例
    2. 使用 promise 基本步骤(2 步):
      * 创建 promise 对象
        let promise = new Promise((resolve, reject) => {
          // 初始化 promise 状态为 pending
          // 执行异步操作
          if(异步操作成功) {
            resolve(value);// 修改 promise 的状态为 fullfilled
          } else {
            reject(errMsg);// 修改 promise 的状态为 rejected
          }
        })
      * 调用 promise 的 then()
        promise.then(function(
          result => console.log(result),
          errorMsg => alert(errorMsg)
        ))
    3. promise 对象的3个状态
      * pending: 初始化状态
      * fullfilled: 成功状态
      * rejected: 失败状态
    4. 应用:
      * 使用 promise 实现超时处理

      * 使用 promise 封装处理 ajax 请求
        let request = new XMLHttpRequest();
        request.onreadystatechange = function () {
        }
        request.responseType = 'json';
        request.open("GET", url);
        request.send();
-->

<script type="text/javascript">

    // 创建 promise 对象
    let promise = new Promise((resolve, reject) => {
        // 初始化 promise 状态:pending:初始化
        console.log('111');
        // 执行异步操作,通常是发送 ajax 请求,开启定时器
        setTimeout(() => {
            console.log('333');
            // 根据异步任务的返回结果来修改 promise 的状态
            // 异步任务执行成功
            resolve('哈哈'); // 修改 promise 的状态为 fullfilled:成功的状态
            // 异步任务执行失败
            // reject('哦豁'); // 修改 promise 的状态为 rejected:失败的状态
        }, 2000);

    });
    console.log('222');

    promise
        .then((data) => {// 成功的回调
            console.log(data, '成功了。。。');
        }, (error) => {// 失败的回调
            console.log(error, '失败了。。。');
        });

    // 定义获取新闻的功能函数
    function getNews(url) {
        let promise = new Promise((resolve, reject) => {
            // 状态:初始化
            // 执行异步任务
            // 创建 xmlHttp 实例对象
            let xmlHttp = new XMLHttpRequest();
            // 绑定监听 readyState
            xmlHttp.onreadystatechange = function () {
                if (xmlHttp.readyState === 4) { // 请求成功
                    if (xmlHttp.status === 200) {
                        // 修改状态
                        resolve(xmlHttp.responseText); // 修改 promise 的状态为成功的状态
                    } else { // 请求失败
                        reject('暂时没有新闻内容');
                    }
                }
            };

            // open 设置请求的方式以及 url
            xmlHttp.open('GET', url);
            // 发送
            xmlHttp.send();
        });
        return promise;
    }

    getNews('http://localhost:3000/news?id=3')
        .then((data) => {
            console.log(data);
            // 发送请求获取评论内容准备 url
            let commentsUrl = JSON.parse(data).commentsUrl;
            let url = 'http://localhost:3000' + commentsUrl;
            // 发送请求
            return getNews(url);
        }, (error) => {
            console.log(error);
        })
        .then((data) => {
            console.log(data);
        }, (error) => {
            console.log(error);
        });

</script>
</body>
</html>

Symbol

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Symbol</title>
</head>
<body>
<!--
    前言:ES5 中对象的属性名都是字符串,容易造成重名,污染环境
    Symbol:
    概念:ES6 中的添加了一种原始数据类型 symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象)
    特点:
      1、Symbol 属性值对应的值是唯一的,解决命名冲突问题
      2、Symbol 值不能与其他数据进行计算,包括同字符串拼串
      3for in, for of 遍历时不会遍历 symbol 属性。
    使用:
      1、调用 Symbol 函数得到 symbol 值
        let symbol = Symbol();
        let obj = {};
        obj[symbol] = 'hello';
      2、传参标识
        let symbol = Symbol('one');
        let symbol2 = Symbol('two');
        console.log(symbol);// Symbol('one')
        console.log(symbol2);// Symbol('two')
      3、内置 Symbol 值
        * 除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。
        - Symbol.iterator
        * 对象的 Symbol.iterator 属性,指向该对象的默认遍历器方法
-->

<script type="text/javascript">
    // 创建 symbol 属性值
    let symbol = Symbol();
    console.log(symbol);
    let obj = {username: 'chen', age: 26};
    obj.sex = '男';
    obj[symbol] = 'hello';
    console.log(obj);
    // for in , for of 不能遍历 symbol 属性
    for (let i in obj) {
        console.log(i);
    }

    let symbol2 = Symbol('a');
    let symbol3 = Symbol('b');
    console.log(symbol2 == symbol3);
    console.log(symbol2, symbol3);

    // 可以去定义常量
    const Person_key = Symbol('person_key');
    console.log(Person_key);

</script>
</body>
</html>

Iterator 遍历器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Iterator 遍历器</title>
</head>
<body>
<!--
    概念: iterator 是一种接口机制,为各种不同的数据结构提供统一的访问机制
    作用:
    1、为各种数据结构,提供一个统一的、简便的访问接口;
    2、使得数据结构的成员能够按某种次序排列
    3ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费。
    工作原理:
    - 创建一个指针对象(遍历器对象),指向数据结构的起始位置。
    - 第一次调用 next 方法,指针自动指向数据结构的第一个成员
    - 接下来不断调用 next 方法,指针会一直往后移动,直到指向最后一个成员
    - 每调用 next 方法返回的是一个包含 value 和 done 的对象,{value: 当前成员的值,done: 布尔值}
      * value 表示当前成员的值,done 对应的布尔值表示当前的数据的结构是否遍历结束。
      * 当遍历结束的时候返回的 value 值是 undefined,done 值为 true
    原生具备 iterator 接口的数据(可用 for of 遍历)
    1、Array
    2、arguments
    3set容器
    4、map容器
    5、String
-->

<script type="text/javascript">

    // 模拟指针对象(遍历器对象)
    function myIterator(arr) { // iterator 接口
        // 记录指针的位置
        let nextIndex = 0;
        return { // 遍历器对象
            next: function () {
                return {value: arr[nextIndex++], done: nextIndex > arr.length};
            }
        }
    }

    // 准备数据
    let arr = [1, 3, 6, 'abc'];
    let iteratorObj = myIterator(arr);
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());

    // 将 iterator 接口部署到指定的数据类型上,可以使用 for of 去循环遍历
    // 数组、字符串、arguments、set 容器、map 容器
    for (let i of arr) {
        console.log(i);
    }

    let str = 'abcdefg';
    for (let i of str) {
        console.log(i);
    }

    function fun() {
        for (let i of arguments) {
            console.log(i);
        }
    }

    fun(1, 3, 6, 'a');

    // 对象没有这个接口 obj is not iterable
    let obj = {username: 'chen', age: 26};
    // for (let i of obj) {
    //     console.log(i);
    // }

    // 等同于在指定的数据结构上部署了 iterator 接口
    // 当使用 for of 去遍历某一个数据结构的时候,首先去找 Symbol.iterator 找到了就去遍历,没有找到的话不能遍历 xxx is not iterable
    let targetData = {
        [Symbol.iterator]: function () {
            // 记录指针的位置
            let nextIndex = 0;
            return { // 遍历器对象
                next: function () {
                    return {value: this[nextIndex++], done: nextIndex > this.length};
                }
            }
        },
        name: 'chen'
    };
    // for (let i of targetData) {
    //     console.log(i);
    // }

    // 使用 3 点运算符,解构赋值,默认去调用 iterator 接口
    let arr2 = [1, 6];
    let arr3 = [2, 3, 4, 5];
    arr2 = [1, ...arr3, 6];
    console.log(arr2);
    let [a, b] = arr2;
    console.log(a, b);

</script>
</body>
</html>

Generator 函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Generator 函数</title>
</head>
<body>

<!--
 Generator 函数
  概念:
    1ES6 提供的解决异步编程的方案之一
    2、Generator 函数是一个状态机,内部封装了不同状态的数据,
    3、用来生成遍历器对象
    4、可暂停函数(惰性求值), yield 可暂停,next 方法可启动。每次返回的是 yield 后的表达式结果
  特点:
    1function 与函数名之间有一个星号
    2、内部用 yield 表达式来定义不同的状态
    例如:
      function* generatorExample(){
        let result = yield 'hello';  // 状态值为 hello
        yield 'generator'; // 状态值为 generator
      }
    3、generator 函数返回的是指针对象(接前面章节里 iterator),而不会执行函数内部逻辑
    4、调用 next 方法函数内部逻辑开始执行,遇到 yield 表达式停止,返回{value: yield 后的表达式结果/undefined, done: false/true}
    5、再次调用 next方法会从上一次停止时的 yield 处开始,直到最后
    6yield 语句返回结果通常为 undefined, 当调用 next 方法时传参内容会作为启动时 yield 语句的返回值。
-->
<script type="text/javascript" src="./js/jquery-1.10.1.min.js"></script>
<script type="text/javascript">

    function* myGenerator() {
        console.log('开始执行');
        let result = yield 'hello';
        console.log(result);
        console.log('暂停后,再次执行');
        yield 'generator';
        console.log('遍历完毕。。。');
        return '返回的结果';
    }

    // 生成遍历器对象
    let MG = myGenerator();
    // 执行函数,遇到 yield 后即暂停
    console.log(MG); // 遍历器对象
    let result = MG.next(); // 函数执行,遇到 yield 暂停
    console.log(result); // {value: "hello", done: false}
    result = MG.next('aaaaaaaaa'); // 函数再次启动
    console.log(result); // {value: 'generator', done: false}
    result = MG.next();
    console.log(result); // {value: undefined, done: true}表示函数内部状态已经遍历完毕

    // 对象的 symbol.iterator 属性  指向遍历器对象
    let obj = {username: 'chen', age: 26};

    obj[Symbol.iterator] = function* myTest() {
        yield 1;
        yield 2;
        yield 3;
    };
    for (let i of obj) {
        console.log(i);
    }
    // 案例练习
    /*
     * 需求:
     * 1、发送 ajax 请求获取新闻内容
     * 2、新闻内容获取成功后再次发送请求,获取对应的新闻评论内容
     * 3、新闻内容获取失败则不需要再次发送请求。
     *
     * */
    function getNews(url) {
        $.get(url, function (data) {
            console.log(data);
            let url = `http://localhost:3000${data.commentsUrl}`;
            SX.next(url);
        });
    }

    function* sendXml() {
        let url = yield getNews('http://localhost:3000/news?id=3');
        yield getNews(url);
    }

    // 获取遍历器对象
    let SX = sendXml();
    result = SX.next();

</script>
</body>
</html>

async 函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>async 函数</title>
</head>
<body>

<!--
  async 函数(源自 ES2017)
  概念: 真正意义上去解决异步回调的问题,同步流程表达异步操作
  本质: Generator 的语法糖
  语法:
      async function foo(){
        await 异步操作;
        await 异步操作;
      }
  特点:
    1、不需要像 Generator 去调用 next 方法,遇到 await 等待,当前的异步操作完成就往下执行
    2、返回的总是 Promise 对象,可以用 then 方法进行下一步操作
    3async 取代 Generator 函数的星号*await 取代 Generator 的 yield
    4、语意上更为明确,使用简单,经临床验证,暂时没有任何副作用

-->
<script type="text/javascript" src="./js/jquery-1.10.1.min.js"></script>
<script type="text/javascript">
    // async 基本使用
    async function foo() {
        return new Promise(resolve => {
            // setTimeout(() => {
            //     resolve();
            // }, 2000)
            setTimeout(resolve, 2000);
        });
    }

    async function test() {
        console.log('开始执行', new Date().toTimeString());
        await foo();
        console.log('执行完毕', new Date().toTimeString());
    }

    test();

    // async 里 await 返回值
    function test2() {
        return 'xxx';
    }

    async function asyncPrint() {
        // let result = await test2();
        let result = await Promise.resolve('promise');
        console.log(result);
        result = await Promise.reject('失败了。。。');
        console.log(result);
    }

    asyncPrint();

    // 获取新闻内容
    async function getNews(url) {
        return new Promise((resolve, reject) => {
            $.ajax({
                method: 'GET',
                url,
                success: data => resolve(data),
                error: error => resolve(false)
                // success: function (data) {
                //     resolve();
                // },
                // error: function (error) {
                //     reject();
                // }
            });
        });
    }

    async function sendXml() {
        let result = await getNews('http://localhost:30001/news?id=3');
        console.log(result);
        if (result) {
            result = await getNews('http://localhost:3000' + result.commentsUrl);
            console.log(result);
        } else {
            alert('暂时没有新闻推送');
        }
    }

    sendXml();

</script>
</body>
</html>

class

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>12_class</title>
</head>
<body>
</body>
<!--
    1. 通过 class 定义类/实现类的继承
    2. 在类中通过 constructor 定义构造方法
    3. 通过 new 来创建类的实例
    4. 通过 extends 来实现类的继承
    5. 通过 super 调用父类的构造方法
    6. 重写从父类中继承的一般方法
-->
<script type="text/javascript">
    // function Person(name, age) {
    //     this.name = name;
    //     this.age = age;
    // }
    //
    // let person = new Person('chen', 26);
    // console.log(person);

    // 定义一个人物的类
    class Person {
        // 类的构造方法
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }

        // 类的一般方法
        showName() {
            console.log('调用父类的方法');
            console.log(this.name, this.age);
        }
    }

    let person = new Person('chen', 26);
    console.log(person);
    // person.showName();

    // 子类
    class StartPerson extends Person {
        constructor(name, age, salary) {
            super(name, age); // 调用父类的构造方法
            this.salary = salary;
        }

        showName() {
            console.log('调用子类的方法');
            console.log(this.name, this.age, this.salary);
        }
    }

    let p1 = new StartPerson('wade', 36, 100000);
    console.log(p1);
    p1.showName();

</script>
</html>

字符串扩展

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>01_字符串扩展</title>
</head>
<body>
<!--
    1. includes(str) : 判断是否包含指定的字符串
    2. startsWith(str) : 判断是否以指定字符串开头
    3. endsWith(str) : 判断是否以指定字符串结尾
    4. repeat(count) : 重复指定次数
-->
<script type="text/javascript">
    let str = 'asdfwefwsdfsdf';
    console.log(str.includes('t'));
    console.log(str.includes('a'));
    console.log(str.startsWith('a'));
    console.log(str.endsWith('f'));
    console.log(str.repeat(5));
</script>
</body>
</html>

数值扩展

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>02_数值扩展</title>
</head>
<body>
<!--
    1. 二进制与八进制数值表示法: 二进制用 0b, 八进制用 0o
    2. Number.isFinite(i) : 判断是否是有限大的数
    3. Number.isNaN(i) : 判断是否是 NaN
    4. Number.isInteger(i) : 判断是否是整数
    5. Number.parseInt(str) : 将字符串转换为对应的数值
    6. Math.trunc(i) : 直接去除小数部分
-->
<script type="text/javascript">
    console.log(0b1010);
    console.log(0o56);
    console.log(Number.isFinite(Infinity));

    console.log(Number.isNaN(NaN));

    console.log(Number.isInteger(3.6));
    console.log(Number.isInteger(3.0));

    console.log(Number.parseInt('123abc'));
    console.log(Number.parseInt('a123abc'));

    console.log(Math.trunc(123.123));
</script>
</body>
</html>

数组扩展

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>03_数组扩展</title>
</head>
<body>
<button>测试1</button>
<br>
<button>测试2</button>
<br>
<button>测试3</button>
<br>

<!--
    1. Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
    2. Array.of(v1, v2, v3) : 将一系列值转换成数组
    3. find(function(value, index, arr){return true}) : 找出第一个满足条件返回 true 的元素
    4. findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回 true 的元素下标
-->
<script type="text/javascript">
    let btns = document.getElementsByTagName('button');
    Array.from(btns).forEach(function (item, index) {
        console.log(item);
    });

    let arr = Array.of(1, 3, 6, 7, 8, 'abc', true);
    console.log(arr);

    let arr2 = [2, 3, 5, 6, 3, 6, 8, 9, 6, 2, 9];
    let result = arr2.find(function (item, index) {
        return item > 4;
    });
    console.log(result);
    result = arr2.findIndex(function (item, index) {
        return item > 4;
    });
    console.log(result);

</script>
</body>
</html>

对象扩展

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>04_对象扩展</title>
</head>
<body>
<!--
    1. Object.is(v1, v2)
      * 判断 2 个数据是否完全相等
    2. Object.assign(target, source1, source2..)
      * 将源对象的属性复制到目标对象上
    3. 直接操作 __proto__ 属性
      let obj2 = {};
      obj2.__proto__ = obj1;
-->

<script type="text/javascript">
    console.log(0 === -0); // true
    console.log(NaN == NaN); // false
    console.log(Object.is(0, -0)); // false
    console.log(Object.is(NaN, NaN)); // true

    let obj = {};
    let obj1 = {username: 'chen', age: 26};
    let obj2 = {sex: '男'};
    Object.assign(obj, obj1, obj2);
    console.log(obj);

    let obj3 = {};
    let obj4 = {money: 6000000};
    obj3.__proto__ = obj4;
    console.log(obj3);
    console.log(obj3.money);

</script>
</body>
</html>

对象的深度克隆

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>对象的深度克隆</title>
</head>
<body>

<!--
  1、数据类型:
    * 数据分为基本的数据类型(String, Number, boolean, Null, Undefined)和对象数据类型
    - 基本数据类型:
      特点: 存储的是该对象的实际数据
    - 对象数据类型:
      特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
  2、复制数据
    - 基本数据类型存放的就是实际的数据,可直接复制
      let number2 = 2;
      let number1 = number2;
    - 克隆数据:对象/数组
      1、区别: 浅拷贝/深度拷贝
         判断: 拷贝是否产生了新的数据还是拷贝的是数据的引用
         知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
         let obj = {username: 'kobe'}
         let obj1 = obj; // obj1 复制了obj在栈内存的引用
      2、常用的拷贝技术
        1). arr.concat(): 数组浅拷贝
        2). arr.slice(): 数组浅拷贝
        3). JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据
        4). 浅拷贝包含函数数据的对象/数组
        5). 深拷贝包含函数数据的对象/数组
-->
<script type="text/javascript">
    // 不会影响原数据
    // let str = "abc";
    // let str2 = str;
    // console.log(str2);
    // str2 = '';
    // console.log(str);
    //
    // let bool1 = true;
    // let bool2 = bool1;
    // bool2 = false;
    // console.log(bool1);
    //
    // let obj = {username: 'chen', age: 26};
    // let obj1 = obj;
    // console.log(obj1);
    // obj1.age = 27;
    // console.log(obj);
    //
    // // 拷贝数组/对象 没有生成新的数据而是复制了一份引用
    // let arr = [1, 4, {username: 'chen', age: 26}];
    // let arr2 = arr;
    // arr2[1] = 3;
    // console.log(arr);

    /*
    * 拷贝数据:
    *   基本数据类型:
    *       拷贝后会生成一份新的数据,修改拷贝以后的数据不会影响原数据
    *   对象/数组
    *       拷贝后不会生成一份新的数据,而是拷贝的引用。修改拷贝以后的数据会影响原数据
    *   拷贝数据的方法:
    *       1. 直接赋值给一个变量    // 浅拷贝
    *       2. Object.assign()      // 浅拷贝
    *       3. Array.prototype.concat() // 浅拷贝
    *       4. Array.prototype.slice()  // 浅拷贝
    *       5. JSON.parse(JSON.stringify()) // 深拷贝(深度克隆),拷贝的数据里面不能有函数,处理不了。
    *   浅拷贝(对象/数组)
    *       特点:拷贝的引用,修改拷贝以后的数据会影响原数据,使得原数据不安全
    *   深拷贝(深度克隆)
    *       特点:拷贝的时候会生成一份新的数据,修改拷贝以后的数据不会影响原数据
    * */

    // let obj = {username: 'chen'};
    // let obj2 = Object.assign(obj);
    // console.log(obj2);
    // obj2.username = 'haha';
    // console.log(obj);
    //
    // let arr = [1, 3, {username: 'chen'}, function () {}];
    // let testArr = [2, 4];
    // let arr2 = arr.concat();
    // console.log(arr2);
    // arr2[1] = 'a';
    // console.log(arr);
    // arr2[2].username = 'haha';
    // console.log(arr);
    // let arr3 = arr.slice();
    // console.log(arr3);
    // arr3[2].username = 'chen';
    // console.log(arr);
    //
    // console.log('-------------');
    // let arr4 = JSON.parse(JSON.stringify(arr));
    // console.log(arr4);
    // arr4[2].username = 'oo';
    // console.log(arr);

    /*
    * 思考:
    *   如何实现深度拷贝(克隆)
    *   拷贝的数据里有对象/数组
    *   拷贝的数据里不能有对象/数组
    *   即使有对象/数组可以继续遍历对象、数组拿到里边每一项值,一直拿到是基本数据类型,然后再去复制,就是深度拷贝
    *
    * */
    // 知识点储备
    /*
    * 如何判断数据类型:arr ---> Array null ---> Null
    *   1.typeof 返回的数据类型:String, Number, Boolean, Undefined, Object, Function
    *   2.Object.prototype.toString.call(obj)
    *
    * */
    let result = 'abc'; // [object String]
    result = null; // [object Null]
    result = [1, 3]; // [object Array]
    result = {username: 'chen'}; // [object Object]
    console.log(Object.prototype.toString.call(result).slice(8, -1));

    // for in 循环 对象(属性名) 数组(下标)
    let obj = {username: 'chen', age: 26};
    for (var i in obj) {
        console.log(i);
    }
    let arr = [1, 3, 'abc'];
    for (let i in arr) {
        console.log(i);
    }

    // 定义检测数据类型的功能函数
    function checkedType(target) {
        return Object.prototype.toString.call(target).slice(8, -1);
    }

    // 实现深度克隆 ---> 对象/数组
    function clone(target) {
        // 判断拷贝的数据类型
        // 初始化变量 result 成为最终克隆的数据
        let result, targetType = checkedType(target);
        if (targetType === 'Object') {
            result = {};
        } else if (targetType === 'Array') {
            result = [];
        } else {
            return target;
        }

        // 变量目标数据
        for (let i in target) {
            // 获取遍历数据结构的每一项值
            let value = target[i];
            // 判断目标结构里的每一值是否存在对象/数组
            if (checkedType(value) === 'Object' || checkedType(value) === 'Array') { // 对象/数组里嵌套了对象/数组
                // 继续遍历获取到的 value 值
                result[i] = clone(value);
            } else { // 获取到的 value 值是基本数据类型或者是函数
                result[i] = value;
            }
        }
        return result;
    }

    let arr2 = [1, 3, {username: 'chen', age: 26}];
    let arr3 = clone(arr2);
    console.log(arr3);
    arr3[2].username = 'haha';
    console.log(arr2, arr3);

    let obj3 = {username: 'kobe', age: 39};
    let obj4 = clone(obj3);
    console.log(obj4);
    obj4.username = 'wade';
    console.log(obj3, obj4);

</script>
</body>
</html>

Set 和 Map 数据结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>05_Set 和 Map 数据结构</title>
</head>
<body>
<!--
    1. Set 容器 : 无序不可重复的多个 value 的集合体
      * Set()
      * Set(array)
      * add(value)
      * delete(value)
      * has(value)
      * clear()
      * size
    2. Map 容器 : 无序的 key 不重复的多个 key-value 的集合体
      * Map()
      * Map(array)
      * set(key, value) // 添加
      * get(key)
      * delete(key)
      * has(key)
      * clear()
      * size
-->

<script type="text/javascript">
    let set = new Set([1, 2, 3, 4, 5, 6, 6, 6]);
    console.log(set);
    set.add([1, 2, 3, 3, 3]);
    console.log(set);
    console.log(set.has(3));
    console.log(set.has(8));
    set.clear();
    console.log(set);

    let map = new Map([['aaa', 'username'], [36, 'age']]);
    console.log(map);
    map.set(68, 'haha');
    console.log(map);
    map.delete(36);
    console.log(map);
</script>
</body>
</html>

for of 循环

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>06_for_of 循环</title>
</head>
<body>

<!--
    for(let value of target){}循环遍历
      1. 遍历数组
      2. 遍历 Set
      3. 遍历 Map
      4. 遍历字符串
      5. 遍历伪数组
-->

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>

<script type="text/javascript">
    let arr = [1, 2, 2, 3, 4, 5, 5, 6];
    let result = arr;
    arr = [];
    let set = new Set(result);
    for (let i of set) {
        console.log(i);
        arr.push(i);
    }
    console.log(arr);

</script>
</body>
</html>

ES 7

指数幂

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
    1. 指数运算符(): **
    2. Array.prototype.includes(value) : 判断数组中是否包含指定 value

-->
<script type="text/javascript">
    console.log(3 ** 3);
    let arr = [1, 2, 3, 'abc'];
    console.log(arr.includes('abc'));

</script>
</body>
</html>
上次编辑于:
贡献者: stonebox