1. regenerator: npm install -g renerator 将 es6+ 语法编译成 es5 语法

社区链接

namelink
esdiscuss.orges 标准讨论社区
ecma262官方标准文档
ecma262官方标准文档

操作符

operator.

delete

ReturnIfAbrupt

IsPropertyReference ( V ): Type(V.[[Base]])Boolean,String,Symbol,BigInt, Number, Object 返回 true, 否则 false.

IsSuperReference ( V ): V.[[ThisValue]] 非空返回 true,否则 false 。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
let ref = UnaryExpression

ReturnIfAbrupt(ref)

if (ref is not ReferenceRecord) {
  return true
}

if (IsUnresolvableReference(ref)) {
  assert(ref.[[Strict]] === false)
  return true
}

if (IsPropertyReference(ref)) {
  if (IsSuperReference(ref)) {
    throw new ReferenceError()
  }
  let baseObj = ToObject(ref.[[Base]])
  let deleteStatus = baseObj.[[Delete]](ref.[[ReferencedName]])
  if (deleteStatus === false && ref.[[Strict]]) {
    throw new TypeError()
  }
  return deleteStatus
} else {
  let base = ref.[[Base]]
  assert(base is EnvironmentRecord)

  return base.DeleteBinding(ref.[[ReferencedName]])
}

in

RelationalExpression : RelationalExpression in ShiftExpression
1. Let lref be the result of evaluating RelationalExpression.
2. Let lval be ? GetValue(lref).
3. Let rref be the result of evaluating ShiftExpression.
4. Let rval be ? GetValue(rref).
5. If Type(rval) is not Object, throw a TypeError exception.
6. Return ? HasProperty(rval, ? ToPropertyKey(lval)).

code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 function in(lRelationalExp, rShiftExp) {
   let lref = lRelationalExp()
   let lval = GetValue(lref)
   let rref = rShiftExp()
   let rval = GetValue(rref)
   if (!isObject(rval)) {
     throw new TypeError('right shift expression is not object.')
   }
   return HasProperty(rval, ToProperty(lval))
 }

-> HasProperty(O, P)

Document

Document.execCommand()

Array

Array.from(items[, mapfn[, thisArg]])

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
let C = this
let mapping
if (mapfn === undefined) {
  mapping = false
} else {
  if (!IsCallable(mapfn)) {
    throw new TypeError()
  }
  mapping = true
}

let usingIterator = GetMthod(items, @@iterator)
let A
if (usingIterator) {
  if (IsConstructor(C)) {
    A = Construct(C)
  } else {
    // 可能是被借用了,如:Array.from.call(...)
    A = ArrayCreate(0)
  }

  let iteratorRecord = GetIterator(items, sync, usingIterator)

  let k = 0, error
  while (true) {
    if (k >= Math.pow(2, 53) - 1) {
      // 溢出了
      error = ThrowCompletion(new TypeError())
      return IteratorClose(iteratorRecord, error)
    }

    let Pk = ToString(k)
    let next = IteratorStep(iteratorRecord)

    // 知道迭代器迭代结束,没有下一个元素了作为终止条件
    if (!next) {
      // 只有一个元素
      Set(A, 'length', k, true)
      return A
    }

    let nextValue = IteratorValue(next)

    let mappedValue
    if (mapping) {
      mappedValue = Call(mapfn, thisArg, <<nextValue, k>>)
      if (mappedValue is AbruptCompletion) {
        // 终止迭代
        return IteatorClose(iteratorRecord, mappedValue)
      }
      mappedValue = mappedValue.[[Value]]
    } else {
      mappedValue = nextValue
    }

    let defineStatus = CreateDataPropertyOrThrow(A, Pk, mappedValue)

    if (defineStatus is AbruptCompletion) {
      return IteratorClose(iteratorRecord, defineStatus)
    }

    k++
  }

  // NOTE: items 不是个 iterable 对象,可能是类数组对象
  let arrayLike = ToObject(items)
  let len = LengthOfArrayLike(arrayLike)
  if (IsConstructor(C)) {
    A = Construct(C, len)
  } else {
    A = ArrayCreate(len)
  }

  let k = 0
  // 类数组对象,首先由自己的 length 属性
  while (k < len) {
    let Pk = ToString(k)
    let kValue = Get(arrayLike, Pk)
    if (mapping) {
      mappedValue = Call(mapfn, thisArg, <<kValue, k>>)
    } else {
      mappedValue = kValue
    }

    CreateDataPropertyOrThrow(A, Pk, mappedValue)

    k++
  }

  Set(A, 'length', len, true)

   return A
}

