自己看

121 阅读6分钟

新增的数组API

静态方法

  • Array.of(...args): 使用指定的数组项创建一个新数组
  • Array.from(arg): 通过给定的类数组 或 可迭代对象 创建一个新的数组。

实例方法

  • find(callback): 用于查找满足条件的第一个元素
  • findIndex(callback):用于查找满足条件的第一个元素的下标
  • fill(data):用指定的数据填充满数组所有的内容
  • copyWithin(target, start?, end?): 在数组内部完成复制
  • includes(data):判断数组中是否包含某个值,使用Object.is匹配

执行上下文

函数执行上下文:一个函数运行之前,创建的一块内存空间,空间中包含有该函数执行所需要的数据,为该函数执行提供支持。

执行上下文栈:call stack,所有执行上下文组成的内存空间。

栈:一种数据结构,先进后出,后进先出。

全局执行上下文:所有JS代码执行之前,都必须有该环境。

JS引擎始终执行的是栈顶的上下文。

执行上下文中的内容

  1. this指向

1). 直接调用函数,this指向全局对象 2). 在函数外,this指向全局对象 3). 通过对象调用或new一个函数,this指向调用的对象或新对象

  1. VO 变量对象

Variable Object:VO 中记录了该环境中所有声明的参数、变量和函数

Global Object: GO,全局执行上下文中的VO

Active Object:AO,当前正在执行的上下文中的VO

1). 确定所有形参值以及特殊变量arguments 2). 确定函数中通过var声明的变量,将它们的值设置为undefined,如果VO中已有该名称,则直接忽略。 3). 确定函数中通过字面量声明的函数,将它们的值设置为指向函数对象,如果VO中已存在该名称,则覆盖。

当一个上下文中的代码执行的时候,如果上下文中不存在某个属性,则会从之前的上下文寻找。

作用域链

  1. VO中包含一个额外的属性,该属性指向创建该VO的函数本身
  2. 每个函数在创建时,会有一个隐藏属性[[scope]],它指向创建该函数时的AO
  3. 当访问一个变量时,会先查找自身VO中是否存在,如果不存在,则依次查找[[scope]]属性。

某些浏览器会优化作用域链,函数的[[scope]]中仅保留需要用到的数据。

柯里化函数

function curry (func) {
  var args = Array.prototype.slice.call(arguments, 1);
  var _this = this;
  return function () {
    var curArgs = Array.from(arguments); // 返回新函数后,再调用新函数时将传递的参数变成数组
    var totalArgs = args.concat(curArgs); // 拼接每次传递的参数数组

    // 每个函数身上都有一个length属性, 代表的是所需参数的个数
    if (totalArgs.length >= func.length) {
      // 参数数组的长度满足原函数本身所需的参数个数
      return func.apply(null, totalArgs);
    } else {
      // 参数数组长度不满足原函数所需参数个数时
      totalArgs.unshift(func);
      return _this.curry.apply(_this, totalArgs);
    }
  };
};

事件循环

异步:某些函数不会立即执行,需要等到某个时机成熟后才会执行,该函数叫做异步函数。

浏览器的线程:

  1. JS执行引擎:负责执行JS代码
  2. 渲染线程:负责渲染页面
  3. 计时器线程:负责计时
  4. 事件监听线程:负责监听事件
  5. http网络线程:负责网络通信

事件队列:一块内存空间,用于存放执行时机到达的异步函数。当JS引擎空闲(执行栈没有可执行的上下文),它会从事件队列中拿出第一个函数执行。

事件循环:event loop,是指函数在执行栈、宿主线程、事件队列中的循环移动。

原型和原型链

  • 所有对象都是通过new 函数创建
  • 所有的函数也是对象
    • 函数中可以有属性
  • 所有对象都是引用类型

原型 prototype

所有函数都有一个属性:prototype,称之为函数原型

默认情况下,prototype是一个普通的Object对象

默认情况下,prototype中有一个属性,constructor,它也是一个对象,它指向构造函数本身。

隐式原型 proto

所有的对象都有一个属性:__proto__,称之为隐式原型

默认情况下,隐式原型指向创建该对象的函数的原型。

当访问一个对象的成员时:

  1. 看该对象自身是否拥有该成员,如果有直接使用
  2. 在原型链中依次查找是否拥有该成员,如果有直接使用

猴子补丁:在函数原型中加入成员,以增强起对象的功能,猴子补丁会导致原型污染,使用需谨慎。

原型链

特殊点:

  1. Function的__proto__指向自身的prototype
  2. Object的prototype的__proto__指向null 函数是通过new Function创建的 函数是通过new Function创建的.jpg 链条的全貌 链条的全貌.jpg 每个函数都有原型对象 每个函数都有原型对象.jpg 普通对象是通过new 函数创建的 普通对象是通过new 函数创建的.jpg 隐式原型的指向 隐式原型的指向.jpg 原型中的constructor指向函数本身 原型中的constructor指向函数本身.jpg

