Reflect 认识
Reflect 是 ES6 引入的一个内置对象,它提供了一套与 JavaScript 内置操作直接对应的、用于对象操作的静态方法,这些方法的设计目的是为了使操作对象的行为变得更为清晰、更易于使用,并且在某些情况下提供更好的错误处理机制;
Reflect 对象的方法与 Object 对象上的同名方法 (如 get、set、defineProperty 等) 相对应,但它们通常返回一个布尔值以表示操作是否成功,而不是静默失败;
Reflect 特点
函数式设计
:
- Reflect 对象的方法全部是函数,而不是在对象上作为属性直接调用;
- 这种设计使得 Reflect 方法更易于组合、更易于使用函数式编程风格;
与内建操作对应
:
- Reflect 提供的方法与 JavaScript 内置的许多操作 (如属性访问、定义、删除等) 相对应,形成了一个统一、明确的 API 集合;
- 这使得开发者可以通过 Reflect 对象直接调用这些底层操作,而不是依赖语言的隐式行为或使用 Object 类型上的某些方法;
返回值一致性
:
- Reflect 方法通常返回一个布尔值来表示操作的成功与否,或者返回与操作相关的具体结果;
- 这与一些 Object 类型上的方法可能返回 undefined 或静默失败不同,提高了代码的可预测性和调试性;
错误处理
:
- Reflect 方法在遇到非法操作时会抛出适当的异常,如 TypeError 或 RangeError,而不是默默地失败;
- 这种严格的错误处理有助于在开发阶段尽早发现潜在问题;
元编程支持
:
- Reflect 提供了一系列方法用于进行对象的元编程操作,如获取和设置属性描述符、操作对象的原型链、检查对象的扩展性等;
- 这些方法为实现更高级的编程模式和库提供了底层支持;
Reflect 常用方法
Reflect.get()
Reflect.get() 方法是从对象中读取属性的值,类似 ES5 中属性访问器语法:obj[key],但是它是通过调用函数来获得返回结果的;
/**
* 语法
* target:需要取值的目标对象,如果目标值 target 类型不是 Object,则抛出一个 TypeError
* propertyKey:需要获取的值的键值
* receiver:如果 target 对象中指定了 getter, 则 getter 调用时 this 指向 receiver
*/
Reflect.get(target, propertyKey[, receiver]);
/**
* receiver 是 this 所在的上下文,不传时指的是当前对象,如果传入一个对象则 this 指向该对象;
*/
let obj = {
name: 'es',
lesson: 'ES5 Wiki',
get info() {
console.log(`这是 ricepudding ${this.lesson}`);
return 0;
}
};
Reflect.get(obj, 'info'); // 这是 ricepudding ES5 Wiki
Reflect.get(obj, 'info', { lesson: 'ES6 Wiki' }); // 这是 ricepudding ES6 Wiki
Reflect.set()
Reflect.set() 是在一个对象上设置一个属性,类似 ES5 中属性设置语法:obj[key] = value,它也是通过调用函数的方式来对对象设置属性的,返回值是一个布尔值;
/**
* 语法:
* target:表示要操作的目标对象
* propertyKey:表示要设置的属性名
* value:表示设置的属性值
* receiver:如果 target 对象中指定了 setter, 则 setter 调用时 this 指向 receiver
*/
Reflect.set(target, propertyKey, value[, receiver]);
/**
* 如果 target 对象中指定了 setter, 则 setter 调用时 this 指向 receiver
*/
var obj = {
name: 'zhangsan',
set lession(arg) { // arg:ES5 Wiki
console.log(this); // this 指向 myReceiverObject
this.lession = arg;
}
};
var myReceiverObject = { lession: 'ES6 Wiki', age: 18 };
if (Reflect.set(obj, 'lession', 'ES5 Wiki', myReceiverObject)) {
console.log(myReceiverObject); // { lession: 'ES5 Wiki', age: 18 }
}
Reflect.defineProperty()
Reflect.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性;
- Reflect.defineProperty() 返回的是 Boolean 值,Object.defineProperty() 返回的是个对象;
- Reflect.defineProperty() 可以根据返回值检查属性是否被成功定义,而 Object.defineProperty() 只能通过 try…catch 去捕获其中的错误,相比之下 Reflect.defineProperty() 方法更加方便;
/**
* 语法:
* target:目标对象,如果 target 不是 Object,抛出一个 TypeError
* propertyKey:需要定义或修改的属性的名称
* attributes:需要定义或修改的属性的描述
*/
Reflect.defineProperty(target, propertyKey, attributes);
var obj = {};
if (Reflect.defineProperty(obj, 'a', { value: 10 })) {
console.log(obj.a); // 10
// 成功 todo
} else {
// 失败 todo
}
try {
let obj = {};
Object.defineProperty(obj, 'a', { value: 10 });
} catch (e) {
// 如果失败,捕获的异常
}
Reflect.deleteProperty()
Reflect.deleteProperty() 方法允许删除对象的属性,它类似 ES5 中的 delete 操作符,但它也是一个函数,通过调用函数来实现,返回值是一个 Boolean 值;
/**
* 语法
* target:表示要操作的目标对象
* propertyKey:表示要删除的属性
*/
Reflect.deleteProperty(target, propertyKey);
var obj = {
name: 'ricepudding',
lession: 'ES6 Wiki'
};
var r1 = Reflect.deleteProperty(obj, 'name');
console.log(r1); // true
console.log(obj); // {lession: "ES6 Wiki"}
var r2 = Reflect.deleteProperty(Object.freeze(obj), 'lession');
console.log(r2); // false
console.log(obj); // {lession: "ES6 Wiki"}
Reflect.apply()
Reflect.apply() 通过指定的参数列表发起对目标 (target) 函数的调用;
/**
* 语法:
* target:目标函数
* thisArgument:target 函数调用时绑定的 this 对象
* argumentsList:target 函数调用时传入的实参列表,该参数应该是一个类数组的对象
*/
Reflect.apply(target, thisArgument, argumentsList);
const arr = [1, 6, 7, 10, 2, 5];
console.log(Math.max(...arr));
console.log(Function.prototype.apply.call(Math.max, null, arr)); // 10
console.log(Reflect.apply(Math.max, null, arr)); // 10
Reflect.construct()
Reflect.construct() 和 new 操作符构造函数相似,相当于运行 new target(…args),提供了一种新的不使用 new 来调用构造函数的方法;
/**
* 语法:
* target:被运行的目标构造函数
* argumentsList:类数组,目标构造函数调用时的参数
* newTarget:(可选)表示使用 Reflect.construct 后生成的实列对象是谁的实列,如果没有该参数,默认生成的实列对象就和 target 构造函数是一样的
*/
Reflect.construct(target, argumentsList[, newTarget]);
class A {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class B {
constructor(age) {
this.age = age || 18;
}
getAge() {
return this.age;
}
}
let a = Reflect.construct(A, ['David']);
let b = Reflect.construct(A, ['David'], B);
console.log(a instanceof A); // true
console.log(b instanceof B); // true
Reflect.has()
Reflect.has() 方法可以检查一个对象及原型链上是否含有特定的属性,这个方法相当于 ES5 的 in 操作符,返回值是一个 Boolean 值;
/**
* 语法:
* target:表示要操作的目标对象,如果不是一个对象,会抛出一个异常
* propertyKey: 属性名,表示需要检查目标对象是否存在此属性
*/
Reflect.has(target, propertyKey);
Reflect.has({ x: 0 }, "x"); // true
Reflect.has({ x: 0 }, "toString"); // true
Reflect.has({ x: 0 }, "y"); // false
class A {
constructor(name) {
this.name = name;
}
getName() {
}
}
var a = new A();
console.log(Reflect.has(a, 'name')); // true
console.log(Reflect.has(a, 'getName')); // true
Reflect.ownKeys()
Reflect.ownKeys() 返回一个由目标对象自身的属性键组成的数组;
/**
* 语法:
* target:表示目标对象,如果不是对象会抛出一个异常
*/
Reflect.ownKeys(target);
let a = Symbol.for('a');
let b = Symbol.for('b');
let obj = {
[a]: 10,
[b]: 20,
key1: 30,
key2: 40
};
console.log(Object.getOwnPropertyNames(obj)); // [ 'key1', 'key2' ]
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(a), Symbol(b) ]
console.log(Reflect.ownKeys(obj)); // [ 'key1', 'key2', Symbol(a), Symbol(b) ]
Reflect.preventExtensions()
阻止目标对象 target 扩展 (不能再添加新属性),返回一个布尔值;
const obj = { a: 1 };
console.log(Reflect.preventExtensions(obj)); // 输出:true
console.log(Reflect.isExtensible(obj)); // 输出:false
obj.b = 2; // 尝试添加新属性
console.log(obj.b); // 输出:undefined,因为对象已不可扩展
Reflect.isExtensible()
判断目标对象 target 是否可扩展 (即是否可以添加新属性),返回一个布尔值;
constobj = { a: 1 };
console.log(Reflect.isExtensible(obj)); // true
Object.preventExtensions(obj); // 阻止对一个对象进一步添加新的属性(不可扩展)
console.log(Reflect.isExtensible(obj)); // false
Reflect.getPrototypeOf()
返回目标对象 target 的原型 (即[[Prototype]]),相当于 Object.getPrototypeOf();
class MyClass{ }
const instance = new MyClass();
console.log(Reflect.getPrototypeOf(instance) === MyClass.prototype); // 输出:true
计算机网络🛜 session
上一篇