Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重学js —— Proxy(代理)对象的内置方法和内置插槽 #68

Open
lizhongzhen11 opened this issue Jan 19, 2020 · 0 comments
Labels
重学js 重学js系列 规范+MDN

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Jan 19, 2020

Proxy(代理)对象的内置方法和内置插槽

proxy (代理)对象属于 怪异对象,其基本内置方法有一部分由ECMAScript代码实现。每个 proxy 对象都有 [[ProxyHandler]] 内置插槽。[[ProxyHandler]] 值是一个对象,叫做 proxyhandler object 或者为 nullhandler object 的方法(处理程序方法,见下表)可用于扩展 proxy 对象的一个或多个内部方法的实现。每个 proxy 对象也都有一个叫做 [[ProxyTarget]] 的内置插槽,其值要么是对象,要么是 null。该对象被称为该 proxytarget object(目标对象)。

Proxy Handler Methods(代理对象的处理程序方法)

内置方法 处理方法
[[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

调用 handler method 以提供代理对象内部方法的实现时,该 handler method 作为一个参数传给 proxy 的目标对象。proxyhandler object 不一定有对应每个基本内部方法的方法。如果 handler object 没有对应于内部捕获的方法,则在代理上调用内部方法将导致在代理的目标对象上调用相应的内部方法。

代理对象的 [[ProxyHandler]][[ProxyTarget]] 内置插槽在对象被创建并且通常不会被修改时初始化。一些代理对象的创建方式允许它们随后被销毁。当代理对象被销毁时,其 [[ProxyHandler]][[ProxyTarget]] 内置插槽被设为 null 导致对该代理对象的内部方法的后续调用引发 TypeError 异常。

因为代理对象允许由任意ECMAScript代码提供内部方法的实现,可以定义代理对象,其处理程序方法与 基本内部方法 中定义的不变量冲突。基本内部方法 中定义的一些内部方法不变量是基本的完整性不变量。这些不变量由本节指定的代理对象内部方法显式强制执行。ECMAScript实现必须在所有可能的不变冲突存在时都是健壮的。

在接下来的算法描述中,假设 O 为 ECMAScript 代理对象,P 是键值,VECMAScript语言值Desc属性描述符记录。

[[GetPrototypeOf]] ( )

[[SetPrototypeOf]] ( V )

[[IsExtensible]] ( )

[[PreventExtensions]] ( )

[[GetOwnProperty]] ( P )

[[DefineOwnProperty]] ( P, Desc )

[[HasProperty]] ( P )

[[Get]] ( P, Receiver )

  1. 断言:P 是键名
  2. 定义 handlerO.[[ProxyHandler]]
  3. 如果 handlernull,抛 TypeError
  4. 断言:handler 是对象
  5. 定义 targetO.[[ProxyTarget]]
  6. 定义 trap? GetMethod(handler, "get")
  7. 如果 trapundefined
    1. 返回 ? target.[[Get]](P, Receiver)
  8. 定义 trapResult? Call(trap, handler, « target, P, Receiver »)
  9. 定义 targetDesc? target.[[GetOwnProperty]] (P)
  10. 如果 targetDesc 不是 undefinedtargetDesc.[[Configurable]]false
    1. 如果 targetDesc 是数据属性描述符,且 targetDesc.[[Writable]]false
      1. 如果 SameValue(trapResult, targetDesc.[[Value]])false,抛 TypeError
    2. 如果 targetDesc 是访问器属性描述符,且 targetDesc.[[Get]]undefined
      1. 如果 trapResult 不是 undefined,抛 TypeError
  11. 返回 trapResult

注意:强制执行以下不变量:
1. 如果目标对象属性是不可写的,不可配置的自身数据属性,则为属性报告的值必须与相应目标对象属性的值相同。

2. 如果对应的目标对象属性是一个不可配置的自身访问器属性,且其 [[Get]] 属性未定义,则为属性报告的值必须未定义。

[[Set]] ( P, V, Receiver )

  1. 断言:P 是键名
  2. 定义 handlerO.[[ProxyHandler]]
  3. 如果 handlernull,抛 TypeError
  4. 断言:handler 是对象
  5. 定义 targetO.[[ProxyTarget]]
  6. 定义 trap? GetMethod(handler, "set")
  7. 如果 trapundefined
    1. 返回 ? target.[[Set]](P, V, Receiver)
  8. 定义 booleanTrapResult! ToBoolean(? Call(trap, handler, « target, P, V, Receiver »))
  9. 如果 booleanTrapResultfalse,返回 false
  10. 定义 targetDesc? target.[[GetOwnProperty]] (P)
  11. 如果 targetDescundefinedtargetDesc.[[Configurable]]false
    1. 如果 targetDesc 是数据属性描述符,且 targetDesc.[[Writable]]false
      1. 如果 SameValue(V, targetDesc.[[Value]])false,抛 TypeError
    2. 如果 targetDesc 是访问器属性描述符
      1. 如果 targetDesc.[[Set]]undefined,抛 TypeError

注意 强制执行以下不变量:
1. [[Set]] 是布尔值

2. 如果相应的目标对象属性是不可写的,不可配置的自身数据属性,则无法将属性的值更改为与相应目标对象属性的值不同的值。

3. 如果相应的目标对象属性是不可配置的自身访问器属性且其 [[Set]] 未定义,则无法设置属性的值。

[[Delete]] ( P )

[[OwnPropertyKeys]] ( )

[[Call]] ( thisArgument, argumentsList )

  • 假设Proxy 怪异对象 O
  • argumentsList 是ECMAScript语言值列表
  1. 定义 handlerO.[[ProxyHandler]]
  2. 如果 handlernull,抛 TypeError
  3. 断言:handler 是对象
  4. 定义 targetO.[[ProxyTarget]]
  5. 定义 trap? GetMethod(handler, "apply") 结果
  6. 如果 trapundefined
    1. 返回 ? Call(target, thisArgument, argumentsList)
  7. 定义 argArray! CreateArrayFromList(argumentsList) 结果
  8. 返回 ? Call(trap, handler, « target, thisArgument, argArray »)

注意:如果Proxy 怪异对象[[ProxyTarget]] 内置插槽初始值是一个有 [[Call]] 内置方法的对象,那么该Proxy 怪异对象 仅具有 [[Call]] 内置方法。

[[Construct]] ( argumentsList, newTarget )

  1. 定义 handlerO.[[ProxyHandler]]
  2. 如果 handlernull,抛 TypeError
  3. 断言:handler 是对象
  4. 定义 targetO.[[ProxyTarget]]
  5. 断言:target 是构造器
  6. 定义 trap? GetMethod(handler, "construct")
  7. 如果 trapundefined
    1. 返回 ? Construct(target, argumentsList, newTarget)
  8. 定义 argArray! CreateArrayFromList(argumentsList)
  9. 定义 newObj? Call(trap, handler, « target, argArray, newTarget »)
  10. 如果 newObj 不是对象,抛 TypeError
  11. 返回 newObj

注意:如果Proxy 怪异对象[[ProxyTarget]] 内置插槽初始值是一个有 [[Construct]] 内置方法的对象,那么该Proxy 怪异对象 仅具有 [[Construct]] 内置方法。

代理对象的 [[Construct]] 强制执行以下不变量:[[Construct]] 结果必须是对象

ProxyCreate ( target, handler )

创建新的 proxy 对象

  1. 如果 target 不是对象,抛 TypeError
  2. 如果 targetProxy 怪异对象 并且 target.[[ProxyHandler]]null,抛 TypeError
  3. 如果 handler 不是对象,抛 TypeError
  4. 如果 handlerProxy 怪异对象 并且 handler.[[ProxyHandler]]null,抛 TypeError
  5. 定义 P 为一个新创建的带有 [[ProxyTarget]][[ProxyHandler] 内置插槽的 Proxy 怪异对象
  6. 设置 P 的基本内置方法(除了 [[Call]][[Construct]])为 Proxy内置方法和内置插槽 定义的方法。
  7. 如果 target 可调用,
    1. 设置 P.[[Call]][[Call]] ( thisArgument, argumentsList )
    2. 如果 target 为构造器,
      1. 设置 P.[[Construct]][[Construct]] ( argumentsList, newTarget )
  8. 设置 P.[[ProxyTarget]]target
  9. 设置 P.[[ProxyHandler]]handler
  10. 返回 P

Proxy对象(规范第26章,移到这边)

构造器

  • 即固有对象 %Proxy%
  • 全局对象 "Proxy" 属性的初始值
  • ...

Proxy ( target, handler )

  1. 如果 NewTargetundefined,抛 TypeError 异常
  2. 返回 ? ProxyCreate(target, handler)

Proxy构造器上的属性

  • [[Prototype]] 内置插槽其值为 %Function.prototype%
  • 没有 "prototype" 属性,因为 proxy 怪异对象不需要初始化的 [[Prototype]] 内置插槽
Proxy.prototype // undefined

Proxy.revocable ( target, handler )

  1. 定义 p? ProxyCreate(target, handler)
  2. 定义 stepsProxy Revocation Functions 中定义的算法步骤
  3. 定义 revoker! CreateBuiltinFunction(steps, « [[RevocableProxy]] »)
  4. revoker.[[RevocableProxy]] 设置为 p
  5. 定义 resultOrdinaryObjectCreate(%Object.prototype%)
  6. 执行 ! CreateDataPropertyOrThrow(result, "proxy", p)
  7. 执行 ! CreateDataPropertyOrThrow(result, "revoke", revoker)
  8. 返回 result

Proxy Revocation Functions

  • 每个Proxy revocation function都有 [[RevocableProxy]] 内置插槽
  1. 定义 F活跃函数对象
  2. 定义 pF.[[RevocableProxy]]
  3. 如果 pnull,返回 undefined
  4. F.[[RevocableProxy]] 设为 null
  5. 断言:p 是 Proxy 对象
  6. p.[[ProxyTarget]] 设为 null
  7. p.[[ProxyHandler]] 设为 null
  8. 返回 undefined
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
重学js 重学js系列 规范+MDN
Projects
None yet
Development

No branches or pull requests

1 participant