关注前端小讴,阅读更多原创技术文章

代理捕获器与反射方法

  • 代理可以捕获13 种不同的基本操作,代理对象上执行的任一种操作只会有一种捕获处理程序被调用,不存在重复捕获现象
  • 只要在代理上操作,所有捕获器都会拦截对应的反射 API 操作

相关代码 →

get()

  • 获取属性值的操作中被调用,对应的反射 API 方法为Reflect.get(target, property, receiver)

    • 返回值

      • 无限制
    • 拦截的操作

      • proxy.property
      • proxy[property]
      • Object.create(proxy)[property]
      • Reflect.get(proxy,property,receiver)
    • 捕获器处理程序参数

      • target:目标对象
      • property:目标对象的键属性(字符串键或符号键)
      • receiver:代理对象或继承代理对象的对象
    • 捕获器不变式

      • 如果target.property不可写且不可配,处理程序返回值必须target.property匹配
      • 如果target.property不可配置且[[Get]]特性为undefined,处理程序返回值必须undefined
const myTarget = {
  foo: 'bar',
}
const proxy = new Proxy(myTarget, {
  get(target, property, receiver) {
    console.log(target) // { foo: 'bar' },目标对象
    console.log(property) // 'foo',目标对象键属性
    console.log(receiver) // { foo: 'bar' },代理对象
    return Reflect.get(...arguments)
  },
})
console.log(proxy.foo) // 'bar',拦截的操作

// 捕获器不变式
Object.defineProperty(myTarget, 'foo', {
  configurable: false, // 不可配置
})
const proxy2 = new Proxy(myTarget, {
  get() {
    return 'baz' // 试图重写
  },
})
console.log(proxy2.foo) // TypeError

set()

  • 设置属性值的操作中被调用,对应的反射 API 方法为Reflect.set(target, property, value, receiver)

    • 返回值

      • 布尔值,true 成功 / false 失败(严格模式下抛出 TypeError)
    • 拦截的操作

      • proxy.property = value
      • proxy[property] = value
      • Object.create(proxy)[property] = value
      • Reflect.get(proxy,property,receiver) = value
    • 捕获器处理程序参数

      • target:目标对象
      • property:目标对象的键属性(字符串键或符号键)
      • value:要赋给属性的值
      • receiver:接收最初赋值的对象
    • 捕获器不变式

      • 如果target.property不可写且不可配,则不能修改目标属性的值
      • 如果target.property不可配置且[[Set]]特性为undefined,则不能修改目标属性的值
      • 严格模式下,处理程序返回false会抛出 TypeError
const myTarget2 = {}
const proxy3 = new Proxy(myTarget2, {
  set(target, property, value, receiver) {
    console.log(target) // {},目标对象
    console.log(property) // 'foo',目标对象键属性
    console.log(value) // 'baz',要赋给属性的值
    console.log(receiver) // {},接收最初赋值的对象
    console.log(Reflect.set(...arguments)) // true,操作成功
    return Reflect.set(...arguments)
  },
})
proxy3.foo = 'baz' // 拦截的操作
console.log(proxy3.foo) // 'baz'
console.log(myTarget2.foo) // 'baz',赋值转移到目标对象上

// 捕获器不变式
Object.defineProperty(myTarget2, 'foo', {
  configurable: false, // 不可配置
  writable: false, // 不可重写
})
const proxy4 = new Proxy(myTarget2, {
  set() {
    console.log(Reflect.set(...arguments)) // false,操作失败
    return undefined
  },
})
proxy4.foo = 'bar'
console.log(proxy4.foo) // 'baz'
console.log(myTarget2.foo) // 'baz'

has()

  • in 操作符中被调用,对应的反射 API 方法为Reflect.has(target, property)

    • 返回值

      • 布尔值,表示属性是否存在,非布尔值会被转型为布尔值
    • 拦截的操作

      • property in proxy
      • property in Object.create(proxy)
      • with(proxy) {(property)}
      • Reflect.has(proxy,property)
    • 捕获器处理程序参数

      • target:目标对象
      • property:目标对象的键属性(字符串键或符号键)
    • 捕获器不变式

      • 如果target.property存在且不可配置,则处理程序必须返回true
      • 如果target.property存在且目标对象不可扩展,则处理程序必须返回true
