深入理解 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
}
等等這些考慮,所以就新增了這個靜態(tài)對象。
Reflect對象一共有13個靜態(tài)方法。
一: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
/*
先執(zhí)行 xxx 方法 打印 kongzhi 和 ----,
然后在打印undefined, 因為該xxx()函數沒有返回值
*/
console.log(Reflect.get(obj, 'xxx'));
/*
會執(zhí)行 xxx() 方法,打印 happy, 因此第三個參數指向上下文
就指向了這個對象,然后打印 ----- ,最后打印undefined
因為該函數沒有返回值
*/
console.log(Reflect.get(obj, 'xxx', {name: 'happy'}));
/*
會執(zhí)行 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;
}
};
/*
先執(zhí)行 obj2 該對象中的 xxx 方法,指定了第三個參數作為該上下文對象,
因此會打印 happy2, 然后繼續(xù)打印 ----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
/*
先執(zhí)行 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() 創(chuàng)建一個實列方法作用類似,那么使用該方法,我們就可以提供一種不使用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 函數。
我們繼續(xù)看第二個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方法類似的,不過唯一的區(qū)別是 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 的具體用法,
請看我上一篇文章(http://www.dbjr.com.cn/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 包圍,會執(zhí)行 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用法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
JavaScript中for-in和for-of的不同之處及如何正確使用
這篇文章主要給大家介紹了關于JavaScript中for-in和for-of的不同之處及如何正確使用它們的相關資料,無論是for...in還是for...of語句都是迭代一些東西,它們之間的主要區(qū)別在于它們的迭代方式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-05-05

