您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

ES6+ Reflect(一)

任何一门语言在走向成熟的过程都是趋向精细化和规范化,在 API 设计之初满足当时的需求场景。随着前端的飞速发展,软件复杂度的提升,很多 API 在使用过程中存在很多使用别扭的情况,不符合软件开发的规范。上一节我们学习了 Proxy,Proxy 的设计目的是为了取代 Object.defineProperty,优化,使得数据劫持的过程更加规范。

本节我们将学习 ES6 新的全局对象 —— Reflect(反射),首先我们要了解一下,为什么会新这么全局对象?Reflect 上的一些基本上都可以在 Object 上找到,找不到的,也是可以通过对对象命令式的操作去实现的;那么为什么还要新呢?本节我们将学习 Reflect 的相关知识。

Reflect 是内置的对象,它提供了 JavaScript 操作的。这些与 Proxy 中的 handlers 相同。与大多数全局对象不同 Reflect 并非构造,所以不能通过 new 运算符对其进行,或者将 Reflect 对象作为来。Reflect 的所有和都是静态的(类似 JSON 或者 Math 等对象)。

Reflect 可以检查对象上是否存在特定,可以使用 Reflect.has() 检测。

let key = Symbol.for('a');
const obj = {
  name: 'imooc',
  lession: 'ES6 Wiki',
  [key]: 
}

console.log(Reflect.has(obj, 'name'));	// true
console.log(Reflect.has(obj, 'age'));		// false

可以使用 Reflect.get() 对象上的值。

console.log(Reflect.get(obj, 'name'));	// imooc

可以使用 Reflect.set() 为对象新的。

const res = Reflect.set(obj, 'age', );
console.log(res);		// true
console.log(obj);		// {name: "imooc", lession: "ES6 Wiki", age: 7}

使用 Reflect.ownKeys() 对象上的自有。

console.log(Object.keys(obj));	// ["name", "lession"]

console.log(Reflect.ownKeys(obj));	// ["name", "lession", Symbol(a)]

上面的可以看出,使用 Object.keys() 不到是 Symbol 的值。

Reflect 对象上的并不是专门为对象设计的,而是在语言层面的,它可以拿到语言内部的,和 Proxy 的结合可以实现元编程。并且每个操作都是有返回值的,上节我们使用 Proxy 简单地实现了 Vue3 的响应式。但是在 Vue3 源码中和设置对象上的使用的是 Reflect,Reflect 会返回状态表示和设置的成功与否。

// const res = target[key]; // 上节
const res = Reflect.get(target, key);	// target上key的值

// target[key] = value;	// 上节
const result = Reflect.set(target, key, value);	// 设置目标对象key的值

上面的两段是 Vue3 中的源码,因为在源码中需要知道或赋值的结果,因为可能失败。在 ES5 中如果想要监听劫持操作的结果需要使用 try...catch 的方式。

try {
  Object.defineProperty(obj, prop, descriptor);
  // success
} catch (e) {
  // failure
}

Reflect 在操作对象时是有返回结果的,而 Object.defineProperty 是没有返回结果的,如果失败则会抛出异常,所以需要使用 try...catch 来捕获异常。

Object 中操作数据时,有一些是命令式的操作,如:delete obj.aname in obj ,Reflect 则将一些命令式的操作如 deletein 等使用来替代,这样做的目的是为了让更加好维护,更容易向下兼容;也避免出现更多的保留字。

// ES5
'assign' in Object // true
// ES6
Reflect.has(Object, 'assign') // true

delete obj.name;	// ES5
Reflect.deleteProperty(obj, 'name');	// ES6

Reflect 的出现是为了取代 Object 中一些属于语言层面的 API,这些 API 在 Object 上也是可以找到的,并且它们的基本是相同的。上面我们也提到了 Reflect 和 Proxy 中 handlers 的是一一对应的,在很多场景中它门都是配套使用的。这里我们就来学习一下 Reflect 提供的静态:

Reflect.get() 是从对象中读取的值,类似 ES5 中访问器语法: obj[key] ,但是它是通过来获得返回结果的。

语法:

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