const myTarget3 = { foo: 'bar' }
const proxy5 = new Proxy(myTarget3, {
  has(target, property) {
    console.log(target) // { foo: 'bar' },目标对象
    console.log(property) // 'foo',目标对象键属性
    console.log(Reflect.set(...arguments)) // true,属性存在
    return Reflect.set(...arguments)
  },
})
'foo' in proxy5 // 拦截的操作

// 捕获器不变式
Object.defineProperty(myTarget3, 'foo', {
  configurable: false, // 不可配置
})
const proxy6 = new Proxy(myTarget3, {
  has() {
    return false // 试图返回false
  },
})
'foo' in proxy6 // TypeError

defineProperty()

  • Object.defineProperty()中被调用,对应的反射 API 方法为Reflect.defineProperty(target, property, descriptor)

    • 返回值

      • 布尔值,表示属性是否成功定义,非布尔值会被转型为布尔值
    • 拦截的操作

      • Object.defineProperty(proxy, property, descriptor)
      • Reflect.defineProperty(proxy, property, descriptor)
    • 捕获器处理程序参数

      • target:目标对象
      • property:目标对象的键属性(字符串键或符号键)
      • descriptor:描述符对象(描述符对象的属性:configurableenumerablewritablevaluegetset的一个或多个)
    • 捕获器不变式

      • 如果目标对象不可扩展,则无法定义属性
      • 如果目标对象有一个可配置的属性,则不能添加同名的不可配置属性
      • 如果目标对象有一个不可配置的属性,则不能添加同名的可配置属性
const myTarget4 = {}
const proxy7 = new Proxy(myTarget4, {
  defineProperty(target, property, descriptor) {
    console.log(target) // {},目标对象
    console.log(property) // 'foo',目标对象键属性
    console.log(descriptor) // { value: 'bar' },描述符对象
    console.log(Reflect.defineProperty(...arguments)) // true,属性定义成功
    return Reflect.defineProperty(...arguments)
  },
})
Object.defineProperty(proxy7, 'foo', { value: 'bar' }) // 拦截的操作
console.log(proxy7.foo) // 'bar'
console.log(myTarget4.foo) // 'bar'

// 捕获器不变式
Object.defineProperty(myTarget4, 'fox', {
  value: 'baz',
  configurable: false, // 不可配置
})
const proxy8 = new Proxy(myTarget4, {
  defineProperty() {
    return true
  },
})
Object.defineProperty(proxy8, 'fox', {
  value: 'qux',
  configurable: true,
  writable: true,
}) // TypeError

getOwnPropertyDescriptor()

  • Object.getOwnPropertyDescriptor()中被调用,对应的反射 API 方法为Reflect.getOwnPropertyDescriptor(target, property)

    • 返回值

      • 属性的描述符对象,属性不存在时返回undefined
    • 拦截的操作

      • Object.getOwnPropertyDescriptor(proxy, property)
      • Reflect.getOwnPropertyDescriptor(proxy, property)
    • 捕获器处理程序参数

      • target:目标对象
      • property:目标对象的键属性(字符串键或符号键)
    • 捕获器不变式

      • 如果自有的target.property存在且不可配置,则处理程序必须返回一个表示该属性存在的对象
      • 如果自有的target.property存在且可配置,则处理程序必须返回该属性可可配置的对象
      • 如果自有的target.property存在且目标对象不可扩展,则处理程序必须返回一个表示该属性存在的对象
      • 如果target.property不存在且目标对象不可扩展,则处理程序必须返回undefined表示改属性不存在
      • 如果target.property不存在,则处理程序不能返回表示该属性存在的对象
const myTarget5 = { foo: 'bar' }
const proxy9 = new Proxy(myTarget5, {
  getOwnPropertyDescriptor(target, property) {
    console.log(target) // { foo: 'bar' },目标对象
    console.log(property) // 'foo',目标对象键属性
    console.log(Reflect.getOwnPropertyDescriptor(...arguments)) // { value: 'bar', writable: true, enumerable: true, configurable: true },属性的描述符对象
    return Reflect.getOwnPropertyDescriptor(...arguments)
  },
})
Object.getOwnPropertyDescriptor(proxy9, 'foo') // 拦截的操作

