ECMAScript Apis 内部实现伪代码

374 阅读4分钟

原文地址(原文会一直不断更新): blog.gcl666.com/2019/07/08/…

简介

本文将维护且不断更新 ECMAScript 标准下一些常见,或最新的 API 或功能实现伪码。

参考地址: tc39.es/ecma262/#se…

可直接在版本一章 5 找到本文中所有 Api 。

本文约定:

  1. 标题右上角的 数组n-year 表示该 API 发布的版本及年份

    比如:ES6 是 ECMASCript 2015 代表 {6-2015}

Object

Object.assign(target, …sources)6-2015

实现原理图:

img

伪码:


function assign(target, ...sources) {
  let to = ToObjecct(target);

  // 1. 只有目标参数,原样返回
  if (arguments.length === 1) {
    return to;
  }

  // 2. 获取后面的参数列表,要合并到 target 里面的对象列表
  let sources = List(sources); // 参数列表

  // 3. 取到当前循环中的源对象
  for (let nextSource in sources) {
    // 3.1 非法情况不做处理
    if (nextSource !== undefined || nextSource !== null) {
      let from = ToObject(nextSource);

      // 3.2 取出当前对象的所有自身的 keys
      let keys = from.[[OwnPropertyKeys]]();

      // 3.3 遍历这些 keys 取出非 Undefined 且可枚举的属性
      // 添加到 target 对象上去
      for (let nextKey in keys) {
        let desc = from.[[GetOwnProperty]][nextKey];

        if (desc !== undefined && desc.[[Enumerable]] === true) {
          let propValue = Get(from, nextKey);
          Set(to, nextKey, propValue, true);
        }
      }
    }
  }

  // 4. 返回扩展之后的目标对象
  return to;
}

Object.prototype.toString(obj)

// toString(object)

function toString(obj) {
  // 1. 判断 undefined 和 null
  if (this === undefined) {
    return '[object Undefined]';
  }

  if (this === null) {
    return '[object Null]';
  }

  let O = ToObject(this); // 上下文变量对象化
  let isArray = IsArray(O); // 先判断是不是数组类型
  let builtinTag = ''

  let has = builtinName => !!O.builtinName;

  // 2. 根据内置属性,检测各对象的类型
  if (isArray === true) { // 数组类型
    builtinTag = 'Array';
  } else if ( has([[ParameterMap]]) ) { // 参数列表,函数参数对象
    // 函数的参数 arguments 对象
    builtinTag = 'Arguments';
  } else if ( has([[Call]]) ) { // 函数
    builtinTag = 'Function';
  } else if ( has([[ErrorData]]) ) { // Error对象
    builtinTag = 'Error';
  } else if ( has([[BooleanData]]) ) { // Boolean 布尔对象
    builtinTag = 'Boolean';
  } else if ( has([[StringData]]) ) { // String 对象
    builtinTag = 'String';
  } else if ( has([[DateValue]]) ) { // Date 对象
    builtinTag = 'Date';
  } else if ( has([[RegExpMatcher]]) ) { // RegExp 正则对象
    builtinTag = 'RegExp';
  } else {
    builtinTag = 'Object' // 其他
  }

  // 3. 最后检测 @@toStringTag - Symbol.toStringTag 的值
  let tag = Get(O, @@toStringTag);

  if (Type(tag) !== 'string') {
    tag = builtinTag;
  }

  return `[object ${tag}]`;
}


Symbol

Symbol.for(key)6-2015

在全局符号注册表(Global Symbol Registry)中创建或查找符号值,返回一个符号变量。

Symbol.for = function (key) {

  // 1 key 转字符串
  let stringKey = ToString(key);

  // 2. 遍历 GlobalSymbolRegistryList 注册表
  for (let e in GlobalSymbolRegistryList) {
    // 符号值已经存在
    if (SameValue(e.[[Key]], stringKey)) {
      return e.[[Symbol]];
    }
  }

  // 3. 注册表中不含 `stringKey` 的符号值,则创建新的符号值
  // 3.1 新建符号值
  let newSymbol = Symbol(stringKey);
  // 3.1 给 [[Description]] 赋值
  newSymbol.[[Description]] = stringKey;

  // 4. 注册到符号注册表中去
  GlobalSymbolRegistryList.push({
    [[Key]]: stringKey,
    [[Symbol]]: newSymbol
  });

  // 5. 返回新建的符号值
  return newSymbol;

}

Generator 抽象操作(Abstract Operations)

GeneratorStart(generator, generatorBody)6-2015

实现包含:

  • generator 状态初始化
  • 将当前的执行上下文交给 generator
  • 如果恢复执行(next())
    1. 执行 generator 函数体,得到执行结果
    2. 断言执行过程是否异常(assert.throw)或无内容(assert.return)直接返回
    3. 函数体执行完,释放栈帧,重置下一个栈帧为当前运行栈帧
    4. 将 Generator 状态置为 'completed' ,因为到这里表示正常执行完成了
    5. 根据 result.[ [Type]] 类型(normal, return, throw) 决定 value 的值
    6. 最后得到 {value: xxx, done: true/false } 将结果返回
  • 否则,保存上下文到 generator, 然后改变状态为 suspendedStart
function GeneratorStart(generator, generatorBody) {

  // Assert: 初始状态
  generator.[[GeneratorState]] = undefined;

  // 取出栈顶的运行时栈帧
  let genContext = RunningExecutionContext;

  // 当前执行上下文的执行组件,设置成当前逐个 generator
  genContext.component = generator;

  // 调用 next() 触发代码执行
  if (evaluation.resumed) {
    // 执行 generator 的内容,得到结果
    let result = eval(generatorBody),
        resultValue;

    // Assert: 直接返回
    if (assert.return) {
      return;
    }

    // Assert: 出现异常
    if (assert.throw) {
      throw new Error()
    }

    // generator body 执行完成,删除该栈帧 genContext
    ExecutionContextStack.delete(genContext);
    // 将栈顶的栈帧置为当前运行的栈帧
    RunningExecutionContext = ExecutionContextStack.unshift();

    // 设置 generator 的状态:已完成,此时该 generator 已经执行完成
    // 执行上下文被删除,永远不会再恢复,后面其他的代码都不会被执行而丢弃掉
    generator.[[GeneratorState]] = 'completed';

    // 处理结果值 { value: xxx, done: false/true }
    // 根据结果类型,决定 value 的值
    if (result.[[Type]] === 'normal') {
      // 正常情况,返回 { value: undefined, done: true }
      resultValue = undefined;
    } else if (result.[[Type]] === 'return') {
      resultValue = result.[[Value]];
    } else {
      if (result.[[Type]] === 'throw'){
        throw new Error();
      }

      // 返回结果值 { value: xxx, done: true }
      return Completion(result);
    }
  }

  // 没有调用 next() 将状态置为挂起,保存 generator 的执行上下文
  generator.[[GeneratorContext]] = genContext;
  generator.[[GeneratorState]] = 'suspendedStart';
  return NormalCompletion(undefined);
}

img

版本链接

< ECMAScript 2015

Api 链接(Link)
Object.prototype.toString(obj) Link->2.2

ECMAScript 2015(ES6)

Api 链接(Link)
Object.assign(target, ...sources) Link->2.1
Symbol.for(key) Link->3.1
GeneratorStart(generator, generatorBody) Link->4.1