ES6(十二)—— Reflect

Reflect

  • 反射,什麼是反射機制?
  • Reflect簡介
  • 爲何要用Reflect?
  • Reflect APIjava

    • .apply()
    • .construct()
    • .defineProperty()
    • .deleteProperty()
    • .get()
    • .getOwnPropertyDescriptor()
    • .getPrototypeOf()
    • .has()
    • .isExtensible() —— 是否可擴展
    • .ownKeys() —— 判斷對象自身屬性
    • .preventExtensions() —— 是否可擴展
    • .set() —— 寫數據
    • .setPrototypeOf()
  • ES6-ES10學習版圖

反射,什麼是反射機制?

java的反射機制】是在編譯階段不知道是哪一個類被加載,而是在運行的時候才加載、執行。
js中的apply就是反射機制。數組

Reflect簡介

Reflect 是一個內置的對象,它提供攔截 JavaScript 操做的方法,這些方法與處理器對象的方法相同。Reflect不是一個函數對象,所以它是不可構造的。app

與大多數全局對象不一樣,Reflect沒有構造函數。你不能將其與一個new運算符一塊兒使用,或者將Reflect對象做爲一個函數來調用。Reflect的全部屬性和方法都是靜態的( 就像Math對象函數

爲何要用Reflect?

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

Reflect API

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() 阻止新屬性添加到對象

.apply()

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

.construct()

使用反射的方式去實現建立類的實例,相似於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())

.defineProperty()

靜態方法 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上面移除這些方法。

.deleteProperty()

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

.get()

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

.getOwnPropertyDescriptor()

靜態方法 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 }

.getPrototypeOf()

靜態方法 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: ƒ, …}

.has()

判斷一個對象是否存在某個屬性,和 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

.isExtensible() —— 是否可擴展

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}

.ownKeys() —— 判斷對象自身屬性

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"]

.preventExtensions() —— 是否可擴展

等同於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}

.set() —— 寫數據

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"]

.setPrototypeOf()

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: ƒ, …}

ES6-ES10學習版圖

相關文章
相關標籤/搜索