// 捕获器不变式
Object.defineProperty(myTarget5, 'fox', {
  value: 'baz', // 目标对象的属性存在
  configurable: false, // 不可配置
})
const proxy10 = new Proxy(myTarget5, {
  getOwnPropertyDescriptor() {
    // return undefined // TypeError,必须返回一个表示该属性存在的对象
    return {
      value: 'baz',
      writable: false,
      enumerable: false,
      configurable: false,
    }
  },
})
Object.getOwnPropertyDescriptor(proxy10, 'fox')

deleteProperty()

  • delete 操作符中被调用,对应的反射 API 方法为Reflect.deleteProperty(target, property)

    • 返回值

      • 布尔值,表示删除属性是否成功,非布尔值会被转型为布尔值
    • 拦截的操作

      • delete proxy.property
      • delete proxy[property]
      • Reflect.delete(proxy,property)
    • 捕获器处理程序参数

      • target:目标对象
      • property:目标对象的键属性(字符串键或符号键)
    • 捕获器不变式

      • 如果target.property存在且不可配置,则处理程序不能删除这个属性
const myTarget6 = { foo: 'bar' }
const proxy11 = new Proxy(myTarget6, {
  deleteProperty(target, property) {
    console.log(target) // { foo: 'bar' },目标对象
    console.log(property) // 'foo',目标对象键属性
    console.log(Reflect.deleteProperty(...arguments)) // true,删除属性成功
    return Reflect.deleteProperty(...arguments)
  },
})
delete proxy11.foo // 拦截的操作
console.log(proxy11.foo) // undefined
console.log(myTarget6.foo) // undefined

// 捕获器不变式
Object.defineProperty(myTarget6, 'fox', {
  value: 'baz', // 目标对象的属性存在
  configurable: false, // 不可配置
})
const proxy12 = new Proxy(myTarget6, {
  deleteProperty() {
    console.log(Reflect.deleteProperty(...arguments)) // false,删除属性失败
    return Reflect.deleteProperty(...arguments)
  },
})
delete proxy12.fox
console.log(proxy12.fox) // 'baz'
console.log(myTarget6.fox) // 'baz'

ownKeys()

  • Object.keys()及类似方法中被调用,对应的反射 API 方法为Reflect.ownKeys(target)

    • 返回值

      • 必须返回包含字符串或符号的可枚举对象
    • 拦截的操作

      • Object.getOwnPropertyNames(proxy)
      • Object.getOwnPropertySymbols(proxy)
      • Object.keys(proxy)
      • Reflect.ownKeys(proxy)
    • 捕获器处理程序参数

      • target:目标对象
    • 捕获器不变式

      • 返回的可枚举对象必须包含target所有不可配置的自有属性
      • 如果target不可扩展,则返回可枚举对象必须准确包含自有属性键
Object.defineProperty(myTarget7, 'fox', {
  value: 'baz',
  configurable: false, // 不可配置
})
const proxy14 = new Proxy(myTarget7, {
  ownKeys() {
    // return [] // TypeError: 'ownKeys' on proxy: trap result did not include 'fox',必须包含目标对象所有不可配置的自有属性
    return ['fox', 'qux'] // 必须包含fox键
  },
})
Object.keys(proxy14)

getPrototypeOf()

  • Object.getPrototypeOf()中被调用,对应的反射 API 方法为Reflect.getPrototypeOf(target)

    • 返回值

      • 必须返回对象或 null
    • 拦截的操作

      • Object.getPrototypeOf(proxy)
      • Reflect.getPrototypeOf(proxy)
      • proxy.__proto__
      • Object.prototype.isPrototyprOf(proxy)
      • proxy instanceof Object
    • 捕获器处理程序参数

      • target:目标对象
    • 捕获器不变式

      • 如果target不可扩展,则Object.getPrototypeOf(proxy)唯一有效的返回值就是Object.getPrototypeOf(target)的返回值
const myTarget8 = new Array(1, 2, 3)
const proxy15 = new Proxy(myTarget8, {
  getPrototypeOf(target) {
    console.log(target) // [ 1, 2, 3 ],目标对象
    console.log(Reflect.getPrototypeOf(...arguments)) // Array的原型对象,可在浏览器中查看
    return Reflect.getPrototypeOf(...arguments)
  },
})
Object.getPrototypeOf(proxy15) // 拦截的操作

