【javascript】Reflect学习笔记

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

静态方法

Reflect.apply(target, thisArgument, argumentsList)

对一个函数进行调用 操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。

静态方法 Reflect.apply() 通过指定的参数列表发起对目标 (target) 函数的调用

javascript 复制代码
console.log(Reflect.apply(Math.floor, undefined, [1.75])) 
// 输出: 1

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

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

javascript 复制代码
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())来创建一个对象的。

javascript 复制代码
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

javascript 复制代码
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 来判断结果。

javascript 复制代码
if (Reflect.defineProperty(target, property, attributes)) {
  // 成功
} else {
  // 失败
}

Reflect.deleteProperty(target, propertyKey)

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

javascript 复制代码
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)。

改进:

javascript 复制代码
// 方案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]

javascript 复制代码
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

javascript 复制代码
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

javascript 复制代码
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,非对象的第一个参数将被强制转换为一个对象处理。

    javascript 复制代码
    // 尝试获取非对象的属性描述符
    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()

javascript 复制代码
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 类型

javascript 复制代码
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 运算符 的功能完全相同。

javascript 复制代码
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()

javascript 复制代码
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))

javascript 复制代码
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

javascript 复制代码
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 参数将被强制转换为对象。

    javascript 复制代码
    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

javascript 复制代码
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

javascript 复制代码
function reflectSetPrototypeOfExample() {
	let obj = {}
	console.log(Reflect.setPrototypeOf(obj, null)) // 输出: true
}
  • 对象设置freeze

    javascript 复制代码
    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

    javascript 复制代码
     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

    javascript 复制代码
    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

    javascript 复制代码
    const target = {}
    const proto = Object.create(target)
    console.log(Reflect.setPrototypeOf(target, proto)) // 输出: false

参考

NMD Reflect

相关推荐
ideaout技术团队9 小时前
leetcode学习笔记2:多数元素(摩尔投票算法)
学习·算法·leetcode
十铭忘10 小时前
Bug——PaddleX人脸识别报错:Process finished with exit code -1073741819 (0xC0000005)
学习·bug
less is more_093011 小时前
风力发电机输出功率模型综述
笔记·学习·数学建模
丰锋ff11 小时前
2006 年真题配套词汇单词笔记(考研真相)
笔记·学习·考研
二十雨辰13 小时前
vite如何处理项目中的资源
开发语言·javascript
洛可可白13 小时前
把 Vue2 项目“黑盒”嵌进 Vue3:qiankun 微前端实战笔记
前端·vue.js·笔记
想唱rap14 小时前
直接选择排序、堆排序、冒泡排序
c语言·数据结构·笔记·算法·新浪微博
早睡冠军候选人14 小时前
K8s学习----节点(Node)
运维·学习·云原生·容器·kubernetes
四月_h15 小时前
vue2动态实现多Y轴echarts图表,及节点点击事件
前端·javascript·vue.js·echarts
文心快码BaiduComate15 小时前
用Zulu轻松搭建国庆旅行4行诗网站
前端·javascript·后端