如果目标值 target 类型不是 Object,则抛出 TypeError

// Object
var obj = { a: , b:  };
Reflect.get(obj, "a"); // 1

// Array
Reflect.get(["a", "b", "c"], ); // "one"

第三个参数 receiver 是 this 所在的上下文,不传时指的是当前对象,如果传如人对象则 this 指向该对象。下面我们来看个实例:

let obj = {
  name: 'imooc',
  lesson: 'ES5 Wiki',
  get info() {
    console.log(`这是 ${this.lesson}`);
    return 
  }
};
Reflect.get(obj, 'info');	// 这是 ES5 Wiki
Reflect.get(obj, 'info', {lesson: 'ES6 Wiki'});	// 这是 ES5 Wiki

Reflect.set() 是在对象上设置,类似 ES5 中设置语法:obj[key] = value ,它也是通过的方式来对对象设置的。

语法:

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

这个会返回 Boolean 值,表示在目标对象上设置是否成功。

// Object
var obj = {};
Reflect.set(obj, "name", "imooc"); // true
console.log(obj.name); // "imooc"

// Array
var arr = ["a", "b", "c"];
Reflect.set(arr, , "C"); // true
console.log(arr); // ["a", "b", "C"]

使用可以截断数组:

var arr = ["a", "b", "c"];
Reflect.set(arr, "length", ); // true
console.log(arr);	// ["a", "b"]

当有 receiver 参数时,如果 receiver 对象中有 propertyKey ,则会使用 receiver 对象中的值。

Reflect.set(obj, 'lession', 'ES5 Wiki', {lession: 'ES6 Wiki', age: });
console.log(obj);	// {name: "imooc", lesson: "ES5 Wiki"}

Reflect.delete 允许对象的。它类似 ES5 中的 delete 操作符,但它也是,通过来实现。

语法:

Reflect.deleteProperty(target, propertyKey)

这个的返回值是 Boolean 值,如果成功的话,返回 true;失败的话返回 false。我们来看下面的实例:

var obj = {
    name: 'imooc',
    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

上面的例子中使用 Object.freeze() 来冻结 obj 对象使之不能被。

Reflect.has() 可以检查对象上是否含有特定的,这个相当于 ES5 的 in 操作符。

语法:

Reflect.has(target, propertyKey)

这个的返回结果是 Boolean 值,如果存在就返回 true,不存在就返回 false。当然如果目标对象 (target) 不是对象,那么就会抛出异常。

Reflect.has({x: }, "x"); // true
Reflect.has({x: }, "y"); // false

// 如果该存在于原型链中,也返回true 
Reflect.has({x: }, "toString");	// true

这也可检查构造的。

function A(name) {
    this.name = name || 'imooc';
}
// 在原型上
A.prototype.getName = function() {
    return this.name;
};

var a = new A();

console.log('name' in a); // true
console.log('getName' in a); // true

let r1 = Reflect.has(a, 'name');
let r2 = Reflect.has(a, 'getName');
console.log(r1, r2); // true true

Reflect.ownKeys() 返回由目标对象自身的键组成的数组。

语法:

Reflect.ownKeys(target)

如果这个目标对象不是对象那么这个就会抛出异常。这个数组的值等于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)) 我们来看下面的实例:

let a = Symbol.for('a');
let b = Symbol.for('b');

let obj = {
    [a]: ,
    [b]: ,
    key1: ,
    key2: 
};

let arr1 = Object.getOwnPropertyNames(obj);
console.log(arr1); // [ 'key1', 'key2' ]
let arr2 = Object.getOwnPropertySymbols(obj);
console.log(arr2); // [ Symbol(a), Symbol(b) ]
let arr3 = Reflect.ownKeys(obj);
console.log(arr3); // [ 'key1', 'key2', Symbol(a), Symbol(b) ]

本节主要学习了 ES6 新增的全局对象 Reflect ,它的目的是为了分离 Object 中属于语言部分的,每个使用 Reflect 下的操作的对象都要返回值。 Reflect 对象和 Proxy 下的是一一对应的,二者配合可以实现很多。Vue3 中的数据响应就是使用的它们。


联系我
置顶