// 捕获器不变式
Object.preventExtensions(myTarget8) // 不可扩展
const proxy16 = new Proxy(myTarget8, {
  getPrototypeOf(target) {
    // return [] // TypeError,唯一有效的返回值是Object.getPrototypeOf(target)的返回值
    return Object.getPrototypeOf(target) // 有效
  },
})
Object.getPrototypeOf(proxy16)

setPrototypeOf()

  • Object.setPrototypeOf()中被调用,对应的反射 API 方法为Reflect.setPrototypeOf(target, prototype)

    • 返回值

      • 布尔值,表示原型赋值是否成功,非布尔值会被转型为布尔值
    • 拦截的操作

      • Object.setPrototypeOf(proxy)
      • Reflect.setPrototypeOf(proxy)
    • 捕获器处理程序参数

      • target:目标对象
      • prototypetarget的替代原型,顶级原型则为null
    • 捕获器不变式

      • 如果target.property不可扩展,则唯一有效prototype参数就是Object.getPrototypeOf(target)的返回值
const myTarget9 = {}
const targetPrototype = { foo: 'bar' }
const proxy17 = new Proxy(myTarget9, {
  setPrototypeOf(target, prototype) {
    console.log(target) //{},目标对象
    console.log(targetPrototype) // { foo: 'bar' },target的替代原型
    console.log(Reflect.setPrototypeOf(...arguments)) // true,原型赋值成功
    return Reflect.setPrototypeOf(...arguments)
  },
})
Object.setPrototypeOf(proxy17, targetPrototype)
console.log(proxy17) // {}
console.log(proxy17.__proto__ === targetPrototype) // true
console.log(proxy17.foo) // 'bar'
console.log(myTarget9.foo) // 'bar'

// 捕获器不变式
Object.preventExtensions(myTarget9) // 不可扩展
const proxy18 = new Proxy(myTarget9, {
  setPrototypeOf() {
    return Reflect.setPrototypeOf(...arguments)
  },
})
// Object.setPrototypeOf(proxy18, targetPrototype) // TypeError,唯一有效的prototype参数是Object.getPrototypeOf(target)的返回值
Object.setPrototypeOf(proxy18, Object.getPrototypeOf(myTarget9)) // 有效
console.log(proxy18.__proto__ === Object.getPrototypeOf(myTarget9)) // true

isExtensible()

  • Object.isExtensible()中被调用,对应的反射 API 方法为Reflect.isExtensible(target)

    • 返回值

      • 布尔值,表示target是否可被扩展,非布尔值会被转型为布尔值
    • 拦截的操作

      • Object.isExtensible(proxy)
      • Reflect.isExtensible(proxy)
    • 捕获器处理程序参数

      • target:目标对象
    • 捕获器不变式

      • 如果target可扩展,则处理程序必须返回true
      • 如果target不可扩展,则处理程序必须返回false
const myTarget10 = {}
const proxy19 = new Proxy(myTarget10, {
  isExtensible(target) {
    console.log(target) // {},目标对象
    console.log(Reflect.isExtensible(...arguments)) // true,target可扩展
    return Reflect.isExtensible(...arguments)
  },
})
Object.isExtensible(proxy19) // 拦截的操作

// 捕获器不变式
Object.preventExtensions(myTarget10) // 不可扩展
const proxy20 = new Proxy(myTarget10, {
  isExtensible() {
    // return true // TypeError,不可扩展必须返回false
    console.log(Reflect.isExtensible(...arguments)) // false,target不可扩展
    return false
  },
})
Object.isExtensible(proxy20)

preventExtensions()

  • Object.preventExtensions()中被调用,对应的反射 API 方法为Reflect.preventExtensions(target)

    • 返回值

      • 布尔值,表示target是否已经不可扩展,非布尔值会被转型为布尔值
    • 拦截的操作

      • Object.preventExtensions(proxy)
      • Reflect.preventExtensions(proxy)
    • 捕获器处理程序参数

      • target:目标对象
    • 捕获器不变式

      • 如果Object.isExtensions(target)false,则处理程序必须返回true
const myTarget11 = {}
const proxy21 = new Proxy(myTarget11, {
  preventExtensions(target) {
    console.log(target) // {},目标对象
    console.log(Reflect.preventExtensions(...arguments)) // true,target已经不可扩展
    return Reflect.preventExtensions(...arguments)
  },
})
Object.preventExtensions(proxy21) // 拦截的操作

