最近中文字幕高清中文字幕无,亚洲欧美高清一区二区三区,一本色道无码道dvd在线观看 ,一个人看的www免费高清中文字幕

全部開發(fā)者教程

ES6-10 入門教程

ES6+ Reflect(一)

1. 前言

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

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

2. 基礎(chǔ)知識(shí)

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

2.1 基本用法

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

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() 方法獲取對(duì)象上的屬性值。

console.log(Reflect.get(obj, 'name'));	// imooc

可以使用 Reflect.set() 方法為對(duì)象添加一個(gè)新的屬性。

const res = Reflect.set(obj, 'age', 7);
console.log(res);		// true
console.log(obj);		// {name: "imooc", lession: "ES6 Wiki", age: 7}

使用 Reflect.ownKeys() 方法獲取對(duì)象上的自有屬性。

console.log(Object.keys(obj));	// ["name", "lession"]

console.log(Reflect.ownKeys(obj));	// ["name", "lession", Symbol(a)]

上面的代碼可以看出,使用 Object.keys() 獲取不到屬性是 Symbol 的值。

2.2 返回值

Reflect 對(duì)象上的方法并不是專門為對(duì)象設(shè)計(jì)的,而是在語言層面的,它可以拿到語言內(nèi)部的方法,和 Proxy 的結(jié)合可以實(shí)現(xiàn)元編程。并且每個(gè)操作都是有返回值的,上節(jié)我們使用 Proxy 簡(jiǎn)單地實(shí)現(xiàn)了 Vue3 的響應(yīng)式。但是在 Vue3 源碼中獲取和設(shè)置對(duì)象上的屬性使用的是 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)對(duì)象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 在操作對(duì)象時(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 的方法是一一對(duì)應(yīng)的,在很多場(chǎng)景中它門都是配套使用的。這里我們就來學(xué)習(xí)一下 Reflect 提供的靜態(tài)方法:

3.1 Reflect.get()

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

語法:

Reflect.get(target, propertyKey[, receiver])
  • target:需要取值的目標(biāo)對(duì)象;
  • propertyKey:需要獲取的值的鍵值;
  • receiver:如果 target 對(duì)象中指定了 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)前對(duì)象,如果傳如一個(gè)人對(duì)象則 this 指向該對(duì)象。下面我們來看個(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è)對(duì)象上設(shè)置一個(gè)屬性,類似 ES5 中屬性設(shè)置語法:obj[key] = value ,它也是通過調(diào)用函數(shù)的方式來對(duì)對(duì)象設(shè)置屬性的。

語法:

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

這個(gè)函數(shù)會(huì)返回一個(gè) Boolean 值,表示在目標(biāo)對(duì)象上設(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 對(duì)象中有 propertyKey 屬性,則會(huì)使用 receiver 對(duì)象中的值。

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() 方法允許刪除對(duì)象的屬性。它類似 ES5 中的 delete 操作符,但它也是一個(gè)函數(shù),通過調(diào)用函數(shù)來實(shí)現(xiàn)。

語法:

Reflect.deleteProperty(target, propertyKey)
  • target:表示要操作的目標(biāo)對(duì)象;
  • 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 對(duì)象使之不能被修改。

3.4 Reflect.has()

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

語法:

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

這個(gè)函數(shù)的返回結(jié)果是一個(gè) Boolean 值,如果存在就返回 true,不存在就返回 false。當(dāng)然如果目標(biāo)對(duì)象 (target) 不是一個(gè)對(duì)象,那么就會(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)對(duì)象自身的屬性鍵組成的數(shù)組。

語法:

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

如果這個(gè)目標(biāo)對(duì)象不是一個(gè)對(duì)象那么這個(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 新增的全局對(duì)象 Reflect ,它的目的是為了分離 Object 中屬于語言部分的內(nèi)容,每個(gè)使用 Reflect 下的方法操作的對(duì)象都要返回值。 Reflect 對(duì)象和 Proxy 下的方法是一一對(duì)應(yīng)的,二者配合可以實(shí)現(xiàn)很多功能。Vue3 中的數(shù)據(jù)響應(yīng)就是使用的它們。