原型链的应用

基础方法

W3C不推荐直接使用系统成员__proto__

Object.getPrototypeOf(对象)

获取对象的隐式原型

Object.prototype.isPrototypeOf(对象)

判断当前对象(this)是否在指定对象的原型链上

对象 instanceof 函数

判断函数的原型是否在对象的原型链上

Object.create(对象)

创建一个新对象,其隐式原型指向指定的对象

Object.prototype.hasOwnProperty(属性名)

判断一个对象自身是否拥有某个属性

应用

类数组转换为真数组

Array.prototype.slice.call(类数组);

实现继承

默认情况下,所有构造函数的父类都是Object

圣杯模式

Promise

const MyPromise = (() => {
    const PENDING = "pending",
        RESOLVED = "resolved",
        REJECTED = "rejected",
        PromiseValue = Symbol("PromiseValue"), //状态数据
        PromiseStatus = Symbol("PromiseStatus"),
        thenables = Symbol("thenables"), //thenable
        catchables = Symbol("catchables"), //catchables
        changeStatus = Symbol("changeStatus"),//当前状态
        settleHandle = Symbol("settleHandle"), //后续处理的通用函数
        linkPromise = Symbol("linkPromise");  //创建串联的Promise

    return class MyPromise {

        /**
         * 改变当前Promise的状态
         * @param {*} newStatus 
         * @param {*} newValue 
         * @param {*} queue 执行的作业队列
         */
        [changeStatus](newStatus, newValue, queue) {
            if (this[PromiseStatus] !== PENDING) {
                //状态无法变更
                return;
            }
            this[PromiseStatus] = newStatus;
            this[PromiseValue] = newValue;
            //执行相应队列中的函数
            queue.forEach(handler => handler(newValue));
        }

        /**
         * 
         * @param {*} executor 未决阶段(pending状态)下的处理函数
         */
        constructor(executor) {
            this[PromiseStatus] = PENDING;
            this[PromiseValue] = undefined;
            this[thenables] = []; //后续处理函数的数组 -> resolved
            this[catchables] = []; //后续处理函数的数组 -> rejected

            const resolve = data => {
                this[changeStatus](RESOLVED, data, this[thenables]);
            }

            const reject = reason => {
                this[changeStatus](REJECTED, reason, this[catchables]);
            }
            try {
                executor(resolve, reject)
            }
            catch (err) {
                reject(err);
            }
        }

        /**
         * 处理 后续处理函数
         * @param {*} handler 后续处理函数
         * @param {*} immediatelyStatus 需要立即执行的状态
         * @param {*} queue 作业队列
         */
        [settleHandle](handler, immediatelyStatus, queue) {
            if (typeof handler !== "function") {
                return;
            }
            if (this[PromiseStatus] === immediatelyStatus) {
                //直接运行
                setTimeout(() => {
                    handler(this[PromiseValue]);
                }, 0);
            }
            else {
                queue.push(handler);
            }
        }

        [linkPromise](thenable, catchable) {
            function exec(data, handler, resolve, reject) {
                try {
                    const result = handler(data); //得到当前Promise的处理结果
                    if (result instanceof MyPromise) {
                        result.then(d => {
                            resolve(d)
                        }, err => {
                            reject(err);
                        })
                    }
                    else {
                        resolve(result);
                    }
                }
                catch (err) {
                    reject(err);
                }
            }

            return new MyPromise((resolve, reject) => {
                this[settleHandle](data => {
                    exec(data, thenable, resolve, reject);
                }, RESOLVED, this[thenables])

                this[settleHandle](reason => {
                    exec(reason, catchable, resolve, reject);
                }, REJECTED, this[catchables])
            })
        }

        then(thenable, catchable) {
            return this[linkPromise](thenable, catchable);
        }

        catch(catchable) {
            return this[linkPromise](undefined, catchable);
        }


        static all(proms) {
            return new Promise((resolve, reject) => {
                const results = proms.map(p => {
                    const obj = {
                        result: undefined,
                        isResolved: false
                    }
                    p.then(data => {
                        obj.result = data;
                        obj.isResolved = true;
                        //判断是否全部完成
                        const unResolved = results.filter(r => !r.isResolved)
                        if (unResolved.length === 0) {
                            //全部完成
                            resolve(results.map(r => r.result));
                        }
                    }, reason => {
                        reject(reason);
                    })
                    return obj;
                })
            })
        }

        static race(proms) {
            return new Promise((resolve, reject) => {
                proms.forEach(p => {
                    p.then(data => {
                        resolve(data);
                    }, err => {
                        reject(err);
                    })
                })
            })
        }

        static resolve(data) {
            if (data instanceof MyPromise) {
                return data;
            }
            else {
                return new MyPromise(resolve => {
                    resolve(data);
                })
            }
        }

        static reject(reason) {
            return new MyPromise((resolve, reject) => {
                reject(reason);
            })
        }
    }
})();