// 捕获器不变式
Object.preventExtensions(myTarget11) // 不可扩展
console.log(Object.isExtensible(myTarget11)) // false,目标对象已经不可扩展
const proxy22 = new Proxy(myTarget11, {
  preventExtensions() {
    // return false // TypeError,处理程序此时必须返回true
    return true
  },
})
Object.preventExtensions(proxy22)

apply()

  • 调用函数时被调用,对应的反射 API 方法为Reflect.apply(target, thisArg, argumentsList)

    • 返回值

      • 返回值无限制
    • 拦截的操作

      • proxy(...argumentsList)
      • Function.prototype.apply(thisArg, argumentsList)
      • Function.prototype.call(thisArg, ...argumentsList)
      • Reflect.apply(proxy, thisArg, argumentsList)
    • 捕获器处理程序参数

      • target:目标对象
      • thisArg:调用函数时的 this 参数
      • argumentsList:调用函数时的参数列表
    • 捕获器不变式

      • target必须是一个函数对象
const myTarget12 = () => {}
const targetApply = { foo: 'bar' }
const proxy23 = new Proxy(myTarget12, {
  apply(target, thisArg, argumentsList) {
    console.log(target) // [Function: myTarget12],目标对象
    console.log(thisArg) // { foo: 'bar' },调用函数时的 this 参数
    console.log(argumentsList) // [ 1, 2, 3 ],调用函数时的参数列表
    return Reflect.apply(...arguments)
  },
})
Reflect.apply(proxy23, targetApply, [1, 2, 3]) // 拦截的操作

// 捕获器不变式
const proxy24 = new Proxy(targetApply, {
  apply() {
    return Reflect.apply(...arguments)
  },
})
// proxy24() // TypeError: proxy24 is not a function,target必须是函数对象

construct()

  • new 操作符时被调用,对应的反射 API 方法为Reflect.construct(target, argumentsList, newTarget)

    • 返回值

      • 必须返回一个对象
    • 拦截的操作

      • new proxy(...argumentsList)
      • Reflect.construct(proxy, argumentsList, newTarget)
    • 捕获器处理程序参数

      • target:目标构造函数
      • argumentsList:传给目标构造函数的参数列表
      • newTarget:最初被调用的构造函数
    • 捕获器不变式

      • target必须可以用作构造函数
const MyTarget13 = function () {}
const proxy25 = new Proxy(MyTarget13, {
  construct(target, argumentsList, newTarget) {
    console.log(target) // [Function: MyTarget13],目标构造函数
    console.log(argumentsList) // [ 123 ],传给目标构造函数的参数列表
    console.log(newTarget) // [Function: MyTarget13],最初被调用的构造函数
    return Reflect.construct(...arguments)
  },
})
new proxy25(123) // 拦截的操作

const MyTarget14 = () => {} // 箭头函数,不能用作构造函数
const proxy26 = new Proxy(MyTarget14, {
  construct() {
    return Reflect.construct(...arguments)
  },
})
new proxy26() // TypeError: proxy26 is not a constructor,target必须可以用作构造函数

总结 & 问点