实现分两种情况:

  1. 数组类型,直接 while 循环取迭代器 next 下一个值

  2. 类数组类型,取 len while 循环对象取值设值操作

两种情况设值操作都死调用的 CreateDataPropertyOrThrow 最终使用的是 O.[[DefineOwnProperty]](P, newDesc) 给对象追加属性。

newDesc: {[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}

Array.prototype.slice(start, end)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function slice(start, end) {
  let O = ToObject(this)

  let len = LengthOfArrayLike(O)
  let relativeStart = ToIntegerOrInfinity(start)
  let k
  // 最终目的是取 start 索引
  if (relativeStart === -Infinity) {
    k = 0
  } else if (relativeStart < 0) {
    k = max(len + relativeStart, 0)
  } else {
    k = min(relativeStart, len)
  }

  let relativeEnd
  // 取结束索引
  if (end === undefined) {
    relativeEnd = len
  } else {
    relativeEnd = ToIntegerOrInfinity(end)
  }

  // 和 relativeStart 一样做一遍索引处理
  let final
  if (relativeEnd === -Infinity) {
    final = 0
  } else if (relativeEnd < 0) {
    final = max(len + relativeEnd, 0)
  } else {
    final = min(relativeEnd, len)
  }

  let count = max(final - k, 0)
  // 创建个空数组
  let A = ArraySpeciesCreate(O, count)
  let n = 0 // 数组长度
  while (k < final) {
    let Pk = ToString((k))
    let kPresent = HasProperty(O, count)
    if (kPresent) {
      // 已经存在
      let kValue = Get(O, Pk)
      // 创建新属性
      CreateDataPropertyOrThrow(A, ToString(n), kValue)
    }

    k++
    n++
  }

  Set(A, 'length', n, true)
  return A
}

Array.prototype.reverse()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function revers() {
  const O = ToObject(this)

  let len = LengthOfArrayLike(O)
  let middle = floor(len / 2)
  let lower = 0

  while (lower !== middle) {
    let upper = len - lower - 1 // 对称的最后面那个
    let upperP = ToString(upper)
    let lowerP = ToString(lower)
    let lowerExists = HasProperty(O, lowerP)
    let lowerValue, upperValue
    if (lowerExists) {
      lowerValue = Get(O, lowerP)
    }
    let upperExists = HasProperty(O, upperP)
    if (upperExists) {
      upperValue = Get(O, upperP)
    }

    if (lowerExists && upperExists) {
      // 值互换
      set(O, lowerP, upperValue, true)
      set(O, upperP, lowerValue, true)
    } else if (!lowerExists && upperExists) {
      set(O, lowerP, upperValue, true)
      DeletePropertyOrThrow(O, upperP) // 因为左侧没值,所以将右侧位置删除
    } else if (lowerExists && !upperExists) {
      DeletePropertyOrThrow(O, lowerP) // 因为右侧没值,所以将左侧位置删除
      set(O, upperP, lowerValue, true)
    } else {
      assert(!lowerExists && !upperExists)
    }

    lower++
  }

  return O
}

Map

Map([iterable])

Map.prototype.clear()

Map.prototype.constructor

Map.prototype.delete(key)

Map.prototype.entries()

Map.prototype.forEach(callback)

Map.prototype.get(key)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function get(key) {
  let M = this

  RequireInternalSlot(M, [[MapData]])

  let entries = M.[[MapData]] // list

  for (let { [[Key]], [[Value]] }p of entries) {
    if (p.[[Key]] && SameValueZero(p.[[Key]], key)) return p.[[Value]]
  }

  return undefined
}

取出Map 数据列表,遍历找到满足条件的值。

Map.prototype.has(key)

Map.prototype.keys()

Map.prototype.set(key,value)

Map.prototype.size

Map.prototype.values()

Proxy & Reflect

可被代理的接口列表:

内部方法代理handler方法原子操作Reflect 方法
[[GetProtoypeOf]]getPrototypeOfObject.getPrototypeOf(target)Reflect.getPrototypeOf(obj)
[[SetPrototypeOf]]setPrototypeOfObject.setPrototypeOf(target, proto)Reflect.setPrototypeOf(obj, protoObj)
[[IsExtensible]]isExtensibleObject.isExtensible(proxy)Reflect.isExtensible(obj)
[[PreventExtensions]]preventExtensionsObject.preventExtensions(obj)Reflect.preventExtensions(obj)
[[GetOwnProperty]](P)getOwnPropertyDescriptorObject.getOwnPropertyDescriptorReflect.getOwnPropertyDescriptor(obj, 'prop')
[[DefineOwnProperty]](P, desc)defineProperty属性定义函数: Object.defineProperty(obj, key, value)Reflect.defineProperty(obj, 'prop', descriptors)
[[HasProperty]](P)has属性检测操作符: name in objReflect.has(obj, 'prop')
[[Get]](P, Receiver)get取值操作,如: obj.nameReflect.get(obj, prop)
[[Set]](P, V, Receiver)set赋值操作,如: obj.name = 1Reflect.set(obj, prop, value)
[[Delete]](P)deleteProperty属性删除操作,如: delete obj.nameReflect.deleteProperty(obj.prop)
[[OwnPropertyKeys]]()ownKeysObject.getOwnPropertyNamesObject.getOwnPropertySymbolsReflect.ownKeys(obj)
[[Call(thisArgument, argumentsList)]]apply函数调用 proxy1(1, 2) 操作触发Reflect.apply(target, thisArg, argumentsList)
[[Construct]](argumentsList, newTarget)constructnew Func() 操作Reflect.construct(fn, args)

ProxyCreate(target, handler)abstract

  1. 创建基本对象 P

  2. 设置内部函数 -> handler 函数映射

  3. Callable(target) 单独处理

  4. Construct(target) 单独处理

  5. 设置 P.[[ProxyHandler]] = handler

  6. 设置 P.[[ProxyTarget]] = target

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function ProxyCreate(target, handler) {
  if (Type(target) !== 'object') {
    throw new TypeError('target required object.')
  }

  if (Type(handler) !== 'object') {
    throw new TypeError('handler required object.')
  }

  let P = MakeBasicObject(<<[[ProxyHandler]], [[ProxyTarget]]>>)

  // 设置 P 除了 [[Call]] 和 [[Construct]] 之外的主要内部方法

  // Internal Method -> Handler Method
  // [[GetPrototypeOf]] -> getPrototypeOf
  // [[SetPrototypeOf]] -> setPrototypeOf
  // [[IsExtensible]] -> isExtensible
  // [[PreventExtensions]] -> preventExtensions
  // [[GetOwnProperty]] -> getOwnPropertyDescriptor
  // [[DefineOwnProperty]] -> defineProperty
  // [[HasProperty]] -> has
  // [[Get]] -> get
  // [[Set]] -> set
  // [[Delete]] -> deleteProperty
  // [[OwnPropertyKeys]] -> ownKeys
  // [[Call]] -> apply
  // [[Construct]] -> construct

  if (IsCallable(target)) {
    // set P.[[Call]]
    if (IsConstructor(target)) {
      // set P.[[Construct]]
    }
  }

  P.[[ProxyTarget]] = target
  P.[[ProxyHandler]] = handler

  return P
}

[[Construct(argumentsList, newTarget)]] abstract

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function [[Construct]](argumentsList, newTarget) {
  let handler = O.[[ProxyHandler]]
  if (!handler) {
    throw new TypeError('handler is null')
  }

  assert(Type(handler) === 'object')

  let target = O.[[ProxyTarget]]

  assert(IsConstructor(target) === true)

  let trap = GetMethod(handler, 'construct')

  if (trap === undefined) {
    return Construct(target, argumentsList, newTarget)
  }

  let argArray = CreateArrayFromList(argumentsList)
  let newObj = Call(trap, handler, <<target, argArray, newTarget>>)

  if (Type(newObj) !== 'object') {
    throw new TypeError('create new object error')
  }

  return newObj
}

[[Call]](thisArgument, arugmentList) abstract

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
function [[Call]](thisArgument, argumentsList) {
  let handler = O.[[ProxyHandler]]

  if (!handler) {
    throw new TypeError('no handler.')
  }

  assert(Type(handler) === 'object')

  let target = O.[[ProxyTarget]]
  let trap = GetMethod(handler, 'apply')

  if (!trap) {
    return Call(target, thisArgument, argumentsList)
  }

  let argArray = CreateArrayFromList(argumentsList)

  return Call(trap, handler, <<target, thisArgument, argArray>>)
}

TODO ES2017

ProposalStage-
Object.values/Object.entries3对象操作

Object.keys ( O )

EnumerableOwnPropertyNames, CreateArrayFromList

1
2
3
4
5
6
7
8
9
  function keys(O) {
    let obj = Object(O)

    // 遍历对象的键
    let nameList = EnumerableOwnPropertyNames(obj, key)

    // 创建数组
    return CreateArrayFromList(nameList)
  }

Object.values ( O )

EnumerableOwnPropertyNames, CreateArrayFromList

1
2
3
4
5
6
7
8
9
  function keys(O) {
    let obj = Object(O)

    // 遍历对象的键
    let nameList = EnumerableOwnPropertyNames(obj, value)

    // 创建数组
    return CreateArrayFromList(nameList)
  }

Object.entries( O )

1
2
3
4
5
6
7
8
9
  function keys(O) {
    let obj = Object(O)

    // 遍历对象的键
    let nameList = EnumerableOwnPropertyNames(obj, key+value)

    // 创建数组
    return CreateArrayFromList(nameList)
  }

TODO ES2016

ProposalStage-
Array.prototype.includes4原定用 contains 但是不兼容
Exponentiation Operator4
SIMD.JS - SIMD APIs + polyfill3一种类似向量的数据类型
Async Functions3async...await 语法,实现规范
String padding3
Trailing commas in function parameter lists and calls3
Object.getOwnPropertyDescriptors3
function.sent metaproperty2
Rest/Spread Properties2
Shared memory and atomics2
Function.prototype.toString revision2
ArrayBuffer.transfer1
Additional export-from Statements1
Class and Property Decorators1
Observable1
String.prototype.{trimLeft,trimRight}1
Class Property Declarations1
String#matchAll1
Callable class constructors1
System.global1
Asynchronous Iterators1

接口相关:

  1. Array.prototype.includes

  2. Object.getOwnPropertyDescriptors

  3. Function.prototype.toString

  4. String.prototype.{trimLeft,trimRight}

  5. String#matchAll

  6. System.global

    Array.prototype.includes ( searchElement [ , fromIndex ] )s4

indexOf 比较:

  1. 语义明确。

  2. 支持 NaN 检测,因为 indexOf 是使用恒等(Strict Equality Comparison)进行比较 的, includes 使用的是 SameValueZero 进行比较。

  3. 遍历的时候不会忽略 missing array 元素(俗称:hole 元素,比如 map 的时候就会跳 过这些元素),而是将他们视为 undefined

1
2
  console.log('[1, NaN 2] index of `NaN`: ' + [1, NaN, 2].indexOf(NaN)) // -1
  console.log('[1, NaN 2] includes `NaN`: ' + [1, NaN, 2].includes(NaN)) // true

result:

  [1, NaN 2] index of `NaN`: -1
  [1, NaN 2] includes `NaN`: true

伪码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  function includes(searchElement[, fromIndex]) {
    let O = Object(this)
    let len = LengthOfArrayLike(O)
    if (len === 0) {
      return false
    }

    // 默认是 0
    let n = int(fromIndex) || 0

    let k
    if (n >= 0) {
      k = n

    } else {
      // 小于零从右开始数
      k = len + n
      if (k < 0) k = 0
    }

    while (k < len) {
      let elementK = get(O, String(k))
      // 这里使用的是类 0 值,而非恒等比较
      if (SameValueZero(searchElement, elementK)) {
        return true

      }
      k++
    }

    return false
  }

⚠️ includes 并不强烈要求调用者是个数组对象,如上伪码实现中使用的是 LengthOfArrayLike(O) 即类数组的对象都可以使用它。

1
2
3
4
5
6
7
8
9
  var obj = {
    length: 2,
    0: 'foo',
    1: 'bar'

  }

  // 这里借用一下数组的函数
  console.log([].includes.call(obj, 'foo'))

+RESULTS:

true

为什么不用 has

has 常用来检测键 "keys", includes 用来检测值 "values",如:

  1. Map 类型

    Map.prototype.has(key) Reflect.has(target, propertyKey)

  2. Set 集合类型(集合类型 value 既是 key 也是 value)

    Set.prototype.has(value)

  3. String 类型,索引 + 字符

    String.prototype.includes(searchString, position)

官方实例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  assert([1, 2, 3].includes(2) === true);
  assert([1, 2, 3].includes(4) === false);

  assert([1, 2, NaN].includes(NaN) === true);

  assert([1, 2, -0].includes(+0) === true);
  assert([1, 2, +0].includes(-0) === true);

  assert(["a", "b", "c"].includes("a") === true);
  assert(["a", "b", "c"].includes("a", 1) === false);

more…

Exponentiation Operator(幂运算符)s3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  let squared = 2 ** 2

  let cubed = 2 ** 3

  let a = 2
  a **= 2

  let b = 3
  b **= 3
  console.log({ squared, cubed, a, b })
{ squared: 4, cubed: 8, a: 4, b: 27 }

more…

纯概念

伪码

C

CreateImmutableBinding(N, S)

CreateImmutableBinding(N, S), 在当前的 Environment Record 中为未初始化的 N 创建一个新的不可变(Immutable)的绑定,前提是该绑定关系之前没有发生过,如果 S 值为 true 则该关系会被视为严格绑定(即严格模式和非严格模式)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  function CreateImmutableBinding(N, S) {
    // 1. 取当前环境
    let envRec = DeclarativeEnvirnomentRecord

    // 2. 断言:envRec 中没有 N 的绑定关系
    assert(envRec..notBinding(N))

    // 3. 创建绑定,且 record 是未初始化状态
    envRec.ImmutableBinding(N)

    // 4. 严格模式
    if (S === true) {
      envRec..Strict = True
    }

    // 正常结束
    return NormalCompletion(empty)
  }

CreateArrayFromList ( elements )

CreateDataPropertyOrThrow

用 List 创建数组类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  function CreateArrayFromList( elements ) {
    assert(elements is List)

    // 创建一个空数组
    let array = ArrayCreate(0)

    let n = 0

    for (let e of elements) {
      CreateDataPropertyOrThrow(array, ToString(n), e)
      n++
    }

    return array
  }

CreateDataPropertyOrThrow ( O, P, V )

CreateDataProperty, IsPropertyKey

抽象操作:为对象创建一个新的属性和对应的值,如果失败抛出异常。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  function CreateDataPropertyOrThrow ( O, P, V ) {
    assert(Types(O) is Object)

    // 是不是合法的对象属性名
    assert(IsPropertyKey(P) === true)

    let success = CreateDataProperty(O, P, V)

    if (!success) throw new TypeError()

    return success
  }

CreateDataProperty ( O, P, V )

抽象操作:创建对象属性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  function CreateDataProperty ( O, P, V ) {
    assert(Type(O) === Object)

    assert(IsPropertyKey(P) === true)

    // 对象属性描述符对象
    let newDesc = PropertyDescriptor{
      [[Value]]: V,
      [[Writable]]: true,
      [[Enumerable]]: true,
      [[Configurable]]: true
    }

    return O.[[DefineOwnProperty]](P, newDesc)
  }

失败情况(返回 false):

  1. 属性不可配置(Configurable: false)

  2. O 是不可扩展类型

E

EnumerableOwnPropertyNames ( O, kind )

CreateArrayFromList

抽象操作:取出对象 O 的属性或值(key, value, 或 key+value)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  function EnumerableOwnPropertyNames(O, kind) {
    // kind -> key, value or key+value

    // 必须是个引用类型
    assert(Type(O) === Object)

    // 自身的所有属性
    let ownKeys = O.[[OwnPropertyKeys]]()

    let properties = new List()

    for (let key of ownKeys) {
      let desc
      if (Type(key) === String) {
        // 取出值来
        desc = O.[[GetOwnProperty]](key)
        // 有效值且是可枚举的
        if (desc !== undefined && desc.[[Enumerable]]) {
          if (kind === 'key') {
            // 保存属性名
            properties.append(key)
          } else {
            let value = Get(O, key)
            if (kind === 'value') {
              // 保存属性值
              properties.append(value)
            } else {
              assert(kind === 'key+value')

              let entry = CreateArrayFromList(<key, value>)
              properties.append(entry)
            }
          }
        }
      }
    }

    return properties
  }

F

Function Definition(函数定义)

参考链接

有几种函数声明方式:

  1. FunctionDeclaration : function Identifier ( FormalParameterListopt ) { FunctionBody }

    TODO

  2. FunctionExpression : function ( FormalParameterListopt ) { FunctionBody }

    TODO

  3. FunctionExpression : function Identifier ( FormalParameterListopt ) { FunctionBody }

    关联函数: CreateImmutableBinding(N, S)

    实例,函数表达式: (function b() {})()

    伪码:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
      // 1. env 是当前可执行上下文环境变量
      let funcEnv = NewDeclarativeEnvironment(env) 
    
      // 2. 保存 funcEnv 的环境记录
      let envRec = funcEnv.env_record 
    
      // 3. 不可变绑定?
      envRec.CreateImmutableBinding(Identifier)
    
      // 4. 创建函数 new Function('a', 'b', 'return a + b')
      let closure = new Function(FormalParameterList, FunctionBody)
    
      // 5. 绑定 closure 执行环境
      closure.bind(funcEnv)
    
      // 6. 严格模式处理
      let Strict
      if ('use strict;') {
        Strict = true
      }
    
      // 7. 初始化 immutable binding ?
      envRec.InitializeImmutableBinding(Identifier, closure)
    
      return closure
    
  4. FunctionBody : SourceElementsopt

    TODO

H

HasProperty(O, p)

Link ->

-> 7.3.11 HasProperty ( O, P )

The abstract operation HasProperty takes arguments O (an Object) and P (a property key). It returns a completion record which, if its Type is normal, has a Value which is a Boolean. It is used to determine whether an object has a property with the specified property key. The property may be either an own or inherited(属性可以是自己的也可以是继承来的,即查找整个原型链). It performs the following steps when called:

  1. Assert: Type(O) is Object.

  2. Assert: IsPropertyKey(P) is true.

  3. Return ? O.HasProperty(P).

I

IsPropertyKey ( argument )

1
2
3
4
5
6
7
  function IsPropertyKey ( argument ) {
    // 只有字符串和符号是合法属性名
    if (Type(argument) === String || Type(argument) === Symbol) return true

    return false
  
  }

L

LengthOfArrayLike ( obj )

1
2
3
4
5
6
7
  function LengthOfArrayLike ( obj ) {
    // 必须是个对象类型
    assert(Type(obj) === 'object')

    // 获取对象的 length 属性,如: { 0: 'foo', 1: 'bar', length: 2 }
    return ToLength(Get(obj, 'length'))
  }

S

SameValueZero(x, y)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  function SameValueZero(x, y) {

    // 不同类型
    if (Type(x) !== Type(y)) return false

    if (Type(x) === 'number' || Type(x) === 'bigint') {
      // 数字处理
      return Type(x)::sameValueZero(x, y)
    }

    // 非数字处理
    return SameValueNonNumeric(x, y)
  }

SameValueNonNumeric ( x, y )

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  function SameValueNonNumeric ( x, y ) {
    // 因为这里只处理非数字情况
    assert(x, !Number && !BigInt)
    assert(Type(x) === Type(y))

    if (Type(x) === 'undefined') return true

    if (Type(x) === 'null') return true

    if (Type(x) === 'string') {
      // 这里比较程度,逐个字符比较,相同返回 true,否则 false
      return x === y
    }

    if (Type(x) === 'boolean') {
      if (x === true && y === true) return true
      return false
    }

    if (Type(x) === 'symbol') {
      // 比较两个符号类型的值
      return x.value === y.value
    }

    return x === y
  }

StrictEqualityComparison 严格比较

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  function StrictEqualityComparison() {
    if(Type(x) !== Type(y)) return false

    if (Type(x) === 'number' || Type(x) === 'bigint') {
      // 直接 equal 比较
      return Type(x)::equal(x, y)

    }

    // 非数字和 SameValueZero 处理一样
    return SameValueNonNumeric(x,y)
  }