第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

ES6-10 入門教程

ES6+ Reflect(一)

1. 前言

任何一門語言在走向成熟的過程都是趨向精細(xì)化和規(guī)范化,在 API 設(shè)計(jì)之初滿足當(dāng)時(shí)的需求場景。隨著前端的飛速發(fā)展,軟件復(fù)雜度的提升,很多 API 在使用過程中存在很多使用別扭的情況,不符合軟件開發(fā)的規(guī)范。上一節(jié)我們學(xué)習(xí)了 Proxy,Proxy 的設(shè)計(jì)目的是為了取代 Object.defineProperty,優(yōu)化性能,使得數(shù)據(jù)劫持的過程更加規(guī)范。

本節(jié)我們將學(xué)習(xí) ES6 新的全局對象 —— Reflect(反射),首先我們要了解一下,為什么會(huì)新添加這么一個(gè)全局對象?Reflect 上的一些函數(shù)基本上都可以在 Object 上找到,找不到的,也是可以通過對對象命令式的操作去實(shí)現(xiàn)的;那么為什么還要新添加一個(gè)呢?本節(jié)我們將學(xué)習(xí) Reflect 的相關(guān)知識。

2. 基礎(chǔ)知識

Reflect 是一個(gè)內(nèi)置的對象,它提供了攔截 JavaScript 操作的方法。這些方法與 Proxy 中的 handlers 方法相同。與大多數(shù)全局對象不同 Reflect 并非一個(gè)構(gòu)造函數(shù),所以不能通過 new 運(yùn)算符對其進(jìn)行調(diào)用,或者將 Reflect 對象作為一個(gè)函數(shù)來調(diào)用。Reflect 的所有屬性和方法都是靜態(tài)的(類似 JSON 或者 Math 等對象)。

2.1 基本用法

Reflect 可以檢查對象上是否存在特定屬性,可以使用 Reflect.has() 方法檢測。

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

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() 方法為對象添加一個(gè)新的屬性。

const res = Reflect.set(obj, 'age', 7);
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 的值。

2.2 返回值

Reflect 對象上的方法并不是專門為對象設(shè)計(jì)的,而是在語言層面的,它可以拿到語言內(nèi)部的方法,和 Proxy 的結(jié)合可以實(shí)現(xiàn)元編程。并且每個(gè)操作都是有返回值的,上節(jié)我們使用 Proxy 簡單地實(shí)現(xiàn)了 Vue3 的響應(yīng)式。但是在 Vue3 源碼中獲取和設(shè)置對象上的屬性使用的是 Reflect,Reflect 會(huì)返回一個(gè)狀態(tài)表示獲取和設(shè)置的成功與否。

// const res = target[key]; // 上節(jié)代碼
const res = Reflect.get(target, key);	// 獲取target上屬性key的值

// target[key] = value;	// 上節(jié)代碼
const result = Reflect.set(target, key, value);	// 設(shè)置目標(biāo)對象key屬性的值

上面的兩段代碼是 Vue3 中的源碼,因?yàn)樵谠创a中需要知道獲取或賦值的結(jié)果,因?yàn)榭赡塬@取失敗。在 ES5 中如果想要監(jiān)聽劫持屬性操作的結(jié)果需要使用 try...catch 的方式。

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

Reflect 在操作對象時(shí)是有返回結(jié)果的,而 Object.defineProperty 是沒有返回結(jié)果的,如果失敗則會(huì)拋出異常,所以需要使用 try...catch 來捕獲異常。

2.3 使用函數(shù)代替命令式

Object 中操作數(shù)據(jù)時(shí),有一些是命令式的操作,如:delete obj.a 、name in obj ,Reflect 則將一些命令式的操作如 delete,in 等使用函數(shù)來替代,這樣做的目的是為了讓代碼更加好維護(hù),更容易向下兼容;也避免出現(xiàn)更多的保留字。

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

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

3. 靜態(tài)方法

Reflect 的出現(xiàn)是為了取代 Object 中一些屬于語言層面的 API,這些 API 在 Object 上也是可以找到的,并且它們的功能基本是相同的。上面我們也提到了 Reflect 和 Proxy 中 handlers 的方法是一一對應(yīng)的,在很多場景中它門都是配套使用的。這里我們就來學(xué)習(xí)一下 Reflect 提供的靜態(tài)方法:

3.1 Reflect.get()

Reflect.get() 方法是從對象中讀取屬性的值,類似 ES5 中屬性訪問器語法: obj[key] ,但是它是通過調(diào)用函數(shù)來獲得返回結(jié)果的。

