美文网首页工作生活
ES6 常用函数 记一次分享内容

ES6 常用函数 记一次分享内容

作者: _一九九一_ | 来源:发表于2019-07-04 11:41 被阅读0次

    ES6 新特性

    简介:

    1. ECMAScript 6.0(以下简称 ES6)是 JavaScript 新一代标准,加入了很多新的功能和语法
    2. ECMAScript 和 JavaScript 的关系是:前者是后者的规格,后者是前者的一种实现

    var let const

    var

    1. ES5 中作用域有:全局作用域、函数作用域。
    // 全局作用域
    var a = 123;
    function test() {
      console.log(a);     
    }
    test();  // 123
    
    //函数作用域
    function test() {
      var a = 123;
    }
    test(); 
    console.log(a);   // ReferenceError
    
    // 不用var  全局定义
    var z = 'n';
    function test() {
      z = 'z';        
    }
    test(); 
    console.log(z);     // z
    
    
    var z = 'n';
    function test() {
      var z = 'z';
    }
    test(); 
    console.log(z);    // n
    
    2. var声明的变量会挂载在window上。容易引起变量污染。
    // i只是用来控制循环, 但泄露为全局变量 
    for (var i = 0; i < 3; i++) { }    
    console.log(window.i);  // 3
    
    3. 变量提升
    var a = 123;
    function test() {
      console.log(a);         // a在声明前打印了  
      if(false) {           
        var a = 'abc';      // 变量提升,导致内层的 a 变量覆盖了外层的 a 变量
      }
    }
    test();  // undefined
    

    let

    ES6 中新增了块级作用域概念。

    1. 声明的变量只在块级作用域内有效
     {  
       let i = 1;  
       { let i = 2; }      
     }  
    
    if( ) { }
    
    for( ) { }
    
    
    2. 不存在变量提升(或者说存在变量提升,但不赋值),而是“绑定”在暂时性死区
    var test = 1;
    function func(){
      console.log(test);   
      let test = 2;     
    };
    func(); 
    
    3. 不能重复声明
    {
       let a = 1;
       let a = 2;
    }
    // 报错
    
    {
      let a = 10;
      var a = 1;
    }
    //报错
    

    const

    1. const一旦声明变量,就必须立即初始化
    const foo;  // 报错
    
    2. 只在声明所在的块级作用域内有效。
    {
      const MAX = 5;
    }
    console.log(MAX)   //报错
    
    3. 同样存在暂时性死区,只能在声明的位置后面使用。
    {
      console.log(MAX); // 报错
      const MAX = 5;
    }
    
    4. 不能重复声明。
    var message = 'Hello';
    const message = 'Goodbye!';
    
    let age = 25;
    const age = 30;
    
    5. const声明一个简单数据类型。一旦声明,常量的值就不能改变。
    const PI = 3.1415;
    PI // 3.1415
    
    PI = 3;  // 报错
    
    6. const 定义的复合类型的数据可以进行修改:
    const foo = { prop:1 };
    foo.prop = 2;   // 只改了数据结构,成功
    foo = {};       // 改变了指针指向,报错
    
    const a = [];
    a.push('Hello');    // 不改动指针指向,只改了数据结构
    a = ['lily'];      // 改变了指针指向,报错
    
    • 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量,const不允许更改
    • 对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了

    编程风格

    1. 建议不再使用var命令,let命令取代。两者语义相同,而且let没有副作用(全局污染,变量提升)
    2. 在let和const之间,建议优先使用const,一是const比较符合函数式编程思想,我不改变值,只新建值。二是JavaScript 编译器会对const进行优化,提高运行效率
    3. const声明常量还有两个好处,一是阅读代码的人立刻会意识到不应该修改这个值,二是万一修改了会报错
    4. 所有的函数都应该设置为常量。

    二、解构赋值

    • 解构:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,
    • 可以叫做“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
    1. 数组的解构
    let [a, b, c] = [1, 2, 3];  
    
    
    // 不完全解构:
    let [x, y] = [1, 2, 3]; 
    
    
    // 嵌套数组进行解构
    let [foo, [[bar], baz]] = [1, [[2], 3]]; 
    
    
    // 只取第三个
    let [ , , third] = ['foo', 'bar', 'baz']; 
    
    
    // 中间的不取
    let [x, , y] = [1, 2, 3];
    
    
    // 取第一个  取剩余的 
    let [head, ...other] = [1, 2, 3, 4];
    head 
    other  
     
    
    let [...other, last] = [1, 2, 3, 4];  //  报错:Rest element must be last element
    
    2. 对象的解构
    let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
    
    const { log, info, table, warn } = console; 
     
    
    3. 解构不成功系列:
    let [foo] = [];   
    // foo: undefined 
    
     
    // 如果等号的右边 是不可遍历的结构    
    let [foo] = 1;
    let [foo] = false;
    let [foo] = NaN;
    let [foo] = undefined;
    let [foo] = null;
    let [foo] = {}; 
    // 都将报错
    
    
    
    // 不同名
    let { abc } = { foo: 'aaa', bar: 'bbb' };
    // abc: undefined
    
    4. 用途:
    // 交换变量的值  
    let x = 1;
    let y = 2; 
    [x, y] = [y, x];
    
    
    // 函数 return 数组 对象  进行解构
    function getArr() {
      return [1, 2, 3];
    }
    let [a, b, c] = getArr();
    
    
    function getObj() {
      return {
        foo: 1,
        bar: 2
      };
    }
    let { foo, bar } = example();
     
    
    // 传参:参数有次序的
    function f([x, y, z]) { console.log(x,y,z) }
    f([1, 2, 3]);
    
    // 无序 也会对应着解构
    function f({x, y, z}) { console.log(x,y,z) }
    f({z: 3, y: 2, x: 1});
     
    
    // 提取接口返回的 JSON 数据
    const jsonData = {
      id: 42,
      status: 'OK',
      data: [867, 5309]
    };
    const { data } = jsonData;
    
    
    import React, { Component } from 'react';
    class SomeComponent extends Component { ... }
     
    

    编程风格

    函数的参数如果是对象的成员,优先使用解构赋值。

    const user = {
        firstName:'firstName',
        lastName:'lastName'
    }
    
    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    }
    
    // good
    function getFullName(obj) {
      const { firstName, lastName } = obj;
    }
    
    // best
    function getFullName({ firstName, lastName }) { }
    
    getFullName(user);
    

    三、模板字符串

    传统的 JavaScript 语言,输出模板通常是这样写的。

    const basket = {
      count:123,
      onSale:20
    }
     let str = 'There are ' + basket.count +  
      'items in your basket, ' +
      + basket.onSale +
      ' are on sale!';
    

    上面这种写法相当繁琐不方便,ES6 引入了模板字符串解决这个问题:

    1. 反引号(`)标识 , 变量名写在 ${ } 之中。
    const basket = {
      count:123,
      onSale:20
    }
    let str = `
      There are  ${basket.count}  items
       in your basket,  ${basket.onSale} 
      are on sale!
    `
    
    2. 进行运算
    let obj = {x: 1, y: 2};
    
    `${obj.x + obj.y}`
    
    3. 调用函数
    function fn() {
      return 'and';
    }
    
    `foo ${fn()} bar`
    

    编程风格

    静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。

    四、函数的扩展

    1. 默认值

    ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 对 0 false不友好

    function log(y) {
      y = y || '我是默认值';
      console.log(y);
    } 
    log('传值了');
    log(0);       
    log(false);
    

    ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

    // 例子1:
    function log(y = '我是默认值') {
      console.log(y);
    } 
    log(0)
    log(false)
    
    // 例子2:
    function Point(x = 0, y = 0) {
      this.x = x;
      this.y = y;
    } 
    const p = new Point();
    p // { x: 0, y: 0 }
    
    2. 函数的length属性
    • length:该函数预期传入的参数个数。
    • 指定了默认值后,后面参数的length属性将失真。
    // 默认值在不同位置的例子:
    
    (function (a) {}).length  // 没有默认值
    
    (function (a = 5) {}).length 
    
    (function (a, b, c = 5) {}).length 
    
    (function(...args) {}).length //  rest 参数   
    
    (function (a = 0, b, c) {}).length 
    
    (function (a, b = 1, c) {}).length 
    
    3. rest 参数
    // arguments 能通过下标访问 转成数组
    function sortNumbers() {
      console.log(arguments)
      return Array.prototype.slice.call(arguments);
    }
    sortNumbers(1,2,3)
    
    // rest参数 真正的数组
    const sortNumbers = (...numbers) => {
      console.log(numbers)
    }
    sortNumbers(1,2,3)
    
    
    4. 箭头函数
    • ES6 允许使用“箭头”(=>)定义函数。
    let f = () => 5;
    // 等同于
    let f = function () { return 5 };
    
    
    
    let sum = (num1, num2) => num1 + num2;
    // 等同于
    let sum = function(num1, num2) {
      return num1 + num2;
    };
    
    
     
    [1,2,3].map(function (x) {
      return x * x;
    });
    // 等同于 
    [1,2,3].map(x => x * x);
    
     
      
    const person = { 
      first:'first', 
      last:'last',
    };
    function full(person) {
      return person.first + ' and ' + person.last;
    }
    full(person)
    // 等同于 
    const full = ({ first, last }) => first + ' and ' + last; 
    full(person)
    
    • 不能使用箭头函数的情况
    // 定义对象方法的时候 不能用箭头函数
    const cat = {
      lives: 9,
      jumps: () => {
        console.log(this);    // window
        this.lives--;     
      }
    } 
    cat.jumps();       // 箭头函数只能调用外层的this  把函数上下文绑定到了 window 上
    
    // 解决方案:
    const dog = {
      lives: 9,
      jumps() {
        console.log(this === dog);    // 写成普通函数 this就指向dog
        this.lives--;     
      }
    } 
    dog.jumps();
    
    
    
    
    // 不可以当作构造函数。 因为构造函数需要有自己的this,箭头函数没有自己的this,用的是外层的this
    let X = () => {};
    x = new X(); 
    
    
    // 定义原型方法的时候 不能用箭头函数
    function Cat(name) {
        this.name = name;
    } 
    Cat.prototype.sayCatName = () => {
        console.log(this); //  window   箭头函数调用外层的this
        return this.name;
    }; 
    const cat = new Cat('Mew');
    cat.sayCatName();   // ''
    
    
    // 定义事件回调函数  不能用箭头函数
    const button = document.getElementById('myButton');
    button.addEventListener('click', () => {
        console.log(this === window); // true
        this.innerHTML = 'Clicked button';
    }); 
    

    编程风格

    • 使用匿名函数当作参数的场合
    // bad
    [1, 2, 3].map(function (x) {
      return x * x;
    }); 
    
    // best
    [1, 2, 3].map(x => x * x);
    
    • 箭头函数取代Function.prototype.bind,不应再用 self/_this/that 绑定 this。
    // bad
    const self = this;
    const boundMethod = function(...params) {
      return method.apply(self, params);
    } 
    
    // best
    const boundMethod = (...params) => method.apply(this, params);
    
    • 不要在函数体内使用 arguments 变量,使用 rest 运算符(...)代替。
    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }
    
    • 函数默认值
    // bad
    function handleThings(opts) {
      opts = opts || {};
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
    

    五、数组的扩展

    1.扩展运算符
    console.log(...[1, 2, 3])
    
    
    console.log(1, ...[2, 3, 4], 5)
    
    
    [...document.querySelectorAll('div')]
    // [<div>, <div>, <div>]
    
    
    // 合并数组
    function push(array, ...items) {
      array.push(...items);
      return array;
    }
    push([1,2,3]4,5,6)
    
    
    // 函数参数展开
    const arr = [0, 1, 2];
    function f(x, y, z) { 
      console.log(x,y,z)
    }
    f(...arr);
    
    
    // 合并数组
    const arr1 = ['a', 'b'];
    const arr2 = ['c'];
    const arr3 = ['d', 'e']; 
    // ES5 
    arr1.concat(arr2, arr3);  
    // ES6 
    [...arr1, ...arr2, ...arr3] 
    
    
    //拆分字符串
    [...'hello']
    // [ 'h', 'e', 'l', 'l', 'o' ]
    
    
    // 遍历map类型的keys
    let map = new Map([
      [1, 'one'],
      [2, 'two'],
      [3, 'three'],
    ]); 
    [...map.keys()]
    [...map.values()]
    
    
    // Generator 返回数组
    const go = function*(){
      yield 1;
      yield 2;
      yield 3;
    }; 
    [...go()]    // [1, 2, 3] 
    
    2. Array.from()
    • 将对象转为真正的数组
    • 伪数组:
      • arguments对象
      • document.querSelectAll('div') 返回的对象
      • 字符串
    // 伪数组的转换
    let arrayLike = {
        '0': 'a',
        '1': 'b',
        '2': 'c',
        length: 3,
    }; 
    console.log(arrayLike instanceof Array)  // false;
    let arr1 = [].slice.call(arrayLike);    // ES5  转换成数组
    let arr2 = Array.from(arrayLike);    // ES6  转换成数组
    
    
    // arguments对象
    function foo() {
      let args = Array.from(arguments); 
      console.log(arguments instanceof Array)  
      console.log(args instanceof Array)
    }
    foo(1,2,3); 
     
    
    // 字符串
    Array.from('string'); 
    
    • Array.from 第二个参数,作用类似于数组的map方法
    let arr = [2,3,4];
    
    Array.from(arr, x => x * x);
    // 等同于
    Array.from(arr).map(x => x * x);
    
    3. 数组实例的 includes()
    // ES5 判读是否存在与数组 
    [1,2,3,NaN].indexOf(1) !== -1 ? console.log('存在') : console.log('不存在');
    [1,2,3,NaN].indexOf(4) !== -1 ? console.log('存在') : console.log('不存在');
     //  误判  缺点:1. 不够语义化 2. 它内部使用严格相等运算符(===)进行判断 
    [1,2,3,NaN].indexOf(NaN) !== -1 ? console.log('存在') : console.log('不存在');   
      
    
    // ES6:  
    [1, 2, 3].includes(1)     // true
    [1, 2, 3].includes(4)     // false
    [1, 2, 3, NaN].includes(NaN) // true
    
    

    六.对象的扩展

    1. Object.assign()
    • 对象的合并
    const target = { a: 1, b: 1 };
    
    const source1 = { b: 2, c: 2 };
    const source2 = { c: 3 };
    
    Object.assign(target, source1, source2);
    target // {a:1, b:2, c:3}    
    
    • 自动转换成对象
    typeof Object.assign(2)   // 'object'     
    Object.assign(undefined) // 报错  
    Object.assign(null)   // 报错  undefined和null无法转成对象
    
    • 属于浅拷贝 或者说是一级深拷贝
    const obj1 = { 
      a: { b: 1 },
      c:2
    };
    const obj2 = Object.assign({}, obj1);   // 与 {} 拼接会产生一个新的对象
    
    obj1.c = 3;   
    obj2     // c不会变  一级深拷贝
    
    obj1.a.b = 2;   
    obj2      // b会跟着变 并没有开辟新地址
    
    • 数组的处理
    Object.assign([1, 2, 3], [4, 5])
    // [4, 5, 3]
    
    • 用途:
    // ES5写法  prototype 添加方法
    SomeClass.prototype.someMethod = function (arg1, arg2) {
      ···
    };
    SomeClass.prototype.anotherMethod = function () {
      ···
    };
    // ES6 prototype 添加方法
    Object.assign(SomeClass.prototype, {
      someMethod(arg1, arg2) {
        ···
      },
      anotherMethod() {
        ···
      }
    });
    
    2. Object.keys(),Object.values(),Object.entries()
    • 拿对象的keys values 键值对
    let obj1 = { foo: 'bar', baz: 42 };
    Object.keys(obj1)
    
    let obj2 = { foo: 'bar', baz: 42 };
    Object.values(obj2)
    
    let obj3 = { foo: 'bar', baz: 42 };
    Object.entries(obj3)
    
    • 与for of结合
    let {keys, values, entries} = Object;
    let obj = { a: 1, b: 2, c: 3 };
    
    // 拿obj的keys
    for (let key of keys(obj)) {
      console.log(key);  
    }
    
    // 拿obj的values
    for (let value of values(obj)) {
      console.log(value);  
    }
    
    for (let [key, value] of entries(obj)) {
      console.log(key, value); 
    }
    
    3. Object.fromEntries()
    • Object.entries()的逆操作,用于将一个键值对数组转为对象。
    Object.fromEntries([
      ['foo', 'bar'],
      ['baz', 42]
    ])
    // { foo: 'bar', baz: 42 }
    

    七. Promise

    1. 简介
    • Promise 是异步编程的一种解决方案

    • 有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。 只有异步操作的结果,可以决定当前是哪一种状态。

    • 缺点:
      无法取消Promise,一旦新建它就会立即执行,无法中途取消。
      其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
      第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    • Promise对象是一个构造函数,创造Promise实例

    • resolve: “未完成”变为“成功”

    • reject: “未完成”变为“失败”

    • 一般来说,调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolve或reject的后面。

    const promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/* 异步操作成功 */){
        return resolve(value);
      } else {
        return reject(error);
      }
    }); 
    
    2. then()
    • 第一个回调函数 状态变为resolved时调用
    • 第二个回调函数 状态变为rejected时调用
    promise.then(function(value) {
      // success  resolved时调用
    }, function(error) {
      // failure  rejected时调用 
    });
    

    拿ajax举例:

    const getJSON = function(url) {
      const promise = new Promise(function(resolve, reject){
        const handler = function() {
          if (this.readyState !== 4) {
            return;
          }
          if (this.status === 200) {
            resolve(this.response);
          } else {
            reject(new Error(this.statusText));
          }
        };
        const client = new XMLHttpRequest();
        client.open('GET', url);
        client.onreadystatechange = handler;
        client.responseType = 'json';
        client.setRequestHeader('Accept', 'application/json');
        client.send();
    
      });
    
      return promise;
    };
    
    // 一个异步
    getJSON('/posts.json').then(
       json => console.log(json),
       err => console.error('出错了', err)
    );
    
    // 嵌套异步
    getJSON('/post/1.json').then(
      post => getJSON(post.commentURL)      // 返回的还是一个Promise对象(即有异步操作)
    ).then(
      comments => console.log('resolved: ', comments),   // 等待前一个Promise对象的状态发生变化,才会被调
      err => console.log('rejected: ', err)
    ); 
    
    3. catch()
    // bad
    promise
      .then(function(data) {
        // success
      }, function(err) {
        // error
      });
    
    // good     可以捕获then执行中的错误,也更接近同步的写法(try/catch)
    promise 
      .then(function(data) { 
        // success      
      })
      .catch(function(err) {
        // error
      });
    
    4. Promise.all()
    • 6 个 Promise 实例, 6个都成功或1个失败 才会走回调
    • 6个都成功:返回值组成一个数组给回调
    const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
      return getJSON('/post/' + id + '.json');
    });
    
    Promise.all(promises).then(function (posts) {
      // ...
    }).catch(function(reason){
      // ...
    });
    

    八. Iterator(遍历器)

    • 遍历器(Iterator):是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作
    • ES6新增:Map Set 结构
    let m = new Map();
    m.set('numberA', 67);
    m.set('numberB', 88);
    m.get('numberA');   
    
    let s = new Set([1, 2, 3, 3, '3']);
    s; // Set {1, 2, 3, "3"}
    
    • ES6 新增遍历命令for...of循环,Iterator 接口主要供for...of消费, Set 和 Map 结构、arguments对象、DOM NodeList 对象、Generator 对象,以及字符串。

    • 任何数据结构只要部署 Iterator 接口

    let iterable = {
      0: 'a',
      1: 'b',
      2: 'c',
      length: 3,
      [Symbol.iterator]: Array.prototype[Symbol.iterator]
    };
    for (let item of iterable) {
      console.log(item); // 'a', 'b', 'c'
    }
    
    • 原生具备 Iterator 接口的数据结构:
      Array, Map, Set, String, 函数的arguments对象, NodeList对象
    // Array
    const arr = ['red', 'green', 'blue'];
    for(let v of arr) {
      console.log(v); // red green blue
    }
    
    
    // Set
    const engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
    for (var e of engines) {
      console.log(e);
    }
    
    let generator = function* () {
      yield 1;
      yield 2;
      yield 5;
    };
    
    var iterator = generator();
    
    for(let v of iterator) {
      console.log(v);  
    }
    

    九. Generator

    1. 简介
    • Generator 也是异步编程的一种解决方案
    • function关键字与函数名之间有一个星号
    • 函数体内部使用yield表达式,暂停执行的标记
    • Generator函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,我们可以通过调用 next 方法,使得指针移向下一个状态
    2.语法
    • *的位置
    function * foo(x, y) { ··· }
    function *foo(x, y) { ··· }
    function* foo(x, y) { ··· }
    function*foo(x, y) { ··· }
    
    
    let obj = {
      * myGeneratorMethod() {
        ···
      }
    };
    // 等价
    let obj = {
      myGeneratorMethod: function* () {
        // ···
      }
    };
    
    • 在另一个表达式之中,必须放在圆括号里面。
    • 函数参数或放在赋值表达式的右边,可以不加括号。
    function* demo() {
      console.log('Hello' + yield);        // SyntaxError
      console.log('Hello' + yield 123);    // SyntaxError
    
      console.log('Hello' + (yield));      // OK
      console.log('Hello' + (yield 123));  // OK
    
      foo(yield 'a', yield 'b');    // OK
      let input = yield;           // OK
    }
    
    3. 方法属性
    • yield:暂停
    • next:执行
    • value:是yield表达式的值
    • done:表示遍历是否结束。
    function* helloWorldGenerator() {
      yield 'hello';
      yield 'world';
      return 'ending';
    }
    
    var hw = helloWorldGenerator();
    hw.next()
    //'   { value: 'hello', done: false }
    
    hw.next()
    // { value: 'world', done: false }
    
    hw.next()
    // { value: 'ending', done: true }
    
    hw.next()
    // { value: undefined, done: true }
    
    3. next()
    • next的参数:设置成上一个yield表达式的返回值
    • next的输出:会执行一条yield语句,并返回yield后面的值
    function* foo(x) {
      var y = 2 * (yield (x + 1));
      var z = yield (y / 3);
      return (x + y + z);
    } 
    
    let b = foo(5);
    b.next() // { value:6, done:false }    x=5, 执行第一行,输出yield的值    x+1的值6 
    b.next(12) // { value:8, done:false }  y=24,执行第二行,输出yield的值 将上一次yield表达式的值设为12   24/3=8
    b.next(13) // { value:42, done:true }  z=13  执行第三行, return (x + y + z);
    
    4. throw()、return()
    
    function* gen(x,y){
      yield 1;
      yield 2;
      yield 3;
    }
    let g = gen();
    g.next();    //{value: 1, done: false}
    g.return(5); //{value: 5, done: true}
    g.next();    //{value: undefined, done: true} 
    
     
    function* foo(x,y){
      yield 1;
      yield 2;
      yield 3;
    }
    let f = foo();
    f.next();    //{value: 1, done: false}
    f.throw(new Error('出错了'));    // Error
    f.next();    //{value: undefined, done: true} 
    
    
    
    5. 异步对比
    // 传统回调函数
    ajax('url_1', () => {
        // callback 函数体
        ajax('url_2', () => {
            // callback 函数体
            ajax('url_3', () => {
                // callback 函数体
            })
        })
    })
    
    // 无法取消 Promise ,错误需要通过回调函数来捕获
    ajax('url_1')
      .then(res => {
          // 操作逻辑
          return ajax('url_2')
      }).then(res => {
          // 操作逻辑
          return ajax('url_3')
      }).then(res => {
          // 操作逻辑
      })
    
    // Generator
    function *fetch() {
        yield ajax('XXX1', () => {})
        yield ajax('XXX2', () => {})
        yield ajax('XXX3', () => {})
    }
    let it = fetch()
    let result1 = it.next()
    let result2 = it.next()
    let result3 = it.next()
    
    // async/await
    async function test() {  
      let result1 = await fetch('XXX1')
      let result2 = await fetch('XXX2')
      let result3 = await fetch('XXX3')
    }
    

    十. class

    1. 构造函数 与 class
    //ES5 生成实例对象的传统方法
    function Point(x, y) {
      this.x = x;
      this.y = y;
    } 
    Point.prototype.toString = function () {
      return `${this.x},${this.y}`
    }; 
    let p = new Point(1, 2);
    
    // ES6  class
    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      } 
      toString() {
        return  `${this.x},${this.y}`
      }
    }
    
    //其实就是调用原型上的方法。
    // 等同于   
    Point.prototype = { 
      constructor() {},
      toString() {}
    };
    
    2. new类的实例
    • 定义在this上的属性才是属于实例的本身,否则都是定义在其原型上
    • x,y绑定在point上,toString绑定在Point上
    //定义类
    class Point { 
      constructor(x, y) {
        this.x = x;
        this.y = y;
        this.toString = this.toString.bind(this);
      }
     
      toString() {  // 普通函数需绑定this
        return `${this.x},${this.y}`
      } 
    
      //toString = () => {  // 箭头函数不需要绑定this 引用外层this
      //  return `${this.x},${this.y}`
      //} 
    }
    
    let point = new Point(2, 3); 
    let { toString } = point;
    toString();  // (2, 3)
    
    // 检测自身属性中是否具有指定的属性
    point.hasOwnProperty('x') // true
    point.hasOwnProperty('y') // true
    
    point.hasOwnProperty('toString') // false
    point.__proto__.constructor === Point;  // true
    point.__proto__.hasOwnProperty('toString') // true   方法在point的原型Point上
    
    3. 继承
    • ES5继承:通过借用构造函数来继承属性, 通过原型链来继承方法
    • 先创造子类的实例对象this,然后再将父类的方法属性用call方法添加到this上面 。
    function Father(name, age){
        this.name = name;
        this.age = age;
    } 
    
    function Son(name, age){
        Father.call(this, name, age);
    }
    
    Son.prototype = Object.create(Father.prototype);  // 通过Object.crete()去关联两者的prototype
    Son.prototype.constructor = Son;                  // 将 Son 的constructor指向自己
    Son.prototype.show = function () {
        console.log(this.name,this.age);
    };
    var s = new Son('子类', 110);  
    s.show();
    
    • ES6继承
    // class构造一个父类
    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
      p() {
        return 2;
      }
    }
    
    // extends,super关键字  继承所有的属性,方法
    class ColorPoint extends Point {   // 先生成父类实例
      constructor(x, y) {         // 调用子类的构造函数修饰父类实例
        super(x, y);              // super当函数用   
        console.log(x,y);         
        console.log(super.p());   //  super当对象用
      }
    }
     
    let colorPoint = new ColorPoint('xx','yy');
    
    // 如何判断一个类是否继承了另一个类 
    Object.getPrototypeOf(ColorPoint) === Point;
    
    
    

    结束!

    相关文章

      网友评论

        本文标题:ES6 常用函数 记一次分享内容

        本文链接:https://www.haomeiwen.com/subject/pynkhctx.html