【javascript】Reflect学习笔记

发布于:2025-08-01 ⋅ 阅读:(21) ⋅ 点赞:(0)

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法,这些方法与 proxy handler 的方法相同。Reflect 不是一个函数对象,因此它是不可构造的,所以不能通过 new 运算符对其进行调用,或者Reflect 对象作为一个函数来调用。Reflect 的所有属性和方法都是静态的(就像 Math 对象)。

静态方法

Reflect.apply(target, thisArgument, argumentsList)

对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。
静态方法 Reflect.apply() 通过指定的参数列表发起对目标 (target) 函数的调用

console.log(Reflect.apply(Math.floor, undefined, [1.75])) 
// 输出: 1

Reflect.construct(target, argumentsList[, newTarget])

对构造函数进行 new 操作,相当于执行 new target(...args)

function reflectConstructExample() {
  const Person = function (name, age) {
    this.name = name
    this.age = age
  }
  const person = Reflect.construct(Person, ['John', 30])
  console.log(person) 
  // 输出: Person { name: 'John', age: 30 }
}
参数
  • target 被运行的目标构造函数
  • argumentsList 类数组,目标构造函数调用时的参数
  • newTarget (可选): 作为新创建对象的原型对象的 constructor 属性,参考 new.target 操作符,默认值为 target

new.target 是一个元属性(meta property),在ECMAScript 2015 (ES6) 中引入,用于检测函数是否通过 new 关键字调用。简单来说,当一个函数用 new 关键字调用时,new.target 会指向这个函数本身;如果函数是直接调用,new.target 的值则为 undefined。

Reflect.construct() vs Object.create()

在新语法 Reflect出现之前,是通过明确指定构造函数和原型对象(使用Object.create())来创建一个对象的。

function reflectConstructExample2() {
  const OneClass = function () {
    this.name = 'oneClass'
  }
  const TwoClass = function () {
    this.name = 'twoClass'
  }
  const obj = Reflect.construct(OneClass, [])
  console.log(obj) // 输出: OneClass {name: 'oneClass'}
  console.log(obj instanceof OneClass) // 输出: true
  console.log(obj instanceof TwoClass) // 输出: false
  // 原型指向 TwoClass.prototype
  const obj1 = Reflect.construct(OneClass, [], TwoClass)
  console.log(obj1) // 输出: TwoClass {name: 'oneClass'}
  console.log(obj1 instanceof OneClass) // 输出: false
  console.log(obj1 instanceof TwoClass) // 输出: true
  //Reflect.construct之前的原型指向 TwoClass.prototype实现方法
  const obj2 = Object.create(TwoClass.prototype) // object.create 创建一个新对象,原型指向 TwoClass.prototype
  OneClass.call(obj2) // “借用” OneClass 的构造函数逻辑来初始化 obj2,对 OneClass 本身及其原型链无影响。
  console.log(obj2) // 输出: TwoClass {name: 'oneClass'}
  console.log(obj2 instanceof OneClass) // 输出: false
  console.log(obj2 instanceof TwoClass) // 输出: true
}

虽然两种方式结果相同,但在创建对象过程中仍一点不同。

  • 当使用Object.create()Function.prototype.apply()时,如果不使用new操作符调用构造函数,构造函数内部的new.target值会指向undefined

  • 当调用Reflect.construct()来创建对象,new.target值会自动指定到target(或者 newTarget,前提是 newTarget 指定了)

Reflect.defineProperty(target, propertyKey, attributes)

Object.defineProperty() 类似,如果设置成功就会返回 true

function reflectDefinePropertyExample() {
  let obj = {}
  Reflect.defineProperty(obj, 'name', {
    value: 'kk'
  })
  console.log(obj.name) // 输出: kk
  console.log(Object.getOwnPropertyDescriptor(obj, 'name'))
  //输出:{value: 'kk', writable: false, enumerable: false, configurable: false}
}

检查属性是否被成功定义:
Object.defineProperty 方法,如果成功则返回一个对象,否则抛出一个 TypeError 。所以,当定义一个属性时,可以使用 try...catch 去捕获其中任何的错误。
Reflect.defineProperty 返回 Boolean 值作为成功的标识,所以使用 if...else 来判断结果。

if (Reflect.defineProperty(target, property, attributes)) {
  // 成功
} else {
  // 失败
}

Reflect.deleteProperty(target, propertyKey)

作为函数的delete操作符,相当于执行 delete target[name]

function reflectDeletePropertyExample() {
	let obj = {
	  name: 'kk',
	  age: 18
	}
	
	console.log(Reflect.deleteProperty(obj, 'name')) // 输出: true
	console.log(obj) // 输出: { age: 18 }
	// 尝试删除被冻结的属性会失败
	Object.freeze(obj)
	console.log(Reflect.deleteProperty(obj, 'age')) // 输出: false
	// 尝试删除不存在的属性会返回 true
	console.log(Reflect.deleteProperty(obj, 'number')) // 输出: true
	var arr = [1, 2, 3, 4, 5]
	Reflect.deleteProperty(arr, '3') // true
	console.log(arr, arr.length) // 输出: [1, 2, 3, empty, 5] 5
}

