深入理解 ES6中的 Reflect用法

Reflect对象是一个全局的普通的对象。Reflect的原型就是Object.

我们首先来验证下 看看Reflect的原型是否是Object, 基本代码如下:

let obj = {};
console.log(Reflect.__proto__ === Object.prototype); // true
console.log(obj.__proto__ === Reflect.__proto__); // true

let str = '111';

console.log(str.__proto__); // String {"", length: 0, constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}

Reflect是ES6为了操作对象而新增的API, 为什么要添加Reflect对象呢?它这样设计的目的是为了什么?

1)将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上,那么以后我们就可以从Reflect对象上可以拿到语言内部的方法。

2)在使用对象的 Object.defineProperty(obj, name, {})时,如果出现异常的话,会抛出一个错误,需要使用try catch去捕获,但是使用 Reflect.defineProperty(obj, name, desc) 则会返回false。

比如 旧的写法如下:

try {
 Object.defineProperty(target, property, attributes);
} catch(e) {
 // 失败
}

// 新写法
if (Reflect.defineProperty(target, property, attributes)) {
 // success
} else {
 // failure
}

等等这些考虑,所以就新增了这个静态对象。

Reflect对象一共有13个静态方法。

一:Reflect.get(target, name, receiver)

该方法是用来读取一个对象的属性。

参数如下解析:

target: 目标对象

name: 是我们要读取的属性。

receiver(可选): 可以理解为上下文this对象。

先看如下demo来理解下 Reflect中的get方法的使用如下:

const obj = {
 name: 'kongzhi',
 age: 30,
 get xxx() {
 console.log(this.name);
 console.log('-------');
 }
};

console.log(Reflect.get(obj, 'name')); // kongzhi
console.log(Reflect.get(obj, 'yyy')); // undefined

/*
 先执行 xxx 方法 打印 kongzhi 和 ----,
 然后在打印undefined, 因为该xxx()函数没有返回值
*/
console.log(Reflect.get(obj, 'xxx')); 

/*
 会执行 xxx() 方法,打印 happy, 因此第三个参数指向上下文
 就指向了这个对象,然后打印 ----- ,最后打印undefined
 因为该函数没有返回值
*/
console.log(Reflect.get(obj, 'xxx', {name: 'happy'})); 

/*
 会执行 xxx() 方法,打印 undefined, 因此第三个参数指向上下文
 就指向了这个对象,而这个对象里面又没有name属性,因此会打印undefined
 然后打印 ----- ,最后打印undefined. 因为该函数没有返回值
*/
console.log(Reflect.get(obj, 'xxx', {age: 'happy'}));

const obj2 = {
 name: 'kongzhi2',
 age: 30,
 get xxx() {
 console.log(this.name);
 console.log('----xxxx---');
 return 0;
 }
};
/*
 先执行 obj2 该对象中的 xxx 方法,指定了第三个参数作为该上下文对象,
 因此会打印 happy2, 然后继续打印 ----xxxx---, 最后我们可以看到
 有返回值为0,因此打印0了
*/
console.log(Reflect.get(obj2, 'xxx', {name: 'happy2'}));

二:Reflect.set(target,name,value,receiver)

上面的get方法是获取对象中的值,那么set就是设置该对象的属性值了,参数解析简单如下:

target: 我们需要操作的对象。

name: 我们需要设置该对象的属性名。

value: 我们要设置的属性值。

receiver: 可以理解为上下文this对象。如果我们在设置值的时候遇到setter函数,该参数就指向与setter中上下文this对象。

该函数会返回一个Boolean的值,代表在目标对象上设置属性是否成功。

如下代码演示:

const obj = {
 age: 30,
 set name(name) {
 console.log(this);
 console.log('-------');
 }
};

const res = Reflect.set(obj, 'age', 31);
console.log(res); // true
console.log(obj); // {age: 31, set name:function} 这样的
console.log(obj.age); // 打印 31

/*
 如下代码,设置 obj对象中的name属性,因此打印 console.log(this)
 返回 {age: 31, set name:function} 这样的, console.log(res2)返回true,设置成功
*/
const res2 = Reflect.set(obj, 'name', 'xxxx');
console.log(res2); // true