語法:

Reflect.get(target, propertyKey[, receiver])
  • target:需要取值的目標(biāo)對象;
  • propertyKey:需要獲取的值的鍵值;
  • receiver:如果 target 對象中指定了 getter,receiver 則為 getter 調(diào)用時(shí)的 this 值。

如果目標(biāo)值 target 類型不是 Object,則拋出一個(gè) TypeError。

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

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

第三個(gè)參數(shù) receiver 是 this 所在的上下文,不傳時(shí)指的是當(dāng)前對象,如果傳如一個(gè)人對象則 this 指向該對象。下面我們來看個(gè)實(shí)例:

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

3.2 Reflect.set()

Reflect.set() 是在一個(gè)對象上設(shè)置一個(gè)屬性,類似 ES5 中屬性設(shè)置語法:obj[key] = value ,它也是通過調(diào)用函數(shù)的方式來對對象設(shè)置屬性的。

語法:

Reflect.set(target, propertyKey, value[, receiver])
  • target:表示要操作的目標(biāo)對象;
  • propertyKey:表示要設(shè)置的屬性名;
  • value:表示設(shè)置的屬性值;
  • receiver:表示的是一個(gè) this 值,如果我們在設(shè)置值的時(shí)候遇到 setter 函數(shù),那么這個(gè) receiver 值表示的就是 setter 函數(shù)中的 this 值。

這個(gè)函數(shù)會(huì)返回一個(gè) Boolean 值,表示在目標(biāo)對象上設(shè)置屬性是否成功。

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

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

使用可以截?cái)鄶?shù)組:

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

當(dāng)有 receiver 參數(shù)時(shí),如果 receiver 對象中有 propertyKey 屬性,則會(huì)使用 receiver 對象中的值。

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

3.3 Reflect.deleteProperty()

Reflect.deleteProperty() 方法允許刪除對象的屬性。它類似 ES5 中的 delete 操作符,但它也是一個(gè)函數(shù),通過調(diào)用函數(shù)來實(shí)現(xiàn)。

語法:

Reflect.deleteProperty(target, propertyKey)
  • target:表示要操作的目標(biāo)對象;
  • propertyKey:表示要?jiǎng)h除的屬性。

這個(gè)函數(shù)的返回值是一個(gè) Boolean 值,如果成功的話,返回 true;失敗的話返回 false。我們來看下面的實(shí)例:

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() 方法來凍結(jié) obj 對象使之不能被修改。

3.4 Reflect.has()

Reflect.has() 方法可以檢查一個(gè)對象上是否含有特定的屬性,這個(gè)方法相當(dāng)于 ES5 的 in 操作符。

語法:

Reflect.has(target, propertyKey)
  • target:表示要操作的目標(biāo)對象;
  • propertyKey: 屬性名,表示需要檢查目標(biāo)對象是否存在此屬性。

這個(gè)函數(shù)的返回結(jié)果是一個(gè) Boolean 值,如果存在就返回 true,不存在就返回 false。當(dāng)然如果目標(biāo)對象 (target) 不是一個(gè)對象,那么就會(huì)拋出一個(gè)異常。

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

// 如果該屬性存在于原型鏈中,也返回true 
Reflect.has({x: 0}, "toString");	// true

這方法也可檢查構(gòu)造函數(shù)的屬性。

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

3.5 Reflect.ownKeys()

Reflect.ownKeys() 返回一個(gè)由目標(biāo)對象自身的屬性鍵組成的數(shù)組。

語法:

Reflect.ownKeys(target)
  • target:表示目標(biāo)對象

如果這個(gè)目標(biāo)對象不是一個(gè)對象那么這個(gè)函數(shù)就會(huì)拋出一個(gè)異常。這個(gè)數(shù)組的值等于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)) 我們來看下面的實(shí)例:

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

let obj = {
    [a]: 10,
    [b]: 20,
    key1: 30,
    key2: 40
};

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

4. 小結(jié)

本節(jié)主要學(xué)習(xí)了 ES6 新增的全局對象 Reflect ,它的目的是為了分離 Object 中屬于語言部分的內(nèi)容,每個(gè)使用 Reflect 下的方法操作的對象都要返回值。 Reflect 對象和 Proxy 下的方法是一一對應(yīng)的,二者配合可以實(shí)現(xiàn)很多功能。Vue3 中的數(shù)據(jù)響應(yīng)就是使用的它們。