上面当删除数组元素时,JavaScript 不会自动重新索引数组,而是将该位置标记为 “empty”(稀疏数组),数组长度保持为5,索引3的位置变成空位(empty)。

改进:

// 方案1:使用 splice 保持数组连续性
arr.splice(3, 1) // 输出: [1, 2, 3, 5]

// 方案2:使用 filter 创建新数组(不修改原数组)
const newArr = arr.filter((_, index) => index !== 3) // 输出: [1, 2, 3, 5]

// 方案3:显式设置为 undefined(保留位置)
Reflect.set(arr, 3, undefined) // 输出: [1, 2, 3, undefined, 5]

Reflect.get(target, propertyKey[, receiver])

获取对象身上某个属性的值,类似于 target[name]

function reflectGetExample() {
  let obj = {
    name: 'kk',
    age: 18
  }
  console.log(Reflect.get(obj, 'name')) // 输出: kk
  console.log(Reflect.get(obj, 'number')) // 输出: undefined
  let arr = [1, 2]
  console.log(Reflect.get(arr, 0)) // 输出: 1
  console.log(Reflect.get(arr, 2)) // 输出: undefined
}

receiver 参数用于指定 getter 函数中的 this 上下文。
当目标属性是访问器属性(getter)时,receiver 会作为 getter 函数的 this 值。如果省略该参数,则默认使用目标对象本身作为 this

function reflectGetExample2() {
  let obj = {
    name: 'kk',
    get greeting() {
      return `Hello, ${this.name}!`
    }
  }
  console.log(Reflect.get(obj, 'greeting')) // 输出: Hello, kk!
  const receiver = { name: 'll' }
  console.log(Reflect.get(obj, 'greeting', receiver)) // 输出: Hello, ll!
}

Reflect.getOwnPropertyDescriptor(target, propertyKey)

类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符,否则返回 undefined

function reflectGetOwnPropertyDescriptorExample() {
  let obj = {
    name: 'kk',
    age: 18
  }
  console.log(Reflect.getOwnPropertyDescriptor(obj, 'name'))
  // 输出: {value: 'kk', writable: true, enumerable: true, configurable: true}
  console.log(Reflect.getOwnPropertyDescriptor(obj, 'number')) // 输出: undefined
  console.log(Reflect.getOwnPropertyDescriptor([], 'length'))
  // 输出: {value: 0, writable: true, enumerable: false, configurable: false}
}
  • 如果该方法的第一个参数不是一个对象(一个原始值),那么将造成 TypeError 错误。
  • Object.getOwnPropertyDescriptor,非对象的第一个参数将被强制转换为一个对象处理。
    // 尝试获取非对象的属性描述符
    console.log(Object.getOwnPropertyDescriptor('a', '0'))
    //输出: {value: 'a', writable: false, enumerable: true, configurable: false}
    console.log(Reflect.getOwnPropertyDescriptor('a', '0'))
    // 输出报错: TypeError: Reflect.getOwnPropertyDescriptor called on non-object
    

Reflect.getPrototypeOf(target)

类似于 Object.getPrototypeOf()

function reflectGetPrototypeOfExample() {
  const object1 = {
    property1: 42
  }
  const proto1 = Reflect.getPrototypeOf(object1)
  console.log(proto1)
  // 输出: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
  console.log(Reflect.getPrototypeOf({}))
  // 输出: {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
  console.log(Reflect.getPrototypeOf(Reflect.getPrototypeOf({}))) // 输出: null
  console.log(Reflect.getPrototypeOf(proto1)) // 输出: null
}

在 ES2015 规范下,Reflect 抛异常,Object 强制转换非 Object 类型

console.log(Object.getPrototypeOf('foo')) 
// 输出:  String {'', constructor: ƒ, anchor: ƒ, at: ƒ, big: ƒ, …}
console.log(Reflect.getPrototypeOf('foo')) 
// 输出报错: TypeError: Reflect.getPrototypeOf called on non-object

Reflect.has(target, propertyKey)

判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。

function reflectHasExample() {
  let obj = {
    name: 'kk',
    age: 18
  }
  console.log(Reflect.has(obj, 'name')) // 输出: true
  console.log(Reflect.has(obj, 'number')) // 输出: false
  console.log(Reflect.has([], 'length')) // 输出: true
  // Reflect.has 可以用于检查数组的索引
  console.log(Reflect.has([1, 2, 3], '0')) // 输出: true
  console.log(Reflect.has([], '0')) // 输出: false
  console.log(Reflect.has([0], '1')) // 输出: false
  // Reflect.has 也可以用于检查 Symbol 属性
  let sym = Symbol('test')
  obj[sym] = 'symbol value'
  console.log(Reflect.has(obj, sym)) // 输出: true
}

Reflect.isExtensible(target)