/*
 先执行 set 中的name方法,打印 console.log(this);this就指向了第四个参数 {test: 'test'}
 然后会打印 '-----';
*/
const r2 = Reflect.set(obj, 'name', 'dreamapple', {test: 'test'}); // this: --> { test: 'test' }
console.log(r2); // true
console.log(obj); // { name: [Setter], age: 31 }

三:Reflect.apply(target,thisArg,args)

该方法的含义是:通过指定的参数列表对该目标函数的调用。该方法类似于我们之前的 Function.prototype.apply 方法的。

参数解析如下:

target: 我们的目标函数.

thisArg: target函数调用的时候绑定的this对象。

args: 就是函数参数列表。

如下代码demo演示:

// 查找数组里面最小的元素值

const arrs = [1, 2, 3, 4];
// ES6 的语法如下
const min = Reflect.apply(Math.min, arrs, arrs);

console.log(min); // 1

// ES5的语法如下:

const min2 = Math.min.apply(arrs, arrs);
console.log(min2); // 1

// 或者我们使用 Finction.prototype 代码如下演示

const min3 = Function.prototype.apply.call(Math.min, arrs, arrs);
console.log(min3); // 1

// 下面是截取字符串的方法演示下 

const strs = 'kongzhi';

// 使用ES6的语法 代码演示如下:

const str1 = Reflect.apply(String.prototype.slice, strs, [0, 3]);
console.log(str1); // 打印 kon

// 使用 ES5的语法
const str2 = strs.slice(0, 3);
console.log(str2); // 打印 kon

// 或者我们使用 String.prototype 代码如下演示
const str3 = String.prototype.slice.apply(strs, [0, 3]);
console.log(str3); // kon

四:Reflect.construct(target,args[, newTarget])

该方法的作用和 new AAA() 创建一个实列方法作用类似,那么使用该方法,我们就可以提供一种不使用new来调用构造函数的方法,

参数含义如下:

target: 被运行的目标函数。

args: 调用构造函数传递的参数数组或伪数组。

newTarget: 也是构造函数,表示使用 Reflect.construct后生成的实列对象是谁的实列。如果没有该参数,默认生成的实列对象就和target构造函数是一样的。

代码演示如下:

function XXXX(name) {
 this.name = name;
}

XXXX.prototype.getName = function() {
 return this.name;
}

function YYYY(age) {
 this.age = age;
}

YYYY.prototype.getAge = function() {
 return this.age || 31;
}

// 使用 XXXX函数作为构造函数, 那么构造函数就指向了 XXXX函数
const xxxx = Reflect.construct(XXXX, ['xx']);
console.log(xxxx); // 打印 XXXX {name: xx}
console.log(xxxx.getName()); // 打印 xx

如下图所示:

// 使用 YYYY 函数作为构造函数,那么构造函数就指向了 YYYY函数
const yyyy = Reflect.construct(XXXX, ['30'], YYYY);

console.log(yyyy); // 打印 YYYY {name: 30}
console.log(yyyy.name); // 30
console.log(yyyy.age); // undefined
console.log(yyyy instanceof YYYY); // true
console.log(yyyy instanceof XXXX); // false
console.log(yyyy.getAge()); // 31

如上demo所示:当const xxxx = Reflect.construct(XXXX, ['xx']); 没有第三个参数的时候,那么构造函数指向了 XXXX 函数。

我们继续看第二个demo,const yyyy = Reflect.construct(XXXX, ['30'], YYYY); 有第三个参数,因此 yyyy的实列指向了 YYYY.

如上代码打印的信息看到 console.log(yyyy instanceof YYYY); 返回true, console.log(yyyy instanceof XXXX); 返回false.

但是呢 console.log(yyyy.getAge()); 返回的是 31. 如果我们没有默认的 31值的话,那么就应该返回undefined了,可以看到,请看下面的注意总结:

注意:如果有第三个参数的话,那么我们的实列由两部分组成,实列的属性部分由第一部分构造函数生成。实列的方法由第三个参数对象生成。

比如上面打印的 console.log(yyyy); // 打印 YYYY {name: 30} 看到只返回了 XXXX中的name属性,XXXX中的getName方法并没有拿到。

