Reflect APIjava
【java
的反射機制】是在編譯階段不知道是哪一個類被加載,而是在運行的時候才加載、執行。js
中的apply
就是反射機制。數組
Reflect
是一個內置的對象,它提供攔截 JavaScript
操做的方法,這些方法與處理器對象的方法相同。Reflect
不是一個函數對象,所以它是不可構造的。app
與大多數全局對象不一樣,Reflect
沒有構造函數。你不能將其與一個new
運算符一塊兒使用,或者將Reflect
對象做爲一個函數來調用。Reflect
的全部屬性和方法都是靜態的( 就像Math對象 )函數
Reflect
內部封裝了一系列對對象的底層操做,Reflect
成員方法就是Proxy
處理對象的默認實現學習
const proxy = new Proxy(obj, { get(target, property) { // 若是沒有定義get方法,那麼默認返回的就是Reflect的get方法 return Reflect.get(target, property) } })
爲何要用Reflect
? <br/>由於Reflect
提供了一套用於操做對象的API
,咱們以前操做對象能夠用Object
上面的一些方法,也能夠用in、delete
這種操做符,使用Reflect
就統一了操做方式。this
handler ⽅法 | 默認調⽤ | 功能 |
---|---|---|
get | Reflect.get() | 獲取對象身上某個屬性的值 |
set | Reflect.set() | 在對象上設置屬性 |
has | Reflect.has() | 判斷一個對象是否存在某個屬性 |
deleteProperty | Reflect.deleteProperty() | 刪除對象上的屬性 |
getProperty | Reflect.getPrototypeOf() | 獲取指定對象原型的函數 |
setProperty | Reflect.setPrototypeOf() | 設置或改變對象原型的函數 |
isExtensible | Reflect.isExtensible() | 判斷一個對象是否可擴展 (便是否可以添加新的屬性) |
preventExtensions | Reflect.preventExtensions() | 阻止新屬性添加到對象 |
getOwnPropertyDescriptor | Reflect.getOwnPropertyDescriptor() | 獲取給定屬性的屬性描述符 |
defineProperty | Reflect.defineProperty() | 定義或修改一個對象的屬性 |
ownKeys | Reflect.ownKeys() | 返回由目標對象自身的屬性鍵組成的數組 |
apply | Reflect.apply() | 對一個函數進行調用操做,同時能夠傳入一個數組做爲調用參數 |
construct | Reflect.construct() | 對構造函數進行 new 操做,實現建立類的實例 |
.preventExtensions | Reflect.preventExtensions() | 阻止新屬性添加到對象 |
Reflect.apply(target, thisArgument, argumentsList)target:目標函數,必傳<br/>
thisArgument:target函數調用時綁定的this對象,沒必要須<br/>
argumentsList:target函數調用時傳入的實參列表,該參數應該是一個類數組的對象,沒必要須spa
//ES5 console.log(Math.floor.apply(null,[1.72])) // 1 // 必須先指定方法,再去調用apply。
//Reflect是一個對象,可是不能使用new // 先傳遞apply,再指定是哪一個方法 // 靜態掃描的時候,Math.floor是沒有被執行的,運行的時候,是動態的將Math.floor做爲參數傳進來的。 Reflect.apply(Math.floor,null,[4.72]) // 4
實際應用prototype
// ES5 let price = 101.5 if (price > 100) { price = Math.floor.apply(null, [price]) } else { price = Math.ceil.apply(null, [price]) } console.log(price) // 101 //ES6 let price = 101.5 console.log(Reflect.apply(price > 100 ? Math.floor : Math.ceil, null, [price])) // 101
使用反射的方式去實現建立類的實例,相似於new target(…args)
.code
Reflect.construct(target, argumentsList[, newTarget])target:被運行的目標函數,必選<br/>
argumentsList 調用構造函數的數組或者僞數組,沒必要選<br/>
newTarget 該參數爲構造函數, 參考 new.target 操做符,若是沒有newTarget參數, 默認和target同樣,沒必要選對象
let d = new Date() console.log(d.getTime())
let d1 = Reflect.construct(Date, []) console.log(d1.getTime())
靜態方法 Reflect.defineProperty()
基本等同於 Object.defineProperty()
方法
Reflect.defineProperty(target, propertyKey, attributes)target:目標對象,必填<br/>
propertyKey:要定義或修改的屬性的名稱,沒必要填<br/>
attributes:要定義或修改的屬性的描述,沒必要填
const student = {} const r = Object.defineProperty(student, 'name', { value:'Mike' }) console.log(student, r) // {name: "Mike"} {name: "Mike"}
const student = {} const r = Reflect.defineProperty(student, 'name', { value:'Mike' }) console.log(student, r) // {name: "Mike"} true
這兩個方法效果上來看是一摸同樣的,均可以改變一個對象的值,他們的區別在於返回值不一樣。Object
是返回這個值,Reflect
是返回true
PS: 在W3C
中,之後全部的Object
上面的方法,都會慢慢遷移到Reflect
對象,可能之後會在Object
上面移除這些方法。
Reflect.deleteProperty
容許你刪除一個對象上的屬性。返回一個 Boolean
值表示該屬性是否被成功刪除。它幾乎與非嚴格的 delete operator
相同。
Reflect.deleteProperty(target, propertyKey)target:刪除屬性的目標對象<br/>
propertyKey:將被刪除的屬性的名稱
const obj = { x: 1, y: 2 } delete obj.x console.log(obj) // {y: 2}
const obj = { x: 1, y: 2 } const d = Reflect.deleteProperty(obj, 'x') console.log(obj, d) // {y: 2} true
Reflect.get()
方法的工做方式,就像從 object (target[propertyKey])
中獲取屬性,但它是做爲一個函數執行的。
Reflect.get(target, propertyKey[, receiver])
const obj = { x: 1, y: 2 } console.log(obj.x) // 1 console.log(obj['x']) // 1
const obj = { x: 1, y: 2 } console.log(Reflect.get(obj, 'x')) // 1 console.log(Reflect.get([3, 4], 1)) // 4
靜態方法 Reflect.getOwnPropertyDescriptor()
與 Object.getOwnPropertyDescriptor()
方法類似。若是在對象中存在,則返回給定的屬性的屬性描述符,不然返回 undefined
。
Reflect.getOwnPropertyDescriptor(target, propertyKey)
const obj = { x: 1, y: 2 } console.log(Object.getOwnPropertyDescriptor(obj, 'x')) // {value: 1, writable: true, enumerable: true, configurable: true} console.log(Reflect.getOwnPropertyDescriptor(obj, 'x')) // {value: 1, writable: true, enumerable: true, configurable: true} console.log(Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'y')) // undefined console.log(Reflect.getOwnPropertyDescriptor([], 'length')) // {value: 0, writable: true, enumerable: false, configurable: false}
對比
若是該方法的第一個參數不是一個對象(一個原始值),那麼將形成 TypeError
錯誤。而對於Object.getOwnPropertyDescriptor
,非對象的第一個參數將被強制轉換爲一個對象處理。
Reflect.getOwnPropertyDescriptor("foo", 0); // TypeError: "foo" is not non-null object Object.getOwnPropertyDescriptor("foo", 0); // { value: "f", writable: false, enumerable: true, configurable: false }
靜態方法 Reflect.getPrototypeOf()
與 Object.getPrototypeOf()
方法是同樣的。都是返回指定對象的原型(即,內部的 [[Prototype]]
屬性的值)。
Reflect.getPrototypeOf(target)
const d = New Date() console.log(Reflect.getPrototypeOf(d)) // {constructor: ƒ, toString: ƒ, toDateString: ƒ, toTimeString: ƒ, toISOString: ƒ, …} console.log(Object.getPrototypeOf(d)) // {constructor: ƒ, toString: ƒ, toDateString: ƒ, toTimeString: ƒ, toISOString: ƒ, …}
判斷一個對象是否存在某個屬性,和 in
運算符 的功能徹底相同。
Reflect.has(target, propertyKey)
const obj = { x: 1, y: 2 } console.log(Reflect.has(obj, 'x')) // true console.log(Reflect.has(obj, 'z')) // false
Reflect.isExtensible
判斷一個對象是否可擴展 (便是否可以添加新的屬性),它與 Object.isExtensible()
方法同樣。
Reflect.isExtensible(target)
const obj = { x: 1, y: 2 } console.log(Reflect.isExtensible(obj)) // true Object.freeze(obj) obj.z = 3 console.log(Reflect.isExtensible(obj)) // false console.log(obj) // {x: 1, y: 2}
Reflect.ownKeys
方法返回一個由目標對象自身的屬性鍵組成的數組。它的返回值等同於 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
Reflect.ownKeys(target)
const obj = { x: 1, y: 2 } console.log(Reflect.ownKeys(obj)) // ["x", "y"] console.log(Reflect.ownKeys([])) // ["length"] console.log(Reflect.ownKeys([1,2])) // ["0", "1", "length"]
等同於Object.freeze()
Reflect.preventExtensions
方法阻止新屬性添加到對象 例如:防止未來對對象的擴展被添加到對象中)。該方法與 Object.preventExtensions()
方法一致
Reflect.preventExtensions(target)
const obj = { x: 1, y: 2 } console.log(Reflect.isExtensible(obj)) // true Reflect.preventExtensions(obj) obj.z = 3 console.log(Reflect.isExtensible(obj)) // false console.log(obj) // {x: 1, y: 2}
Reflect.set
方法容許你在對象上設置屬性。它的做用是給屬性賦值而且就像 property accessor
語法同樣,可是它是以函數的方式。
Reflect.set(target, propertyKey, value[, receiver])
const obj = { x: 1, y: 2 } Reflect.set(obj, 'z', 4) console.log(obj) // {x: 1, y: 2, z: 4} const arr = ['apple', 'pear'] Reflect.set(arr, 1, 'banana') console.log(arr) // ["apple", "banana"]
Reflect.setPrototypeOf
方法改變指定對象的原型 (即,內部的 [[Prototype]]
屬性值)
Reflect.setPrototypeOf(target, prototype)
const arr = ['apple', 'pear'] console.log(Reflect.getPrototypeOf(arr)) // [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ,…] Reflect.setPrototypeOf(arr, String.prototype) console.log(Reflect.getPrototypeOf(arr)) // String {"", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}