当前位置: 首页 > news >正文

【javascript】Reflect学习笔记

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 = namethis.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) // 输出: trueconsole.log(obj instanceof TwoClass) // 输出: false// 原型指向 TwoClass.prototypeconst obj1 = Reflect.construct(OneClass, [], TwoClass)console.log(obj1) // 输出: TwoClass {name: 'oneClass'}console.log(obj1 instanceof OneClass) // 输出: falseconsole.log(obj1 instanceof TwoClass) // 输出: true//Reflect.construct之前的原型指向 TwoClass.prototype实现方法const obj2 = Object.create(TwoClass.prototype) // object.create 创建一个新对象,原型指向 TwoClass.prototypeOneClass.call(obj2) // “借用” OneClass 的构造函数逻辑来初始化 obj2,对 OneClass 本身及其原型链无影响。console.log(obj2) // 输出: TwoClass {name: 'oneClass'}console.log(obj2 instanceof OneClass) // 输出: falseconsole.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) // 输出: kkconsole.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')) // 输出: trueconsole.log(obj) // 输出: { age: 18 }// 尝试删除被冻结的属性会失败Object.freeze(obj)console.log(Reflect.deleteProperty(obj, 'age')) // 输出: false// 尝试删除不存在的属性会返回 trueconsole.log(Reflect.deleteProperty(obj, 'number')) // 输出: truevar arr = [1, 2, 3, 4, 5]Reflect.deleteProperty(arr, '3') // trueconsole.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')) // 输出: kkconsole.log(Reflect.get(obj, 'number')) // 输出: undefinedlet arr = [1, 2]console.log(Reflect.get(arr, 0)) // 输出: 1console.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')) // 输出: undefinedconsole.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({}))) // 输出: nullconsole.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')) // 输出: trueconsole.log(Reflect.has(obj, 'number')) // 输出: falseconsole.log(Reflect.has([], 'length')) // 输出: true// Reflect.has 可以用于检查数组的索引console.log(Reflect.has([1, 2, 3], '0')) // 输出: trueconsole.log(Reflect.has([], '0')) // 输出: falseconsole.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)) // 输出: trueObject.preventExtensions(obj) // 阻止扩展console.log(Reflect.isExtensible(obj)) // 输出: falselet sealedObj = Object.seal({ name: 'kk' })console.log(Reflect.isExtensible(sealedObj)) // 输出: falselet frozenObj = Object.freeze({ age: 18 })console.log(Reflect.isExtensible(frozenObj)) // 输出: false// Reflect.isExtensible 也可以用于检查数组let arr = [1, 2, 3]console.log(Reflect.isExtensible(arr)) // 输出: trueObject.preventExtensions(arr) // 阻止扩展console.log(Reflect.isExtensible(arr)) // 输出: false// 尝试在不可扩展的字符串上使用 Reflect.isExtensibleconsole.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)) // 输出: trueconsole.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')) // 输出: trueconsole.log(obj.name) // 输出: llconsole.log(Reflect.set(obj, 'age', 20)) // 输出: trueconsole.log(obj.age) // 输出: 20console.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)) // 输出: falselet obj3_1 = Object.seal(obj)console.log(Reflect.setPrototypeOf(obj3_1, null)) // 输出: trueconsole.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

http://www.dtcms.com/a/308630.html

相关文章:

  • OCP网卡、OVS网卡和DPU(数据处理单元)三类技术方案
  • system.conf linux用于启动和管理系统进程的初始化系统和服务管理器的配置文件
  • 检索召回率优化探究二:基于 LangChain 0.3集成 Milvus 2.5向量数据库构建的智能问答系统
  • 中国高速铁路网的“四纵四横“和“八纵八横“shp数据
  • LLM——使用 LangGraph 构建 ReAct 智能体:多轮对话 + 工具调用 + 可视化流程图
  • flowable对已经部署的流程进行更新,不产生新版本
  • 【问题】Docker 容器内的应用(如n8n),访问不到外部主机的应用(如mysql)
  • C语言基础第18天:内存操作函数
  • Jmeter 性能测试常用图表、服务器资源监控
  • AI学习笔记三十四:基于yolov5+deepsort+slowfast的视频实时行为检测测试
  • 【源力觉醒 创作者计划】文心大模型4.5体验:技术跃迁,拥抱AI新时代
  • Coze是什么?能做什么?
  • MySQL 9 INNODB Cluster部署
  • Qt之CJSON:从基础到进阶的 JSON 数据处理指南
  • MySQL 8.0 OCP 1Z0-908 题目解析(41)
  • 节目预告:工程师张仰彪在相对论学习中的九个疑问
  • 【Kubernetes 指南】基础入门——Kubernetes 集群(一)
  • python每日一题练习---简单题目
  • 基于STM32设计的景区便民服务系统(NBIOT)_261
  • IDEA识别lombok注解问题
  • MySQL常用命令完整指南
  • systmctl的作用,使用场景和用法
  • 硬件-音频学习DAY1——音箱材料选择:密度板为何完胜实木
  • 动手学习深度学习-深度学习知识大纲
  • 云迁移技术深度解析:核心原理与最佳实践
  • Python删除字符串的3种高效方法
  • Spring Boot + MinIO + KKFile:三步搭建企业级文件预览系统
  • Mysql索引失效问题及其原因
  • 【Leetcode】2683. 相邻值的按位异或
  • 五、cv::SparseMat的介绍和使用