JS笔记《Reflect》

134 阅读3分钟

概述

  • Reflect翻译过来是反射的意思,与Proxy一样,都是为了操作对象而提供的。设计目的有以下几点:
    • Object对象的一些属于语言内部的方法放到Reflect对象上。未来对象的新方法只部署到Reflect对象上。
    • 修改某些Object方法的返回结果,让其变得更合理。比如Object.defindProperty在无法定义属性时会抛出错误,而Reflect则会返回false
    • Object操作都变成函数行为。比如name in objdelete obj.name是命令式的。而Reflect让它们都变成了函数行为。
    • Reflect对象的方法和Proxy的方法一一对应,无论Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
let loggedObj = new Proxy(obj, {
  get(target, name) {
    return Reflect.get(target, name);
  },
  deleteProperty(target, name) {
    return Reflect.deleteProperty(target, name);
  },
  has(target, name) {
    return Reflect.has(target, name);
  }
});

静态方法

get(target, name, receiver);

  • 查找并返回target对象的name属性,如果没有该属性,则返回undefined
let obj = {
  foo: 1,
  bar: 2,
  get baz(){
    return this.foo + this.bar;
  }
}

console.log(Reflect.get(obj, 'foo'));  // 1
console.log(Reflect.get(obj, 'baz'));  // 3
  • 如果name属性设置了getter,则读取函数的this指向receiver
let obj = {
  get baz(){
    // this 指向了 receiver
    return this.foo + this.bar;
  }
}

let receiver = {
  foo: 10,
  bar: 20
}

Reflect.get(obj, 'baz', receiver);

set(target, name, value, receiver);

  • 设置target对象的name属性等于value。如果name属性设置了setter,则赋值函数内的this指向receiver
let obj = {
  foo: 1,
  bar: 2,
  set baz(value) {
    // this指向为receiver
    this.foo = value;
  }
}
let receiver = { foo: 10 }

Reflect.set(obj, 'bar', 2);
console.log(obj.bar) // 2

Reflect.set(obj, 'foo', 3, receiver);
console.log(obj.foo) // 1
console.log(receiver.foo) // 3  receiver中的被修改了
  • 如果 Proxy对象和 Reflect对象联合使用,前者拦截赋值操作,后者完成赋值的默认行为,而且传入了receiver,那么Reflect.set会触发Proxy.defineProperty拦截。
let p = {
  a: 'a'
};

let handler = {
  set(target, key, value, receiver) {
    console.log('set');
    Reflect.set(target, key, value, receiver);
    // Proxy.set中的receiver指向proxy实例本身,
    // 如果Reflect.set中也传入receiver,receiver会指向proxy,
    // 相当于给proxy实例赋值,就会触发defineProperty
  },
  defineProperty(target, key, attribute) {
    console.log('defineProperty');
    Reflect.defineProperty(target, key, attribute);
  }
};

let obj = new Proxy(p, handler);
obj.a = 'A';
// set
// defineProperty

has(obj, name)

  • 对应in运算符。
var myObject = {
  foo: 1
};

// 新写法
Reflect.has(myObject, 'foo') // true

deleteProperty(obj, name)

  • 等同于delete obj[name],用于删除对象的属性。返回一个布尔值,如果删除成功或被删除的属性不存在,返回true,删除失败返回false
const myObj = { foo: 'bar' };

// 新写法
Reflect.deleteProperty(myObj, 'foo');

construct(target, args)

  • 等同于new target(...args),这提供了一种不使用new来调用构造函数的方法。
function Greeting(name) {
  this.name = name;
}

const instance = Reflect.construct(Greeting, ['张三']);
console.log(instance)  // Greeting {name: '张三'}

getPrototypeOf(obj)

  • 用于读取对象的原型对象,对应Object.getPrototypeOf(obj)
let obj = {a: 1};
let obj2 = Object.create(obj);
Reflect.getPrototypeOf(obj2);  // {a: 1}

setPrototypeOf(obj, newProto)

  • 用于设置目标对象的原型,对应Object.setPrototypeOf()。返回一个布尔值,表示是否设置成功。
const myObj = {};

Reflect.setPrototypeOf(myObj, Array.prototype);
myObj.length // 0  可以调用数组的属性方法

apply(func, thisArgs, args)

  • 等同于Function.prototype.apply.call(func, thisArg, args),用于绑定this对象后执行给定函数。
function sum() {
  return this.num1 + this.num2;
}

let num = {
  num1: 10,
  num2: 20
}

Reflect.apply(sum, num, [])  // 30

defineProperty(target, key, desccriptor)

  • 等同于Object.defineProperty,用来为对象定义属性。
function MyDate() {}

Reflect.defineProperty(MyDate, 'now', {
  value: () => Date.now()
});

console.log(MyDate.now())  // 1709382033991

getOwnPropertyDescriptor(target, key)

  • 等同于Object.getOwnPropertyDescriptor,用于得到指定属性的描述对象。
var myObject = {};

Object.defineProperty(myObject, 'hidden', {
  value: true,
  enumerable: false,
});

Reflect.getOwnPropertyDescriptor(myObject, 'hidden'); 
// {value: true, writable: false, enumerable: false, configurable: false}

isExtensible(target)

  • 对应Object.isExtensible,返回一个布尔值,表示当前对象是否可扩展。
const myObject = {};

Reflect.isExtensible(myObject) // true

preventExtensions(target)

  • 对应Object.preventExtensions方法,用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。
var myObject = {};

Reflect.preventExtensions(myObject) // true

ownKeys(target)

  • 用于返回对象的所有属性,等同于Object.getOwnPropertyNamesObject.getOwnPropertySymbols之和。
var myObject = {
  foo: 1,
  bar: 2,
  [Symbol.for('baz')]: 3,
  [Symbol.for('bing')]: 4,
};

Object.getOwnPropertyNames(myObject) // ['foo', 'bar']
Object.getOwnPropertySymbols(myObject)  //[Symbol(baz), Symbol(bing)]

Reflect.ownKeys(myObject)  // ['foo', 'bar', Symbol(baz), Symbol(bing)]