捕获器被调用反射 API返回值拦截操作参数不变式
get()获取属性值Reflect.get()无限制proxy.property
proxy[property]
Object.create(proxy)[property]
Reflect.get(proxy,property,receiver)
target:目标对象
property:目标对象的键属性(字符串键或符号键)
receiver:代理对象或继承代理对象的对象
如果target.property不可写且不可配,处理程序返回值必须target.property匹配
如果target.property不可配置且[[Get]]特性为undefined,处理程序返回值必须undefined
set()设置属性值Reflect.set()布尔值,配置是否成功proxy.property = value
proxy[property] = value
Object.create(proxy)[property] = value
Reflect.get(proxy,property,receiver) = value
target:目标对象
property:目标对象的键属性(字符串键或符号键)
value:要赋给属性的值
receiver:代理对象或继承代理对象的对象
如果target.property不可写且不可配,则不能修改目标属性的值
如果target.property不可配置且[[Set]]特性为undefined,则不能修改目标属性的值
严格模式下,处理程序返回false会抛出 TypeError
has()in 操作符Reflect.has()布尔值,属性是否存在property in proxy
property in Object.create(proxy)
with(proxy) {(property)}
Reflect.has(proxy,property)
target:目标对象
property:目标对象的键属性(字符串键或符号键)
如果target.property存在且不可配置,则处理程序必须返回true
如果target.property存在且目标对象不可扩展,则处理程序必须返回true
defineProperty()Object.defineProperty()Reflect.defineProperty()布尔值,属性是否成功定义Object.defineProperty(proxy, property, descriptor)
Reflect.defineProperty(proxy, property, descriptor)
target:目标对象
property:目标对象的键属性(字符串键或符号键)
如果目标对象不可扩展,则无法定义属性
如果目标对象有一个可配置的属性,则不能添加同名的不可配置属性
如果目标对象有一个不可配置的属性,则不能添加同名的可配置属性
getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor()Reflect.getOwnPropertyDescriptor()属性的描述符对象,属性不存在时返回undefinedObject.getOwnPropertyDescriptor(proxy, property)
Reflect.getOwnPropertyDescriptor(proxy, property)
target:目标对象
property:目标对象的键属性(字符串键或符号键)
如果自有的target.property存在且不可配置,则处理程序必须返回一个表示该属性存在的对象
如果自有的target.property存在且可配置,则处理程序必须返回该属性可可配置的对象
如果自有的target.property存在且目标对象不可扩展,则处理程序必须返回一个表示该属性存在的对象
如果target.property不存在且目标对象不可扩展,则处理程序必须返回undefined表示改属性不存在
如果target.property不存在,则处理程序不能返回表示该属性存在的对象
deleteProperty()delete 操作符Reflect.deleteProperty()布尔值,删除属性是否成功delete proxy.property
delete proxy[property]
Reflect.delete(proxy,property)
target:目标对象
property:目标对象的键属性(字符串键或符号键)
如果target.property存在且不可配置,则处理程序不能删除这个属性
ownKeys()Object.keys()及类似方法Reflect.ownKeys()包含字符串或符号的可枚举对象Object.getOwnPropertyNames(proxy)
Object.getOwnPropertySymbols(proxy)
Object.keys(proxy)
Reflect.ownKeys(proxy)
target:目标对象返回的可枚举对象必须包含target所有不可配置的自有属性
如果target不可扩展,则返回可枚举对象必须准确包含自有属性键
getPrototypeOf()Object.getPrototypeOf()Reflect.getPrototypeOf()对象或 nullObject.getPrototypeOf(proxy)
Reflect.getPrototypeOf(proxy)
proxy.__proto__
Object.prototype.isPrototyprOf(proxy)
proxy instanceof Object
target:目标对象如果target不可扩展,则Object.getPrototypeOf(proxy)唯一有效的返回值就是Object.getPrototypeOf(target)的返回值
setPrototypeOf()Object.setPrototypeOf()Reflect.setPrototypeOf()布尔值,原型赋值是否成功Object.setPrototypeOf(proxy)
Reflect.setPrototypeOf(proxy)
target:目标对象
prototypetarget的替代原型,顶级原型则为null
如果target.property不可扩展,则唯一有效prototype参数就是Object.getPrototypeOf(target)的返回值
isExtensible()Object.isExtensible()Reflect.isExtensible()布尔值,target是否可被扩展Object.isExtensible(proxy)
Reflect.isExtensible(proxy)
target:目标对象如果target可扩展,则处理程序必须返回true
如果target不可扩展,则处理程序必须返回false
preventExtensions()Object.preventExtensions()Reflect.preventExtensions()布尔值,target是否不可扩展Object.preventExtensions(proxy)
Reflect.preventExtensions(proxy)
target:目标对象如果Object.isExtensions(target)false,则处理程序必须返回true
apply()调用函数Reflect.apply()无限制proxy(...argumentsList)
Function.prototype.apply(thisArg, argumentsList)
Function.prototype.call(thisArg, ...argumentsList)
Reflect.apply(proxy, thisArg, argumentsList)
target:目标对象
thisArg:调用函数时的 this 参数
argumentsList:调用函数时的参数列表
target必须是一个函数对象
construct()new 操作符Reflect.construct()一个对象new proxy(...argumentsList)
Reflect.construct(proxy, argumentsList, newTarget)
target:目标构造函数
argumentsList:传给目标构造函数的参数列表
newTarget:最初被调用的构造函数
target必须可以用作构造函数

小讴
217 声望16 粉丝