类似于 Object.isExtensible()

function reflectIsExtensibleExample() {
  let obj = {}
  console.log(Reflect.isExtensible(obj)) // 输出: true
  Object.preventExtensions(obj) // 阻止扩展
  console.log(Reflect.isExtensible(obj)) // 输出: false
  let sealedObj = Object.seal({ name: 'kk' })
  console.log(Reflect.isExtensible(sealedObj)) // 输出: false
  let frozenObj = Object.freeze({ age: 18 })
  console.log(Reflect.isExtensible(frozenObj)) // 输出: false
  // Reflect.isExtensible 也可以用于检查数组
  let arr = [1, 2, 3]
  console.log(Reflect.isExtensible(arr)) // 输出: true
  Object.preventExtensions(arr) // 阻止扩展
  console.log(Reflect.isExtensible(arr)) // 输出: false
  // 尝试在不可扩展的字符串上使用 Reflect.isExtensible
  console.log(Reflect.isExtensible('hello'))
  // 输出报错: TypeError: Reflect.isExtensible called on non-object
}

Reflect.ownKeys(target)

返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable 影响)。它的返回值等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))

function reflectOwnKeysExample() {
  let obj = {
    [Symbol.for('comet')]: 'comet',
    name: 'kk',
    age: 18,
    773: 773,
    0: 0,
    '-1': '-1',
    [Symbol.for('meteor')]: 'meteor'
  }
  console.log(Reflect.ownKeys(obj))
  // 输出:  ['0', '773', 'name', 'age', '-1', Symbol(comet), Symbol(meteor)]
  let arr = [1, 2, 3]
  console.log(Reflect.ownKeys(arr))
  // 输出: ['0', '1', '2', 'length']
}

Reflect.preventExtensions(target)

类似于 Object.preventExtensions()。返回一个Boolean

function reflectPreventExtensionsExample() {
	let obj = {
	  name: 'kk',
	  age: 18
	}
	console.log(Reflect.preventExtensions(obj)) // 输出: true
	console.log(Reflect.isExtensible(obj)) // 输出: false
}
  • 如果该方法的 target 参数不是一个对象(是原始值),那么将造成一个 TypeError 异常。
  • 对于Object.preventExtensions() 方法,非对象的 target 参数将被强制转换为对象。
    console.log(Object.preventExtensions(1)) // 输出: 1
    console.log(Reflect.preventExtensions(1))
    // 输出报错: TypeError: Reflect.preventExtensions called on non-object
    

Reflect.set(target, propertyKey, value[, receiver])

将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回 true

function reflectSetExample() {
  let obj = {
    name: 'kk',
    age: 18
  }
  console.log(Reflect.set(obj, 'name', 'll')) // 输出: true
  console.log(obj.name) // 输出: ll
  console.log(Reflect.set(obj, 'age', 20)) // 输出: true
  console.log(obj.age) // 输出: 20
  console.log(Reflect.set('hello', 0, 'a'))
  // 输出报错: TypeError: Reflect.set called on non-object
}

Reflect.setPrototypeOf(target, prototype)

设置对象原型的函数。返回一个 Boolean,如果更新成功,则返回 true

function reflectSetPrototypeOfExample() {
	let obj = {}
	console.log(Reflect.setPrototypeOf(obj, null)) // 输出: true
}
  • 对象设置freeze
    let obj = {}
    console.log(Reflect.setPrototypeOf(obj, null)) // 输出: true
    let obj2 = Object.freeze({})
    console.log(Reflect.setPrototypeOf(obj2, null)) // 输出: false
    let obj2_1 = Object.freeze(obj)
    console.log(Reflect.setPrototypeOf(obj2_1, null))
    // 输出: true,因为 Object.freeze() 冻结的对象的原型已经是 null,再次设置null返回true
    console.log(Reflect.setPrototypeOf(obj2_1, {})) // 输出: false
    
  • 对象设置seal
     let obj = {}
     let obj3 = Object.seal({})
     console.log(Reflect.setPrototypeOf(obj3, null)) // 输出: false
     let obj3_1 = Object.seal(obj)
     console.log(Reflect.setPrototypeOf(obj3_1, null)) // 输出: true
     console.log(Reflect.setPrototypeOf(obj3_1, {})) // 输出: false
    
  • 对象设置preventExtensions
    let obj = {}
    let obj4 = Object.preventExtensions({})
    console.log(Reflect.setPrototypeOf(obj4, null)) // 输出: false
    let obj4_1 = Object.preventExtensions(obj)
    console.log(Reflect.setPrototypeOf(obj4_1, null)) // 输出: true
    console.log(Reflect.setPrototypeOf(obj4_1, {})) // 输出: false
    
  • 如果导致原型链循环,则返回 false
    const target = {}
    const proto = Object.create(target)
    console.log(Reflect.setPrototypeOf(target, proto)) // 输出: false
    

参考

NMD Reflect


网站公告

今日签到

点亮在社区的每一天
去签到