同理如上 console.log(yyyy.age); 为undefined, console.log(yyyy.getAge()); 返回了31. 如下图所示:

五:Reflect.defineProperty(target,name,desc)

该方法与Object.defineProperty方法类似的,不过唯一的区别是 Reflect.defineProperty返回值是一个Boolean的值。

比如如下基本的代码比较:

const obj = {};
// 使用 Object.defineProperty
try {
 Object.defineProperty(obj, 'a', {
 value: 22
 })
} catch(e) {
 console.log('define property failed');
}

// 使用 Reflect.defineProperty

const res = Reflect.defineProperty(obj, 'b', {
 configurable: true,
 enumerable: true
});

console.log(res); // true

既然两者的用法是一样的,那配置项也是一样的,那这边就不多介绍了,只是返回值不一样而已,那么Object.defineProperty 的具体用法,

请看我上一篇文章(https://www.jb51.net/article/191097.htm)。

因此总结一下:如果使用Object.defineProperty的属性定义失败了,就会抛出一个错误,成功的话就会返回这个对象;

Reflect.defineProperty如果定义属性失败的话就会返回false,如果成功定义的话,就会返回true。

但是如果使用Reflect.defineProperty函数,它的第一个参数不是对象的话,也会抛出错误。

六:Reflect.deleteProperty(target,name)

该方法用于删除一个对象上的属性,它和delete操作符类似的。

参数如下:

target: 表示要操作的对象。

name: 表示要删除该对象上的属性。

该函数返回值是一个Boolean的值,如果成功的话,返回true,失败的话返回false。比如如下demo演示:

const obj = {
 name: 'kongzhi',
 age: 30
};

let test1 = Reflect.deleteProperty(obj, 'name');
console.log(test1); // true
console.log(obj); // {age: 30}

// 如果删除对象上不存在的属性的话,也是返回true的
let test2 = Reflect.deleteProperty(obj, 'xx');
console.log(test2); // true
console.log(obj); // {age: 30}

let test3 = Reflect.deleteProperty(obj, 'age');
console.log(test3); // true
console.log(obj); // {}

七:Reflect.has(target,name)

该方法的含义是:检查一个对象上是否含有特定的属性。相当于es5中的in操作符。

那么参数 target: 就是改对象哦,name的含义是:该对象上的属性。

具体的demo演示如下:

// 一般的对象
const obj = {
 name: 'kongzhi',
 age: 30
};

console.log(Reflect.has(obj, 'name')); // true
console.log(Reflect.has(obj, 'username')); // 该对象上没有 username属性 返回false
console.log(Reflect.has(obj, 'age')); // true

// 函数的实列

function Obj(name) {
 this.name = name;
}
Obj.prototype.getName = function() {
 return this.name;
}
const test = new Obj();

// 使用in操作符测试
console.log('name' in test); // true
console.log('getName' in test); // true

// 使用Reflect.has 测试
console.log(Reflect.has(test, 'name')); // true
console.log(Reflect.has(test, 'getName')); // true

八:Reflect.ownKeys(target)

该函数的作用是:返回由目标对象自身的属性键组成的数组。如果这个目标对象不是一个对象的话,那么该函数就会抛出一个异常。 target参数:它是一个对象。如下代码演示:

const obj = {
 name: 'kongzhi',
 age: 30
};
console.log(Reflect.ownKeys(obj)); // ['name', 'age'];

九:Reflect.preventExtensions(target)

该方法的作用是 阻止新的属性添加到对象中去。target参数必须是一个对象,否则的话会抛出一个异常。

如下代码演示:

const obj = {};
// 判断该对象是否可以扩展,使用 Reflect.isExtensible 该方法
const t1 = Reflect.isExtensible(obj);
console.log(t1); // true

// 使用 Reflect.preventExtensions 来阻止该对象扩展

Reflect.preventExtensions(obj);

// 再来扩展下该对象,看是否可以
const t2 = Reflect.isExtensible(obj);
console.log(t2); // false

十:Reflect.isExtensible(target)

该方法的作用是检查一个对象是否可以扩展的,也就是说对象里面是否可以添加新的属性或方法。

target参数表示目标对象。如果该目标对象不是一个对象的话,那么函数会抛出一个异常。

该函数会返回一个Boolean值,如果为true的话,说明该对象可以扩展,否则的话返回false,表示该对象不可以扩展。

如下demo来演示下:

const obj = {};
// 判断该对象是否可以扩展,使用 Reflect.isExtensible 该方法
const t1 = Reflect.isExtensible(obj);
console.log(t1); // true

// 使用 Reflect.preventExtensions 来阻止该对象扩展
Reflect.preventExtensions(obj);

// 再来扩展下该对象,看是否可以
const t2 = Reflect.isExtensible(obj);
console.log(t2); // false

十一:Reflect.getOwnPropertyDescriptor(target, name)

该方法的参数如下解析:

target: 表示的是目标对象。

name: 表示目标对象的属性

该方法的具体含义是:如果目标对象中的属性描述符存在的话,就返回这个属性描述符,如果不存在,就返回undefined。

如下demo演示:

const obj = {};

Reflect.defineProperty(obj, 'name', {
 configurable: true,
 enumerable: true,
 writable: true,
 value: '30'
});

const test1 = Reflect.getOwnPropertyDescriptor(obj, 'name');
/*
 打印值如下:
 {
 configurable: true
 enumerable: true
 value: "30"
 writable: true
 }
*/
console.log(test1);

const test2 = Reflect.getOwnPropertyDescriptor(obj, 'age');
console.log(test2); // undefined

// 如果第一个参数不是对象
const test3 = Object.getOwnPropertyDescriptor('kkkk', 'name');
console.log(test3); // undefined

// 使用 try catch 包围,会执行 catch方法内部代码
try {
 const test4 = Reflect.getOwnPropertyDescriptor('kkkk', 'name');
 console.log(test4);
} catch (e) {
 console.log('error');
}

十二:Reflect.getPrototypeOf(target)

该方法是返回一个对象的原型的,也就是说内部的 [[Prototype]] 属性的值。来看如下代码:

function testA() {};
testA.prototype.xxx = function() {};
const a = new testA();
console.log(Object.getPrototypeOf(a));

打印 如下图所示:

十三:Reflect.setPrototypeOf(target, prototype)

该方法的作用是设置一个对象的原型。如果设置成功的话,这个对象就返回一个true,如果设置失败的话,这个对象就返回一个false。

比如如下代码:

const obj = {};
const test1 = Reflect.setPrototypeOf(obj, Object.prototype);
console.log(test1); // true

let test2 = Reflect.setPrototypeOf(Object.freeze({}), null);
console.log(test2); // false

以上这篇深入理解 ES6中的 Reflect用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • ES6中字符串的使用方法扩展

    字符的Unicode表示法 JavaScript允许采用\uxxxx形式表示一个字符,其中"xxxx"表示字符的码点. "\u0061" // "a" 但是,这种表示法只限于\u0000--\uFFFF之间的字符.超出这个范围的字符,必须用两个双字节的形式表达. "\uD842\uDFB7" // "

  • ES6 javascript中class静态方法、属性与实例属性用法示例

    本文实例讲述了ES6 javascript中class静态方法.属性与实例属性用法.分享给大家供大家参考,具体如下: 类相当于实例的原型, 所有在类中定义的方法, 都会被实例继承. 如果在一个方法前, 加上static关键字, 就表示该方法不会被实例继承, 而是直接通过类来调用, 这就称为" 静态方法". class Foo { static classMethod() { return 'hello'; } } Foo.classMethod() // 'hello' var foo

  • es6中reduce的基本使用方法

    前言 为啥要把es6 中 reduce 单独拿出来说呢,因为这个功能实在太骚,值得如此. reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值.reduce() 方法接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce() 的数组. reduce() 的几个强大用法: 数组求和 var total = [ 0, 1, 2, 3 ].reduce(( acc, cur ) => { return acc + cu

  • 深入理解 ES6中的 Reflect用法

    Reflect对象是一个全局的普通的对象.Reflect的原型就是Object. 我们首先来验证下 看看Reflect的原型是否是Object, 基本代码如下: let obj = {}; console.log(Reflect.__proto__ === Object.prototype); // true console.log(obj.__proto__ === Reflect.__proto__); // true let str = '111'; console.log(str.__p

  • ES6中class类用法实例浅析

    本文实例讲述了ES6中class类用法.分享给大家供大家参考,具体如下: 类语法是ES6中新增的一个亮点特色.我们熟悉的JavaScript终于迎来了真正意义上的类.在之前,想要通过javascript来实现类,通常会采用如下构造函数的模式: function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends = ['Shelby','Court']; } Person.pro

  • 深入理解js中this的用法

    this是js的一个关键字,随着函数使用场合不同,this的值会发生变化.但是总有一个原则,那就是this指的是调用函数的那个对象. 1.纯粹函数调用. function test() { this.x = 1; alert(x); } test(); 其实这里的this就是全局变量.看下面的例子就能很好的理解其实this就是全局对象Global.其实这里的this就是全局变量.看下面的例子就能很好的理解其实this就是全局对象Global. var x = 1; function test()

  • ES6中Proxy代理用法实例浅析

    本文实例讲述了ES6中Proxy代理用法.分享给大家供大家参考,具体如下: ES6中提出了一个新的特性,就是proxy,用来拦截在一个对象上的指定操作.这个功能非常的有用.举一个例子来说: var engineer = { name: 'Joe Sixpack', salary: 50 }; var interceptor = { set: function (receiver, property, value) { console.log(property, 'is changed to',

  • 深入理解ES6中let和闭包

    本文介绍了深入理解ES6中let和闭包,分享给大家,具体如下: 在开始本文之前我们先来看一段代码 for(var i=0;i<10;i++){ arr[i]=function(){ return i; } } console.log(arr[3]());//10 显然这段代码输出10,并没有向我们期望的返回3,原因也很简单(js的变量提升)函数在调用时候访问的是一个全局作用域的i,此时for循环已经执行完毕,全局变量i=10: 在ES5标准中,我们要想返回期望的3,通常的做法也很简单,就是让数组

  • 原生JavaScript之es6中Class的用法分析

    本文实例讲述了原生JavaScript之es6中Class的用法.分享给大家供大家参考,具体如下: es6class写法 class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } es5写法 function Point(x, y) { this.x = x; this.y = y; } Point.prototyp

  • ES6中Symbol类型用法实例详解

    本文实例讲述了ES6中的Symbol类型.分享给大家供大家参考,具体如下: Symbol是在ES6中新加入的类型. 正如我们所知,JavaScript中有以下几种类型: Undefined ,Null ,Boolean ,Number ,String, Object. 但是上述类型在处理某些情况的时候是远远不够的.下面我们来举一个例子: 假设我们要移动div,也需要在某些情况下判断该div是否处于移动状态,所以我们会想到给div这类的对象设置一个属性. if (element.isMoving)

  • 全面理解Python中self的用法

    刚开始学习Python的类写法的时候觉得很是麻烦,为什么定义时需要而调用时又不需要,为什么不能内部简化从而减少我们敲击键盘的次数?你看完这篇文章后就会明白所有的疑问. self代表类的实例,而非类. 实例来说明: class Test: def prt(self): print(self) print(self.__class__) t = Test() t.prt() 执行结果如下 <__main__.Test object at 0x000000000284E080> <class

  • 深入理解jquery中的each用法

    1种 通过each遍历li 可以获得所有li的内容 <!-- 1种 --> <ul class="one"> <li>11a</li> <li>22b</li> <li>33c</li> <li>44d</li> <li>55e</li> </ul> <button>输出每个li值</button> <

  • javascript ES6中set集合、map集合使用方法详解与源码实例

    set与map理解 ES6中新增,set集合和map集合就是一种数据的存储结构(在ES6之前数据存储结构只有array,object),不同的场景使用不同的集合去存储数据 set集合 Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用. set集合语法: //创建一个set集合,传参为一个可迭代的对象 const s1 = new Set(iterable); API 名称 类型 简介 Set.add() 原型方法 添加数据 Set.has() 原型方法 判断是否存在一个数据 S

随机推荐