洗牌算法三种继承Promise

向下滚动可查看阅读进度

  • 洗牌算法

把一个数组里的元素随机打乱顺序(Fisher-Yates 洗牌算法)

const shuffle = (arr) => {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = (Math.floor((i + 1) * Math.random())[
      //math.random生成[0,1)区间随机数
      (arr[j], arr[i])
    ] = [arr[i], arr[j]]);
  }
  return arr;
};
  • 继承套餐

    • 原型继承

      function Person() {
        this.name = "Navi";
      }
      
      Person.prototype.eating = function () {
        console.log("eating");
      };
      //相当于定义了一个person类
      
      function Student() {}
      
      Student.prototype = new Person();
      //prototype也是对象(用来挂方法),可以换成一个person实例
      
      const stu = new Student();
      
      console.log(stu.name); // "juege"
      stu.eating(); // "eating"
    • 借用构造函数继承

      function Person(name) {
        this.name = name;
        this.hobbies = ["eat", "sleep"];
      }
      function Students(name, number) {
        Person.call(this, name);
        // 此时 this 指向当前新创建的 Student 实例(s1,s2)
        // Person.call(this, name)
        // 相当于让Person里面的this指向当前 Student 实例
        // 从而把Person中定义的属性添加到 Student 实例上
        this.number = number;
        //students自己的this
      }
      const s1 = new Students("Tom", 1001);
      const s2 = new Students("Jerry", 1002);
      
      console.log(s1);
      console.log(s2);
      // {
      //   name: 'Tom',
      //   hobbies: ['eat', 'sleep'],
      //   number: 1001
      // }
    • 寄生组合式继承(把子类原型的 proto 接到父类原型上)

      还不太会敲

      function Person(name, age) {
        // 每个实例自己的属性
        this.name = name;
        this.age = age;
      }
      
      // 父类原型上的共享方法
      Person.prototype.running = function () {
        console.log("我会跑");
      };
      
      function Student(name, age, number) {
        // 1. 借用父构造函数
        // 让 Person 里的 this 指向当前 Student 实例
        // 所以 name、age 会直接添加到 Student 实例自己身上
        Person.call(this, name, age);
      
        // Student 自己的属性
        this.number = number;
      }
      
      inheritPrototype(Student, Person);
      
      function inheritPrototype(children, parent) {
        children.prototype = Object.create(parent.prototype);
        //@param o — Object to use as a prototype.
        //aka Student.prototype.__proto__ = Person.prototype
        //s1 自己找不到某个属性时,就去 Student.prototype 上找。
      
        //上一句把 children.prototype 整个换成了一个新对象
        // 原来 Student.prototype 里的 constructor: Student 就没了
        //
        // 所以重新给新的 Student.prototype 加上constructor: Student
        Object.defineProperty(children.prototype, "constructor", {
          value: children, // constructor 指回 Student
          enumerable: false, // 不可枚举
          configurable: true, // 可以再次修改
          writable: true, // 可以重新赋值
        });
      }
  • Promise

    Promise → resolve/reject → then/catch

    .then() 的第一个回调(箭头函数)会在 Promise fulfilled 后执行;.then() 的第二个回调或 .catch() 会在 Promise rejected 后执行。

    resolve(value) 会让 Promise 进入 fulfilled 状态,value 会传给 .then() 里面的第一个箭头函数。

    reject(error) 会让 Promise 进入 rejected 状态,error 会传给 .then() 的第二个箭头函数,没有的话就会传给 .catch() ,当然then只会返回一个promise

    .then() 或 .catch() 返回的新 Promise:回调正常 return 普通值 -> fulfilled; 回调 throw new Error(“出错!”) 或者return Promise.reject(…) -> rejected;

    .then()里面如果自己报错,也会被后面的 catch 接住。

    Promise.all()是JavaScript中的一个静态方法,它接受一个Promise实例的数组作为参数,(或者它接受一个可迭代对象作为参数,其中可以包含 Promise 或普通值)并返回一个新的 Promise。并返回一个新的Promise实例。这个新的Promise实例的状态将在所有传递的Promise实例都变为fulfilled,并且它的完成值将是一个包含所有传递Promise实例完成值的数组。

    当所有传递的Promise实例都fulfilled,then()方法指定的回调函数将被调用,并且它的参数将是一个包含所有Promise实例完成值的数组(也就是前面说的)。如果其中任意一个Promise实例的状态变为已失败,则Promise.all()方法返回的Promise实例的状态也将变为已失败,并且将调用catch()方法指定的回调函数。

    • 手写 Promise.all 基础版
      function promiseAll(promises) {
      // promiseAll 自己也要返回一个 Promise
      // 这样外面才能继续 .then() / .catch()
      return new Promise((resolve, reject) => {
      
      // 用来保存每一个 Promise 成功后的结果
      const res = []
      
      // len 一开始表示 Promise 的数量
      // 后面每成功一个就 len--
      let len = promises.length
      
      // 如果传进来的是空数组 []
      // 直接成功,结果就是 []
      if (!len) resolve(res)
      
      // 某一个 Promise 成功之后调用这个函数
      function fulfill(idx, val) {
      
        // 按原来的下标保存结果
        // 不能用 push,因为 Promise 完成顺序不一定和传入顺序一样
        res[idx] = val
      
        // 成功完成一个
        len--
      
        // len === 0
        // 说明所有 Promise 都成功了
        if (!len) {
          resolve(res)
        }
      }
      
      // 遍历每一个 Promise
      promises.forEach((promise, idx) => {
      
        // Promise.resolve(promise)
        // 如果 promise 本来就是 Promise,就直接使用
        // 如果是普通值,比如 1,就包装成成功的 Promise
        Promise.resolve(promise)
      
          // 当前 Promise 成功
          // val 就是它 resolve 出来的结果
          .then((val) => fulfill(idx, val))
      
          // 当前 Promise 失败
          // 任意一个失败,整个 Promise.all 直接失败
          .catch((e) => reject(e))
        })
      })

    }

    - 手写 Promise.all 加强版
    ```js
    function promiseAll(iterable){
    const promises = Array.from(iterable)
    //把可迭代对象转为数组(常见的可迭代对象有ArrayStringSet集合Map)
    return new Promise((resolve,reject)=>{
    const result=[]
    let count=0
    const len=promises.length
    if(len===0){
      resolve(result)
    }
    
    promises.forEach((promise,index)=>{
    Promise.resolve(promise).then(
      (value)=>{
        result[index]=value
        count++
        if(count===len)resolve(result)
      }
    ).catch(reject)//失败后再调用这个Promise的reject
    //等价于.catch((error)=>reject(error))
    })
    
    })
    }
    
    • 手写 Promise.allSettled
      • 不管成功失败都等完
      • 最后返回每一个 Promise 的状态
    Promise.allSettled = function (promises) {
    // allSettled 最终不会因为某个子 Promise 失败而 reject
    // 所以这里甚至只需要 resolve
    return new Promise((resolve) => {
    
      // map 会把每一个 Promise 转换成一个“永远会成功”的 Promise
      const results = promises.map((promise) => {
    
        return promise.then(
          // 当前 Promise 成功
          (value) => {
            // 不直接返回 value
            // 而是包装成一个对象
            return {
              status: "fulfilled",
              value: value
            }
          },
    
          // 当前 Promise 失败
          (reason) => {
          // .then() 或 .catch() 返回的新 Promise:
          // 回调正常 return 普通值 -> fulfilled
          // 回调 throw 错误 -> rejected
          // 回调 return Promise.reject(...) -> rejected
            return {
              status: "rejected",
              reason: reason
            }
          }
        )
      })
    
      // 此时 results 里面的每一个 Promise
      // 都会成功,不会失败
      //
      // 所以就可以放心使用 Promise.all
      Promise.all(results).then((settledResults) => {
        // 全部结束以后,把所有结果返回
        resolve(settledResults)
      })
    })

}