伊人久久大香线蕉综合影视_日韩精品少妇无码受不了_71pao成人国产永久免费视频_国产伦片中文免费观看_国产高清无码麻豆精品_九色综合伊人久久富二代_日韩黄色精品_日韩A∨精品日韩精品无码

細(xì)數(shù) TS 中那些奇怪的符號(hào)

2020-9-4    seo達(dá)人

TypeScript 是一種由微軟開發(fā)的自由和開源的編程語(yǔ)言。它是 JavaScript 的一個(gè)超集,而且本質(zhì)上向這個(gè)語(yǔ)言添加了可選的靜態(tài)類型和基于類的面向?qū)ο缶幊獭?


本文阿寶哥將分享這些年在學(xué)習(xí) TypeScript 過程中,遇到的 10 大 “奇怪” 的符號(hào)。其中有一些符號(hào),阿寶哥第一次見的時(shí)候也覺得 “一臉懵逼”,希望本文對(duì)學(xué)習(xí) TypeScript 的小伙伴能有一些幫助。


好的,下面我們來開始介紹第一個(gè)符號(hào) —— ! 非空斷言操作符。


一、! 非空斷言操作符

在上下文中當(dāng)類型檢查器無法斷定類型時(shí),一個(gè)新的后綴表達(dá)式操作符 ! 可以用于斷言操作對(duì)象是非 null 和非 undefined 類型。具體而言,x! 將從 x 值域中排除 null 和 undefined 。


那么非空斷言操作符到底有什么用呢?下面我們先來看一下非空斷言操作符的一些使用場(chǎng)景。


1.1 忽略 undefined 和 null 類型

function myFunc(maybeString: string | undefined | null) { // Type 'string | null | undefined' is not assignable to type 'string'. // Type 'undefined' is not assignable to type 'string'.  const onlyString: string = maybeString; // Error const ignoreUndefinedAndNull: string = maybeString!; // Ok }

1.2 調(diào)用函數(shù)時(shí)忽略 undefined 類型

type NumGenerator = () => number; function myFunc(numGenerator: NumGenerator | undefined) { // Object is possibly 'undefined'.(2532) // Cannot invoke an object which is possibly 'undefined'.(2722) const num1 = numGenerator(); // Error const num2 = numGenerator!(); //OK }

因?yàn)?! 非空斷言操作符會(huì)從編譯生成的 JavaScript 代碼中移除,所以在實(shí)際使用的過程中,要特別注意。比如下面這個(gè)例子:


const a: number | undefined = undefined; const b: number = a!; console.log(b);

以上 TS 代碼會(huì)編譯生成以下 ES5 代碼:


"use strict"; const a = undefined; const b = a; console.log(b);

雖然在 TS 代碼中,我們使用了非空斷言,使得 const b: number = a!; 語(yǔ)句可以通過 TypeScript 類型檢查器的檢查。但在生成的 ES5 代碼中,! 非空斷言操作符被移除了,所以在瀏覽器中執(zhí)行以上代碼,在控制臺(tái)會(huì)輸出 undefined。


二、?. 運(yùn)算符

TypeScript 3.7 實(shí)現(xiàn)了呼聲最高的 ECMAScript 功能之一:可選鏈(Optional Chaining)。有了可選鏈后,我們編寫代碼時(shí)如果遇到 null 或 undefined 就可以立即停止某些表達(dá)式的運(yùn)行??蛇x鏈的核心是新的 ?. 運(yùn)算符,它支持以下語(yǔ)法:


obj?.prop

obj?.[expr]

arr?.[index] func?.(args)

這里我們來舉一個(gè)可選的屬性訪問的例子:


const val = a?.b;

為了更好的理解可選鏈,我們來看一下該 const val = a?.b 語(yǔ)句編譯生成的 ES5 代碼:


var val = a === null || a === void 0 ? void 0 : a.b;

上述的代碼會(huì)自動(dòng)檢查對(duì)象 a 是否為 null 或 undefined,如果是的話就立即返回 undefined,這樣就可以立即停止某些表達(dá)式的運(yùn)行。你可能已經(jīng)想到可以使用 ?. 來替代很多使用 && 執(zhí)行空檢查的代碼:


if(a && a.b) { } if(a?.b){ } /**

* if(a?.b){ } 編譯后的ES5代碼

*

* if(

*  a === null || a === void 0

*  ? void 0 : a.b) {

* }

*/

但需要注意的是,?. 與 && 運(yùn)算符行為略有不同,&& 專門用于檢測(cè) falsy 值,比如空字符串、0、NaN、null 和 false 等。而 ?. 只會(huì)驗(yàn)證對(duì)象是否為 null 或 undefined,對(duì)于 0 或空字符串來說,并不會(huì)出現(xiàn) “短路”。


2.1 可選元素訪問

可選鏈除了支持可選屬性的訪問之外,它還支持可選元素的訪問,它的行為類似于可選屬性的訪問,只是可選元素的訪問允許我們?cè)L問非標(biāo)識(shí)符的屬性,比如任意字符串、數(shù)字索引和 Symbol:


function tryGetArrayElement<T>(arr?: T[], index: number = 0) { return arr?.[index];

}

以上代碼經(jīng)過編譯后會(huì)生成以下 ES5 代碼:


"use strict"; function tryGetArrayElement(arr, index) { if (index === void 0) { index = 0; } return arr === null || arr === void 0 ? void 0 : arr[index];

}

通過觀察生成的 ES5 代碼,很明顯在 tryGetArrayElement 方法中會(huì)自動(dòng)檢測(cè)輸入?yún)?shù) arr 的值是否為 null 或 undefined,從而保證了我們代碼的健壯性。


2.2 可選鏈與函數(shù)調(diào)用

當(dāng)嘗試調(diào)用一個(gè)可能不存在的方法時(shí)也可以使用可選鏈。在實(shí)際開發(fā)過程中,這是很有用的。系統(tǒng)中某個(gè)方法不可用,有可能是由于版本不一致或者用戶設(shè)備兼容性問題導(dǎo)致的。函數(shù)調(diào)用時(shí)如果被調(diào)用的方法不存在,使用可選鏈可以使表達(dá)式自動(dòng)返回 undefined 而不是拋出一個(gè)異常。


可選調(diào)用使用起來也很簡(jiǎn)單,比如:


let result = obj.customMethod?.();

該 TypeScript 代碼編譯生成的 ES5 代碼如下:


var result = (_a = obj.customMethod) === null || _a === void 0 ? void 0 : _a.call(obj);

另外在使用可選調(diào)用的時(shí)候,我們要注意以下兩個(gè)注意事項(xiàng):


如果存在一個(gè)屬性名且該屬性名對(duì)應(yīng)的值不是函數(shù)類型,使用 ?. 仍然會(huì)產(chǎn)生一個(gè) TypeError 異常。

可選鏈的運(yùn)算行為被局限在屬性的訪問、調(diào)用以及元素的訪問 —— 它不會(huì)沿伸到后續(xù)的表達(dá)式中,也就是說可選調(diào)用不會(huì)阻止 a?.b / someMethod() 表達(dá)式中的除法運(yùn)算或 someMethod 的方法調(diào)用。

三、?? 空值合并運(yùn)算符

在 TypeScript 3.7 版本中除了引入了前面介紹的可選鏈 ?. 之外,也引入了一個(gè)新的邏輯運(yùn)算符 —— 空值合并運(yùn)算符 ??。當(dāng)左側(cè)操作數(shù)為 null 或 undefined 時(shí),其返回右側(cè)的操作數(shù),否則返回左側(cè)的操作數(shù)。


與邏輯或 || 運(yùn)算符不同,邏輯或會(huì)在左操作數(shù)為 falsy 值時(shí)返回右側(cè)操作數(shù)。也就是說,如果你使用 || 來為某些變量設(shè)置默認(rèn)的值時(shí),你可能會(huì)遇到意料之外的行為。比如為 falsy 值(''、NaN 或 0)時(shí)。


這里來看一個(gè)具體的例子:


const foo = null ?? 'default string'; console.log(foo); // 輸出:"default string" const baz = 0 ?? 42; console.log(baz); // 輸出:0

以上 TS 代碼經(jīng)過編譯后,會(huì)生成以下 ES5 代碼:


"use strict"; var _a, _b; var foo = (_a = null) !== null && _a !== void 0 ? _a : 'default string';

console.log(foo); // 輸出:"default string" var baz = (_b = 0) !== null && _b !== void 0 ? _b : 42;

console.log(baz); // 輸出:0

通過觀察以上代碼,我們更加直觀的了解到,空值合并運(yùn)算符是如何解決前面 || 運(yùn)算符存在的潛在問題。下面我們來介紹空值合并運(yùn)算符的特性和使用時(shí)的一些注意事項(xiàng)。


3.1 短路

當(dāng)空值合并運(yùn)算符的左表達(dá)式不為 null 或 undefined 時(shí),不會(huì)對(duì)右表達(dá)式進(jìn)行求值。


function A() { console.log('A was called'); return undefined;} function B() { console.log('B was called'); return false;} function C() { console.log('C was called'); return "foo";} console.log(A() ?? C()); console.log(B() ?? C());

上述代碼運(yùn)行后,控制臺(tái)會(huì)輸出以下結(jié)果:


A was called

C was called

foo

B was called

false

3.2 不能與 && 或 || 操作符共用

若空值合并運(yùn)算符 ?? 直接與 AND(&&)和 OR(||)操作符組合使用 ?? 是不行的。這種情況下會(huì)拋出 SyntaxError。


// '||' and '??' operations cannot be mixed without parentheses.(5076) null || undefined ?? "foo"; // raises a SyntaxError // '&&' and '??' operations cannot be mixed without parentheses.(5076) true && undefined ?? "foo"; // raises a SyntaxError

但當(dāng)使用括號(hào)來顯式表明優(yōu)先級(jí)時(shí)是可行的,比如:


(null || undefined ) ?? "foo"; // 返回 "foo"

3.3 與可選鏈操作符 ?. 的關(guān)系

空值合并運(yùn)算符針對(duì) undefined 與 null 這兩個(gè)值,可選鏈?zhǔn)讲僮鞣??. 也是如此??蛇x鏈?zhǔn)讲僮鞣瑢?duì)于訪問屬性可能為 undefined 與 null 的對(duì)象時(shí)非常有用。


interface Customer {

 name: string;

 city?: string;

} let customer: Customer = {

 name: "Semlinker" }; let customerCity = customer?.city ?? "Unknown city"; console.log(customerCity); // 輸出:Unknown city

前面我們已經(jīng)介紹了空值合并運(yùn)算符的應(yīng)用場(chǎng)景和使用時(shí)的一些注意事項(xiàng),該運(yùn)算符不僅可以在 TypeScript 3.7 以上版本中使用。當(dāng)然你也可以在 JavaScript 的環(huán)境中使用它,但你需要借助 Babel,在 Babel 7.8.0 版本也開始支持空值合并運(yùn)算符。


四、?: 可選屬性

在面向?qū)ο笳Z(yǔ)言中,接口是一個(gè)很重要的概念,它是對(duì)行為的抽象,而具體如何行動(dòng)需要由類去實(shí)現(xiàn)。 TypeScript 中的接口是一個(gè)非常靈活的概念,除了可用于對(duì)類的一部分行為進(jìn)行抽象以外,也常用于對(duì)「對(duì)象的形狀(Shape)」進(jìn)行描述。


在 TypeScript 中使用 interface 關(guān)鍵字就可以聲明一個(gè)接口:


interface Person {

 name: string;

 age: number;

} let semlinker: Person = {

 name: "semlinker",

 age: 33,

};

在以上代碼中,我們聲明了 Person 接口,它包含了兩個(gè)必填的屬性 name 和 age。在初始化 Person 類型變量時(shí),如果缺少某個(gè)屬性,TypeScript 編譯器就會(huì)提示相應(yīng)的錯(cuò)誤信息,比如:


// Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.(2741) let lolo: Person  = { // Error name: "lolo" }

為了解決上述的問題,我們可以把某個(gè)屬性聲明為可選的:


interface Person {

 name: string;

 age?: number;

} let lolo: Person  = {

 name: "lolo" }

4.1 工具類型

4.1.1 Partial<T>

在實(shí)際項(xiàng)目開發(fā)過程中,為了提高代碼復(fù)用率,我們可以利用 TypeScript 內(nèi)置的工具類型 Partial<T> 來快速把某個(gè)接口類型中定義的屬性變成可選的:


interface PullDownRefreshConfig {

 threshold: number;

 stop: number;

} /**

* type PullDownRefreshOptions = {

*   threshold?: number | undefined;

*   stop?: number | undefined;

* }

*/ type PullDownRefreshOptions = Partial<PullDownRefreshConfig>

是不是覺得 Partial<T> 很方便,下面讓我們來看一下它是如何實(shí)現(xiàn)的:


/**

* Make all properties in T optional

*/ type Partial<T> = {

 [P in keyof T]?: T[P];

};

4.1.2 Required<T>

既然可以快速地把某個(gè)接口中定義的屬性全部聲明為可選,那能不能把所有的可選的屬性變成必選的呢?答案是可以的,針對(duì)這個(gè)需求,我們可以使用 Required<T> 工具類型,具體的使用方式如下:


interface PullDownRefreshConfig {

 threshold: number;

 stop: number;

} type PullDownRefreshOptions = Partial<PullDownRefreshConfig> /**

* type PullDownRefresh = {

*   threshold: number;

*   stop: number;

* }

*/ type PullDownRefresh = Required<Partial<PullDownRefreshConfig>>

同樣,我們來看一下 Required<T> 工具類型是如何實(shí)現(xiàn)的:


/**

* Make all properties in T required

*/ type Required<T> = {

 [P in keyof T]-?: T[P];

};

原來在 Required<T> 工具類型內(nèi)部,通過 -? 移除了可選屬性中的 ?,使得屬性從可選變?yōu)楸剡x的。


五、& 運(yùn)算符

在 TypeScript 中交叉類型是將多個(gè)類型合并為一個(gè)類型。通過 & 運(yùn)算符可以將現(xiàn)有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性。


type PartialPointX = { x: number; }; type Point = PartialPointX & { y: number; }; let point: Point = {

 x: 1,

 y: 1 }

在上面代碼中我們先定義了 PartialPointX 類型,接著使用 & 運(yùn)算符創(chuàng)建一個(gè)新的 Point 類型,表示一個(gè)含有 x 和 y 坐標(biāo)的點(diǎn),然后定義了一個(gè) Point 類型的變量并初始化。


5.1 同名基礎(chǔ)類型屬性的合并

那么現(xiàn)在問題來了,假設(shè)在合并多個(gè)類型的過程中,剛好出現(xiàn)某些類型存在相同的成員,但對(duì)應(yīng)的類型又不一致,比如:


interface X {

 c: string;

 d: string;

} interface Y {

 c: number;

 e: string } type XY = X & Y; type YX = Y & X; let p: XY; let q: YX;

在上面的代碼中,接口 X 和接口 Y 都含有一個(gè)相同的成員 c,但它們的類型不一致。對(duì)于這種情況,此時(shí) XY 類型或 YX 類型中成員 c 的類型是不是可以是 string 或 number 類型呢?比如下面的例子:


p = { c: 6, d: "d", e: "e" };



q = { c: "c", d: "d", e: "e" };



為什么接口 X 和接口 Y 混入后,成員 c 的類型會(huì)變成 never 呢?這是因?yàn)榛烊牒蟪蓡T c 的類型為 string & number,即成員 c 的類型既可以是 string 類型又可以是 number 類型。很明顯這種類型是不存在的,所以混入后成員 c 的類型為 never。


5.2 同名非基礎(chǔ)類型屬性的合并

在上面示例中,剛好接口 X 和接口 Y 中內(nèi)部成員 c 的類型都是基本數(shù)據(jù)類型,那么如果是非基本數(shù)據(jù)類型的話,又會(huì)是什么情形。我們來看個(gè)具體的例子:


interface D { d: boolean; } interface E { e: string; } interface F { f: number; } interface A { x: D; } interface B { x: E; } interface C { x: F; } type ABC = A & B & C; let abc: ABC = {

 x: {

   d: true,

   e: 'semlinker',

   f: 666 }

}; console.log('abc:', abc);

以上代碼成功運(yùn)行后,控制臺(tái)會(huì)輸出以下結(jié)果:




由上圖可知,在混入多個(gè)類型時(shí),若存在相同的成員,且成員類型為非基本數(shù)據(jù)類型,那么是可以成功合并。


六、| 分隔符

在 TypeScript 中聯(lián)合類型(Union Types)表示取值可以為多種類型中的一種,聯(lián)合類型使用 | 分隔每個(gè)類型。聯(lián)合類型通常與 null 或 undefined 一起使用:


const sayHello = (name: string | undefined) => { /* ... */ };

以上示例中 name 的類型是 string | undefined 意味著可以將 string 或 undefined 的值傳遞給 sayHello 函數(shù)。


sayHello("semlinker");

sayHello(undefined);

此外,對(duì)于聯(lián)合類型來說,你可能會(huì)遇到以下的用法:


let num: 1 | 2 = 1; type EventNames = 'click' | 'scroll' | 'mousemove';

示例中的 1、2 或 'click' 被稱為字面量類型,用來約束取值只能是某幾個(gè)值中的一個(gè)。


6.1 類型保護(hù)

當(dāng)使用聯(lián)合類型時(shí),我們必須盡量把當(dāng)前值的類型收窄為當(dāng)前值的實(shí)際類型,而類型保護(hù)就是實(shí)現(xiàn)類型收窄的一種手段。


類型保護(hù)是可執(zhí)行運(yùn)行時(shí)檢查的一種表達(dá)式,用于確保該類型在一定的范圍內(nèi)。換句話說,類型保護(hù)可以保證一個(gè)字符串是一個(gè)字符串,盡管它的值也可以是一個(gè)數(shù)字。類型保護(hù)與特性檢測(cè)并不是完全不同,其主要思想是嘗試檢測(cè)屬性、方法或原型,以確定如何處理值。


目前主要有四種的方式來實(shí)現(xiàn)類型保護(hù):


6.1.1 in 關(guān)鍵字

interface Admin {

 name: string;

 privileges: string[];

} interface Employee {

 name: string;

 startDate: Date;

} type UnknownEmployee = Employee | Admin; function printEmployeeInformation(emp: UnknownEmployee) { console.log("Name: " + emp.name); if ("privileges" in emp) { console.log("Privileges: " + emp.privileges);

 } if ("startDate" in emp) { console.log("Start Date: " + emp.startDate);

 }

}

6.1.2 typeof 關(guān)鍵字

function padLeft(value: string, padding: string | number) { if (typeof padding === "number") { return Array(padding + 1).join(" ") + value;

 } if (typeof padding === "string") { return padding + value;

 } throw new Error(`Expected string or number, got '${padding}'.`);

}

typeof 類型保護(hù)只支持兩種形式:typeof v === "typename" 和 typeof v !== typename,"typename" 必須是 "number", "string", "boolean" 或 "symbol"。 但是 TypeScript 并不會(huì)阻止你與其它字符串比較,語(yǔ)言不會(huì)把那些表達(dá)式識(shí)別為類型保護(hù)。


6.1.3 instanceof 關(guān)鍵字

interface Padder {

 getPaddingString(): string;

} class SpaceRepeatingPadder implements Padder { constructor(private numSpaces: number) {}

 getPaddingString() { return Array(this.numSpaces + 1).join(" ");

 }

} class StringPadder implements Padder { constructor(private value: string) {}

 getPaddingString() { return this.value;

 }

} let padder: Padder = new SpaceRepeatingPadder(6); if (padder instanceof SpaceRepeatingPadder) { // padder的類型收窄為 'SpaceRepeatingPadder' }

6.1.4 自定義類型保護(hù)的類型謂詞(type predicate)

function isNumber(x: any): x is number { return typeof x === "number";

} function isString(x: any): x is string { return typeof x === "string";

}

七、_ 數(shù)字分隔符

TypeScript 2.7 帶來了對(duì)數(shù)字分隔符的支持,正如數(shù)值分隔符 ECMAScript 提案中所概述的那樣。對(duì)于一個(gè)數(shù)字字面量,你現(xiàn)在可以通過把一個(gè)下劃線作為它們之間的分隔符來分組數(shù)字:


const inhabitantsOfMunich = 1_464_301; const distanceEarthSunInKm = 149_600_000; const fileSystemPermission = 0b111_111_000; const bytes = 0b1111_10101011_11110000_00001101;

分隔符不會(huì)改變數(shù)值字面量的值,但邏輯分組使人們更容易一眼就能讀懂?dāng)?shù)字。以上 TS 代碼經(jīng)過編譯后,會(huì)生成以下 ES5 代碼:


"use strict"; var inhabitantsOfMunich = 1464301; var distanceEarthSunInKm = 149600000; var fileSystemPermission = 504; var bytes = 262926349;

7.1 使用限制

雖然數(shù)字分隔符看起來很簡(jiǎn)單,但在使用時(shí)還是有一些限制。比如你只能在兩個(gè)數(shù)字之間添加 _ 分隔符。以下的使用方式是非法的:


// Numeric separators are not allowed here.(6188) 3_.141592 // Error 3._141592 // Error // Numeric separators are not allowed here.(6188) 1_e10 // Error 1e_10 // Error // Cannot find name '_126301'.(2304) _126301 // Error // Numeric separators are not allowed here.(6188) 126301_ // Error // Cannot find name 'b111111000'.(2304) // An identifier or keyword cannot immediately follow a numeric literal.(1351) 0_b111111000 // Error // Numeric separators are not allowed here.(6188) 0b_111111000 // Error

當(dāng)然你也不能連續(xù)使用多個(gè) _ 分隔符,比如:


// Multiple consecutive numeric separators are not permitted.(6189) 123__456 // Error

7.2 解析分隔符

此外,需要注意的是以下用于解析數(shù)字的函數(shù)是不支持分隔符:


Number()

parseInt()

parseFloat()

這里我們來看一下實(shí)際的例子:


Number('123_456') NaN parseInt('123_456') 123 parseFloat('123_456') 123

很明顯對(duì)于以上的結(jié)果不是我們所期望的,所以在處理分隔符時(shí)要特別注意。當(dāng)然要解決上述問題,也很簡(jiǎn)單只需要非數(shù)字的字符刪掉即可。這里我們來定義一個(gè) removeNonDigits 的函數(shù):


const RE_NON_DIGIT = /[^0-9]/gu; function removeNonDigits(str) {

 str = str.replace(RE_NON_DIGIT, ''); return Number(str);

}

該函數(shù)通過調(diào)用字符串的 replace 方法來移除非數(shù)字的字符,具體的使用方式如下:


removeNonDigits('123_456') 123456 removeNonDigits('149,600,000') 149600000 removeNonDigits('1,407,836') 1407836

八、<Type> 語(yǔ)法

8.1 TypeScript 斷言

有時(shí)候你會(huì)遇到這樣的情況,你會(huì)比 TypeScript 更了解某個(gè)值的詳細(xì)信息。通常這會(huì)發(fā)生在你清楚地知道一個(gè)實(shí)體具有比它現(xiàn)有類型更確切的類型。


通過類型斷言這種方式可以告訴編譯器,“相信我,我知道自己在干什么”。類型斷言好比其他語(yǔ)言里的類型轉(zhuǎn)換,但是不進(jìn)行特殊的數(shù)據(jù)檢查和解構(gòu)。它沒有運(yùn)行時(shí)的影響,只是在編譯階段起作用。


類型斷言有兩種形式:


8.1.1 “尖括號(hào)” 語(yǔ)法

let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length;

8.1.2 as 語(yǔ)法

let someValue: any = "this is a string"; let strLength: number = (someValue as string).length;

8.2 TypeScript 泛型

對(duì)于剛接觸 TypeScript 泛型的讀者來說,首次看到 <T> 語(yǔ)法會(huì)感到陌生。其實(shí)它沒有什么特別,就像傳遞參數(shù)一樣,我們傳遞了我們想要用于特定函數(shù)調(diào)用的類型。




參考上面的圖片,當(dāng)我們調(diào)用 identity<Number>(1) ,Number 類型就像參數(shù) 1 一樣,它將在出現(xiàn) T 的任何位置填充該類型。圖中 <T> 內(nèi)部的 T 被稱為類型變量,它是我們希望傳遞給 identity 函數(shù)的類型占位符,同時(shí)它被分配給 value 參數(shù)用來代替它的類型:此時(shí) T 充當(dāng)?shù)氖穷愋停皇翘囟ǖ?Number 類型。


其中 T 代表 Type,在定義泛型時(shí)通常用作第一個(gè)類型變量名稱。但實(shí)際上 T 可以用任何有效名稱代替。除了 T 之外,以下是常見泛型變量代表的意思:


K(Key):表示對(duì)象中的鍵類型;

V(Value):表示對(duì)象中的值類型;

E(Element):表示元素類型。

其實(shí)并不是只能定義一個(gè)類型變量,我們可以引入希望定義的任何數(shù)量的類型變量。比如我們引入一個(gè)新的類型變量 U,用于擴(kuò)展我們定義的 identity 函數(shù):


function identity <T, U>(value: T, message: U) : T { console.log(message); return value;

} console.log(identity<Number, string>(68, "Semlinker"));



除了為類型變量顯式設(shè)定值之外,一種更常見的做法是使編譯器自動(dòng)選擇這些類型,從而使代碼更簡(jiǎn)潔。我們可以完全省略尖括號(hào),比如:


function identity <T, U>(value: T, message: U) : T { console.log(message); return value;

} console.log(identity(68, "Semlinker"));

對(duì)于上述代碼,編譯器足夠聰明,能夠知道我們的參數(shù)類型,并將它們賦值給 T 和 U,而不需要開發(fā)人員顯式指定它們。


九、@XXX 裝飾器

9.1 裝飾器語(yǔ)法

對(duì)于一些剛接觸 TypeScript 的小伙伴來說,在第一次看到 @Plugin({...}) 這種語(yǔ)法可能會(huì)覺得很驚訝。其實(shí)這是裝飾器的語(yǔ)法,裝飾器的本質(zhì)是一個(gè)函數(shù),通過裝飾器我們可以方便地定義與對(duì)象相關(guān)的元數(shù)據(jù)。


@Plugin({

 pluginName: 'Device',

 plugin: 'cordova-plugin-device',

 pluginRef: 'device',

 repo: 'https://github.com/apache/cordova-plugin-device',

 platforms: ['Android', 'Browser', 'iOS', 'macOS', 'Windows'],

}) @Injectable() export class Device extends IonicNativePlugin {}

在以上代碼中,我們通過裝飾器來保存 ionic-native 插件的相關(guān)元信息,而 @Plugin({...}) 中的 @ 符號(hào)只是語(yǔ)法糖,為什么說是語(yǔ)法糖呢?這里我們來看一下編譯生成的 ES5 代碼:


var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r;

}; var Device = /** @class */ (function (_super) {

   __extends(Device, _super); function Device() { return _super !== null && _super.apply(this, arguments) || this;

   }

   Device = __decorate([

       Plugin({ pluginName: 'Device', plugin: 'cordova-plugin-device', pluginRef: 'device', repo: 'https://github.com/apache/cordova-plugin-device', platforms: ['Android', 'Browser', 'iOS', 'macOS', 'Windows'],

       }),

       Injectable()

   ], Device); return Device;

}(IonicNativePlugin));

通過生成的代碼可知,@Plugin({...}) 和 @Injectable() 最終會(huì)被轉(zhuǎn)換成普通的方法調(diào)用,它們的調(diào)用結(jié)果最終會(huì)以數(shù)組的形式作為參數(shù)傳遞給 __decorate 函數(shù),而在 __decorate 函數(shù)內(nèi)部會(huì)以 Device 類作為參數(shù)調(diào)用各自的類型裝飾器,從而擴(kuò)展對(duì)應(yīng)的功能。


9.2 裝飾器的分類

在 TypeScript 中裝飾器分為類裝飾器、屬性裝飾器、方法裝飾器和參數(shù)裝飾器四大類。


9.2.1 類裝飾器

類裝飾器聲明:


declare type ClassDecorator = <TFunction extends Function>(

 target: TFunction

) => TFunction | void;

類裝飾器顧名思義,就是用來裝飾類的。它接收一個(gè)參數(shù):


target: TFunction - 被裝飾的類

看完第一眼后,是不是感覺都不好了。沒事,我們馬上來個(gè)例子:


function Greeter(target: Function): void {

 target.prototype.greet = function (): void { console.log("Hello Semlinker!");

 };

} @Greeter class Greeting { constructor() { // 內(nèi)部實(shí)現(xiàn) }

} let myGreeting = new Greeting();

myGreeting.greet(); // console output: 'Hello Semlinker!';

上面的例子中,我們定義了 Greeter 類裝飾器,同時(shí)我們使用了 @Greeter 語(yǔ)法糖,來使用裝飾器。


友情提示:讀者可以直接復(fù)制上面的代碼,在 TypeScript Playground 中運(yùn)行查看結(jié)果。

9.2.2 屬性裝飾器

屬性裝飾器聲明:


declare type PropertyDecorator = (target:Object,

 propertyKey: string | symbol ) => void;

屬性裝飾器顧名思義,用來裝飾類的屬性。它接收兩個(gè)參數(shù):


target: Object - 被裝飾的類

propertyKey: string | symbol - 被裝飾類的屬性名

趁熱打鐵,馬上來個(gè)例子熱熱身:


function logProperty(target: any, key: string) { delete target[key]; const backingField = "_" + key; Object.defineProperty(target, backingField, {

   writable: true,

   enumerable: true,

   configurable: true }); // property getter const getter = function (this: any) { const currVal = this[backingField]; console.log(`Get: ${key} => ${currVal}`); return currVal;

 }; // property setter const setter = function (this: any, newVal: any) { console.log(`Set: ${key} => ${newVal}`); this[backingField] = newVal;

 }; // Create new property with getter and setter Object.defineProperty(target, key, { get: getter, set: setter,

   enumerable: true,

   configurable: true });

} class Person { @logProperty public name: string; constructor(name : string) { this.name = name;

 }

} const p1 = new Person("semlinker");

p1.name = "kakuqo";

以上代碼我們定義了一個(gè) logProperty 函數(shù),來跟蹤用戶對(duì)屬性的操作,當(dāng)代碼成功運(yùn)行后,在控制臺(tái)會(huì)輸出以下結(jié)果:


Set: name => semlinker Set: name => kakuqo

9.2.3 方法裝飾器

方法裝飾器聲明:


declare type MethodDecorator = <T>(target:Object, propertyKey: string | symbol,          

 descriptor: TypePropertyDescript<T>) => TypedPropertyDescriptor<T> | void;

方法裝飾器顧名思義,用來裝飾類的方法。它接收三個(gè)參數(shù):


target: Object - 被裝飾的類

propertyKey: string | symbol - 方法名

descriptor: TypePropertyDescript - 屬性描述符

廢話不多說,直接上例子:


function LogOutput(tarage: Function, key: string, descriptor: any) { let originalMethod = descriptor.value; let newMethod = function(...args: any[]): any { let result: any = originalMethod.apply(this, args); if(!this.loggedOutput) { this.loggedOutput = new Array<any>();

   } this.loggedOutput.push({

     method: key,

     parameters: args,

     output: result,

     timestamp: new Date()

   }); return result;

 };

 descriptor.value = newMethod;

} class Calculator { @LogOutput double (num: number): number { return num * 2;

 }

} let calc = new Calculator();

calc.double(11); // console ouput: [{method: "double", output: 22, ...}] console.log(calc.loggedOutput);

9.2.4 參數(shù)裝飾器

參數(shù)裝飾器聲明:


declare type ParameterDecorator = (target: Object, propertyKey: string | symbol,

 parameterIndex: number ) => void

參數(shù)裝飾器顧名思義,是用來裝飾函數(shù)參數(shù),它接收三個(gè)參數(shù):


target: Object - 被裝飾的類

propertyKey: string | symbol - 方法名

parameterIndex: number - 方法中參數(shù)的索引值

function Log(target: Function, key: string, parameterIndex: number) { let functionLogged = key || target.prototype.constructor.name; console.log(`The parameter in position ${parameterIndex} at ${functionLogged} has

   been decorated`);

} class Greeter {

 greeting: string; constructor(@Log phrase: string) { this.greeting = phrase;

 }

} // console output: The parameter in position 0  // at Greeter has been decorated

十、#XXX 私有字段

在 TypeScript 3.8 版本就開始支持 ECMAScript 私有字段,使用方式如下:


class Person {

 #name: string; constructor(name: string) { this.#name = name;

 }


 greet() { console.log(`Hello, my name is ${this.#name}!`);

 }

} let semlinker = new Person("Semlinker");


semlinker.#name; //     ~~~~~ // Property '#name' is not accessible outside class 'Person' // because it has a private identifier.

與常規(guī)屬性(甚至使用 private 修飾符聲明的屬性)不同,私有字段要牢記以下規(guī)則:


私有字段以 # 字符開頭,有時(shí)我們稱之為私有名稱;

每個(gè)私有字段名稱都唯一地限定于其包含的類;

不能在私有字段上使用 TypeScript 可訪問性修飾符(如 public 或 private);

私有字段不能在包含的類之外訪問,甚至不能被檢測(cè)到。

10.1 私有字段與 private 的區(qū)別

說到這里使用 # 定義的私有字段與 private 修飾符定義字段有什么區(qū)別呢?現(xiàn)在我們先來看一個(gè) private 的示例:


class Person { constructor(private name: string){}

} let person = new Person("Semlinker"); console.log(person.name);

在上面代碼中,我們創(chuàng)建了一個(gè) Person 類,該類中使用 private 修飾符定義了一個(gè)私有屬性 name,接著使用該類創(chuàng)建一個(gè) person 對(duì)象,然后通過 person.name 來訪問 person 對(duì)象的私有屬性,這時(shí) TypeScript 編譯器會(huì)提示以下異常:


Property 'name' is private and only accessible within class 'Person'.(2341)

那如何解決這個(gè)異常呢?當(dāng)然你可以使用類型斷言把 person 轉(zhuǎn)為 any 類型:


console.log((person as any).name);

通過這種方式雖然解決了 TypeScript 編譯器的異常提示,但是在運(yùn)行時(shí)我們還是可以訪問到 Person 類內(nèi)部的私有屬性,為什么會(huì)這樣呢?我們來看一下編譯生成的 ES5 代碼,也許你就知道答案了:


var Person = /** @class */ (function () { function Person(name) { this.name = name;

   } return Person;

}()); var person = new Person("Semlinker"); console.log(person.name);

這時(shí)相信有些小伙伴會(huì)好奇,在 TypeScript 3.8 以上版本通過 # 號(hào)定義的私有字段編譯后會(huì)生成什么代碼:


class Person {

 #name: string; constructor(name: string) { this.#name = name;

 }


 greet() { console.log(`Hello, my name is ${this.#name}!`);

 }

}

以上代碼目標(biāo)設(shè)置為 ES2015,會(huì)編譯生成以下代碼:


"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet)

 || function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance");

   }

   privateMap.set(receiver, value); return value;

}; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet)

 || function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance");

   } return privateMap.get(receiver);

}; var _name; class Person { constructor(name) {

     _name.set(this, void 0);

     __classPrivateFieldSet(this, _name, name);

   }

   greet() { console.log(`Hello, my name is ${__classPrivateFieldGet(this, _name)}!`);

   }

}

_name = new WeakMap();

通過觀察上述代碼,使用 # 號(hào)定義的 ECMAScript 私有字段,會(huì)通過 WeakMap 對(duì)象來存儲(chǔ),同時(shí)編譯器會(huì)生成 __classPrivateFieldSet 和 __classPrivateFieldGet 這兩個(gè)方法用于設(shè)置值和獲取值。

藍(lán)藍(lán)設(shè)計(jì)www.cqzjtgb.com )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 平面設(shè)計(jì)服務(wù)

日歷

鏈接

個(gè)人資料

存檔

两人在一起打扑克的视频| 欧美日韩亚洲国产一区二区在线观看| 欧美成人一区二区免费高清观看| 午夜a级毛片| 国产真实伦视频高清在线观看 | 美女高潮喷水抽搐中文字幕| 国产伦精品一区二区三区视频9 | 亚洲av成人av| 国产精品女同一区二区软件 | 俺也久久电影网| 久久久精品欧美日韩精品| 乱人视频在线观看| 男女做爰动态图高潮gif福利片| 国产黄片美女视频| 欧美+日韩+精品| netflix在线观看网站| 国产精品一区二区三区四区免费观看 | 久久久久久久精品吃奶| 免费av毛片视频| 日韩欧美国产一区二区入口| 亚洲av中文字字幕乱码综合| 久久久久免费精品人妻一区二区| 看片在线看免费视频| 一级毛片女人18水好多| 免费人成在线观看视频色| 国产精品亚洲美女久久久| 在线a可以看的网站| 欧美最新免费一区二区三区 | 国产综合懂色| 啦啦啦韩国在线观看视频| 成人欧美大片| 国产精品乱码一区二三区的特点| 日日夜夜操网爽| 岛国在线观看网站| 欧美日韩精品网址| 国产精品影院久久| 香蕉av资源在线| 听说在线观看完整版免费高清| 亚洲精品美女久久久久99蜜臀| 变态另类丝袜制服| 天天躁日日操中文字幕| 香蕉丝袜av| 观看美女的网站| 欧美成人一区二区免费高清观看| 丰满人妻一区二区三区视频av | 中文字幕熟女人妻在线| 性色avwww在线观看| 热99re8久久精品国产| 日韩欧美在线二视频| 尤物成人国产欧美一区二区三区| 亚洲人成网站高清观看| 中文资源天堂在线| 99久久久亚洲精品蜜臀av| 国产真实伦视频高清在线观看 | 97超级碰碰碰精品色视频在线观看| 久久久久精品国产欧美久久久| 国产午夜精品论理片| 天天一区二区日本电影三级| 757午夜福利合集在线观看| 色老头精品视频在线观看| 国产精品久久久久久久电影 | 久久精品91无色码中文字幕| 禁无遮挡网站| 女警被强在线播放| 最新在线观看一区二区三区| 狂野欧美激情性xxxx| 亚洲天堂国产精品一区在线| 亚洲av成人精品一区久久| 内射极品少妇av片p| 天天一区二区日本电影三级| 三级男女做爰猛烈吃奶摸视频| 久久久久久人人人人人| 午夜福利欧美成人| 老熟妇仑乱视频hdxx| 亚洲最大成人中文| 国产aⅴ精品一区二区三区波| 中文字幕av在线有码专区| 99久久九九国产精品国产免费| 亚洲专区中文字幕在线| 神马国产精品三级电影在线观看| 国产午夜精品久久久久久一区二区三区 | 婷婷丁香在线五月| 国产av麻豆久久久久久久| 激情在线观看视频在线高清| 小说图片视频综合网站| 久久香蕉精品热| 亚洲自拍偷在线| 最好的美女福利视频网| 亚洲熟妇熟女久久| 日韩欧美精品免费久久 | 麻豆国产av国片精品| 国模一区二区三区四区视频| 亚洲国产精品成人综合色| 性色av乱码一区二区三区2| 久久久久久久精品吃奶| 最后的刺客免费高清国语| 久久九九热精品免费| 久久久久国内视频| 色综合欧美亚洲国产小说| 免费在线观看日本一区| 好看av亚洲va欧美ⅴa在| 网址你懂的国产日韩在线| 久久精品91蜜桃| 国产男靠女视频免费网站| 国产成年人精品一区二区| 性色av乱码一区二区三区2| 1024手机看黄色片| 亚洲国产精品久久男人天堂| 日韩欧美在线乱码| 成人国产综合亚洲| 精品人妻偷拍中文字幕| 男女下面进入的视频免费午夜| 丰满的人妻完整版| 国产黄a三级三级三级人| 超碰av人人做人人爽久久 | 精品日产1卡2卡| 亚洲午夜理论影院| 麻豆成人av在线观看| 此物有八面人人有两片| 国产不卡一卡二| 岛国视频午夜一区免费看| 偷拍熟女少妇极品色| 日日干狠狠操夜夜爽| 免费观看的影片在线观看| 黄色片一级片一级黄色片| 欧洲精品卡2卡3卡4卡5卡区| 欧美大码av| 18+在线观看网站| 亚洲专区国产一区二区| 亚洲真实伦在线观看| 午夜免费观看网址| 国产一区二区亚洲精品在线观看| a级毛片a级免费在线| 国产精品,欧美在线| 国内揄拍国产精品人妻在线| 久久久久久久久久黄片| 久久久精品欧美日韩精品| 最近视频中文字幕2019在线8| 母亲3免费完整高清在线观看| 一进一出抽搐动态| 久久久精品大字幕| av天堂中文字幕网| 在线观看一区二区三区| 搡老妇女老女人老熟妇| 亚洲aⅴ乱码一区二区在线播放| 日日干狠狠操夜夜爽| xxxwww97欧美| a级一级毛片免费在线观看| 夜夜看夜夜爽夜夜摸| 国产伦精品一区二区三区视频9 | 人妻久久中文字幕网| 国产精品亚洲美女久久久| 99国产极品粉嫩在线观看| 亚洲国产欧美人成| 一级作爱视频免费观看| 久久久久久久亚洲中文字幕 | 亚洲欧美日韩无卡精品| 欧美性猛交黑人性爽| 精品一区二区三区视频在线 | 男女床上黄色一级片免费看| 久久久久国内视频| 精品久久久久久久久久久久久| 亚洲av五月六月丁香网| 亚洲av成人不卡在线观看播放网| 久久中文看片网| 18禁在线播放成人免费| 精品免费久久久久久久清纯| 热99re8久久精品国产| 中文在线观看免费www的网站| 国产激情偷乱视频一区二区| 老司机深夜福利视频在线观看| 亚洲av五月六月丁香网| 国产免费一级a男人的天堂| 18禁黄网站禁片免费观看直播| 久久久久久大精品| 在线观看日韩欧美| 久久人妻av系列| 婷婷精品国产亚洲av| 一区福利在线观看| 叶爱在线成人免费视频播放| 变态另类丝袜制服| 91久久精品国产一区二区成人 | 淫妇啪啪啪对白视频| 国产精品99久久99久久久不卡| 久久国产乱子伦精品免费另类| 欧美性猛交黑人性爽| 日本 欧美在线| 母亲3免费完整高清在线观看| 国产成人aa在线观看| 天堂影院成人在线观看| 岛国在线观看网站| 无遮挡黄片免费观看| av视频在线观看入口| 亚洲国产色片| 国产伦一二天堂av在线观看| 88av欧美| 女人被狂操c到高潮| av天堂中文字幕网| 18禁美女被吸乳视频| svipshipincom国产片| 久久精品亚洲精品国产色婷小说| 一本综合久久免费| 小说图片视频综合网站| 亚洲成人精品中文字幕电影| 色综合亚洲欧美另类图片| 别揉我奶头~嗯~啊~动态视频| 欧美日韩国产亚洲二区| 99在线人妻在线中文字幕| 又爽又黄无遮挡网站| 亚洲国产高清在线一区二区三| 亚洲无线在线观看| 国产高清三级在线| 久久这里只有精品中国| 99精品久久久久人妻精品| 伊人久久精品亚洲午夜| 欧美一区二区国产精品久久精品| 久久久久精品国产欧美久久久| 神马国产精品三级电影在线观看| 国产精华一区二区三区| 国产精品99久久99久久久不卡| 国产三级黄色录像| 国内久久婷婷六月综合欲色啪| 1000部很黄的大片| 女人十人毛片免费观看3o分钟| 免费在线观看日本一区| 他把我摸到了高潮在线观看| 女人被狂操c到高潮| 国产午夜福利久久久久久| 亚洲av一区综合| 国产精品一区二区免费欧美| 五月伊人婷婷丁香| 久久久久性生活片| av在线蜜桃| av视频在线观看入口| 日日夜夜操网爽| 热99在线观看视频| 成年免费大片在线观看| 日韩欧美 国产精品| 久久6这里有精品| 美女被艹到高潮喷水动态| 久久亚洲精品不卡| 少妇的丰满在线观看| 我的老师免费观看完整版| 91久久精品国产一区二区成人 | 丰满的人妻完整版| 熟女少妇亚洲综合色aaa.| 91字幕亚洲| 在线观看午夜福利视频| 国产精品国产高清国产av| 亚洲熟妇熟女久久| 99热这里只有是精品50| 日韩欧美一区二区三区在线观看| 又爽又黄无遮挡网站| 成人av一区二区三区在线看| 久久久久九九精品影院| 免费av不卡在线播放| 黄色视频,在线免费观看| 亚洲av成人精品一区久久| 欧美bdsm另类| 老司机午夜十八禁免费视频| 国产精品综合久久久久久久免费| 18禁裸乳无遮挡免费网站照片| 国产伦在线观看视频一区| АⅤ资源中文在线天堂| 日韩欧美国产在线观看| 九九久久精品国产亚洲av麻豆| 亚洲人成伊人成综合网2020| 国产一区二区三区视频了| 69av精品久久久久久| 亚洲国产欧美网| 日韩欧美三级三区| 欧美另类亚洲清纯唯美| 无遮挡黄片免费观看| 熟女人妻精品中文字幕| 麻豆久久精品国产亚洲av| 日本 欧美在线| 亚洲一区二区三区不卡视频| 久久久久久大精品| 亚洲av中文字字幕乱码综合| www.999成人在线观看| xxxwww97欧美| 欧美三级亚洲精品| 精华霜和精华液先用哪个| 亚洲av电影在线进入| bbb黄色大片| 国产高清三级在线| 熟女电影av网| 国产高清视频在线观看网站| 久久久国产成人免费| 国产av麻豆久久久久久久| 国产三级中文精品| 99国产综合亚洲精品| 国产色爽女视频免费观看| 国产真人三级小视频在线观看| bbb黄色大片| 国产极品精品免费视频能看的| 男女视频在线观看网站免费| 天天一区二区日本电影三级| 长腿黑丝高跟| 国产色爽女视频免费观看| 欧美bdsm另类| www国产在线视频色| 国产精品综合久久久久久久免费| 最近在线观看免费完整版| 亚洲专区国产一区二区| 亚洲五月天丁香| 亚洲欧美日韩东京热| 亚洲狠狠婷婷综合久久图片| 18+在线观看网站| 变态另类丝袜制服| 欧美一级a爱片免费观看看| 免费av毛片视频| 久久精品国产99精品国产亚洲性色| 麻豆久久精品国产亚洲av| 国产成人影院久久av| 手机成人av网站| 国产伦人伦偷精品视频| 搞女人的毛片| 亚洲狠狠婷婷综合久久图片| 亚洲午夜理论影院| 黄色视频,在线免费观看| 一级毛片高清免费大全| 欧美一区二区国产精品久久精品| 午夜视频国产福利| 亚洲精品粉嫩美女一区| 美女被艹到高潮喷水动态| 五月玫瑰六月丁香| 久久久精品大字幕| 长腿黑丝高跟| 日韩大尺度精品在线看网址| 日本精品一区二区三区蜜桃| 天堂网av新在线| 亚洲,欧美精品.| av黄色大香蕉| 一进一出好大好爽视频| 制服人妻中文乱码| 宅男免费午夜| 最近最新中文字幕大全电影3| 久久婷婷人人爽人人干人人爱| 婷婷丁香在线五月| 最新中文字幕久久久久| 国产成人啪精品午夜网站| 中文字幕人成人乱码亚洲影| 国产精品久久电影中文字幕| 美女免费视频网站| 亚洲欧美精品综合久久99| 日韩成人在线观看一区二区三区| 国产精品嫩草影院av在线观看 | bbb黄色大片| 亚洲中文字幕一区二区三区有码在线看| 最后的刺客免费高清国语| 免费av不卡在线播放| 欧美黑人巨大hd| 757午夜福利合集在线观看| 制服丝袜大香蕉在线| 一本综合久久免费| 亚洲欧美一区二区三区黑人| 手机成人av网站| 丝袜美腿在线中文| 欧美最新免费一区二区三区 | 国产淫片久久久久久久久 | 无遮挡黄片免费观看| 欧美色欧美亚洲另类二区| 午夜福利在线在线| 色视频www国产| 人人妻人人澡欧美一区二区| 性欧美人与动物交配| 久久人人精品亚洲av| 免费观看的影片在线观看| 欧美日韩国产亚洲二区| 最新中文字幕久久久久| av视频在线观看入口| 国产色爽女视频免费观看| 动漫黄色视频在线观看| 嫩草影院精品99| 欧美黄色淫秽网站| 三级男女做爰猛烈吃奶摸视频| 琪琪午夜伦伦电影理论片6080| 亚洲欧美精品综合久久99| 欧美日韩黄片免| 天美传媒精品一区二区| 天堂网av新在线| 色噜噜av男人的天堂激情| 久99久视频精品免费| 每晚都被弄得嗷嗷叫到高潮| 国产中年淑女户外野战色| 久久久久亚洲av毛片大全| 99久久精品国产亚洲精品| 人人妻人人澡欧美一区二区| 色综合欧美亚洲国产小说| 男人舔女人下体高潮全视频| 日本在线视频免费播放| 国产精品久久久久久精品电影| 成人18禁在线播放| 亚洲av美国av| 国产欧美日韩精品一区二区| 欧美性猛交╳xxx乱大交人| 国产伦一二天堂av在线观看| 欧美成人性av电影在线观看| 国产精品98久久久久久宅男小说| 禁无遮挡网站| 久久久久久九九精品二区国产| 无人区码免费观看不卡| 无遮挡黄片免费观看| 蜜桃亚洲精品一区二区三区| 久久婷婷人人爽人人干人人爱| 级片在线观看| 亚洲精品美女久久久久99蜜臀| 国产欧美日韩精品一区二区| 俄罗斯特黄特色一大片| 婷婷亚洲欧美| 十八禁人妻一区二区| 国产一级毛片七仙女欲春2| 久久久国产成人免费| 99久久久亚洲精品蜜臀av| 一区二区三区免费毛片| 99热精品在线国产| 又粗又爽又猛毛片免费看| 国产精品女同一区二区软件 | 人人妻,人人澡人人爽秒播| 欧美成人a在线观看| 9191精品国产免费久久| 国产91精品成人一区二区三区| 亚洲一区高清亚洲精品| 每晚都被弄得嗷嗷叫到高潮| 丝袜美腿在线中文| 波野结衣二区三区在线 | 国产熟女xx| 18禁美女被吸乳视频| h日本视频在线播放| 久久久久九九精品影院| 国内少妇人妻偷人精品xxx网站| 国内精品久久久久久久电影| 无人区码免费观看不卡| 一进一出抽搐gif免费好疼| 操出白浆在线播放| 国产午夜福利久久久久久| 日韩有码中文字幕| 成人国产一区最新在线观看| 日本撒尿小便嘘嘘汇集6| 亚洲国产精品sss在线观看| 蜜桃久久精品国产亚洲av| 成人三级黄色视频| 国产在视频线在精品| 国产高清视频在线观看网站| 91在线观看av| 精品免费久久久久久久清纯| 小说图片视频综合网站| 日韩有码中文字幕| 美女大奶头视频| 亚洲avbb在线观看| 久久久久久久久大av| 精品国内亚洲2022精品成人| 成年女人永久免费观看视频| 午夜视频国产福利| 欧美成人性av电影在线观看| 在线a可以看的网站| 亚洲欧美日韩高清专用| av中文乱码字幕在线| 午夜福利成人在线免费观看| 高清日韩中文字幕在线| 国产在视频线在精品| 波多野结衣高清作品| 亚洲午夜理论影院| 国产精品 国内视频| 精品国产亚洲在线| 在线看三级毛片| 少妇丰满av| 久久久久久久亚洲中文字幕 | 午夜福利视频1000在线观看| 久久久久久九九精品二区国产| 最新在线观看一区二区三区| 国产主播在线观看一区二区| 免费在线观看日本一区| 亚洲av一区综合| av福利片在线观看| 一级作爱视频免费观看| 丁香欧美五月| xxx96com| 成年女人永久免费观看视频| 国产伦精品一区二区三区四那| 十八禁网站免费在线| 国产精品永久免费网站| 国产精品久久久久久亚洲av鲁大| 久久九九热精品免费| 在线观看66精品国产| 我要搜黄色片| 亚洲av中文字字幕乱码综合| 免费电影在线观看免费观看| 亚洲久久久久久中文字幕| 欧美bdsm另类| 色综合欧美亚洲国产小说| 成人三级黄色视频| www国产在线视频色| 久久国产乱子伦精品免费另类| 国内精品久久久久久久电影| 97碰自拍视频| bbb黄色大片| 久久精品人妻少妇| 最近在线观看免费完整版| 一区二区三区激情视频| 久久久久国内视频| 精品不卡国产一区二区三区| 欧美成人a在线观看| 一个人看的www免费观看视频| 免费搜索国产男女视频| 欧美不卡视频在线免费观看| 免费人成视频x8x8入口观看| 精品福利观看| 欧美黑人巨大hd| 黄色成人免费大全| 国模一区二区三区四区视频| 精品一区二区三区人妻视频| www国产在线视频色| 国产精品免费一区二区三区在线| 在线播放无遮挡| 最近最新免费中文字幕在线| 又粗又爽又猛毛片免费看| 亚洲人成网站在线播| 老汉色av国产亚洲站长工具| 国产美女午夜福利| av国产免费在线观看| 久久久久久久亚洲中文字幕 | 老司机午夜十八禁免费视频| 欧美午夜高清在线| 韩国av一区二区三区四区| 久久精品91无色码中文字幕| 日韩免费av在线播放| 欧美一级毛片孕妇| 国产国拍精品亚洲av在线观看 | 麻豆国产97在线/欧美| 又黄又粗又硬又大视频| 国产亚洲精品久久久com| 日本五十路高清| 久久久久精品国产欧美久久久| 90打野战视频偷拍视频| 在线a可以看的网站| 很黄的视频免费| 国产精品av视频在线免费观看| 麻豆一二三区av精品| 亚洲精华国产精华精| 亚洲精品亚洲一区二区| 精品久久久久久成人av| 中文字幕人妻丝袜一区二区| 99国产精品一区二区三区| 午夜福利视频1000在线观看| 欧美av亚洲av综合av国产av| 久久久久久久亚洲中文字幕 | 亚洲av电影不卡..在线观看| 天堂√8在线中文| 国产精品国产高清国产av| 日韩有码中文字幕| 99久久精品热视频| 欧美日本视频| 日本一二三区视频观看| 亚洲欧美日韩无卡精品| 中文字幕久久专区| 日韩av在线大香蕉| 97碰自拍视频| 国产又黄又爽又无遮挡在线| 天美传媒精品一区二区| 99久久久亚洲精品蜜臀av| 亚洲久久久久久中文字幕| 亚洲无线在线观看| 午夜两性在线视频| 美女高潮的动态| 99精品欧美一区二区三区四区| 在线十欧美十亚洲十日本专区| 一级作爱视频免费观看| 草草在线视频免费看| 中文字幕高清在线视频| 十八禁人妻一区二区| 在线视频色国产色| 日日夜夜操网爽| 亚洲精华国产精华精| 免费看a级黄色片| 99热这里只有是精品50| 亚洲欧美日韩卡通动漫| 亚洲精品亚洲一区二区| 国产又黄又爽又无遮挡在线| 亚洲欧美一区二区三区黑人| 在线观看av片永久免费下载| 亚洲天堂国产精品一区在线| 国产伦人伦偷精品视频| 久久久久久九九精品二区国产| 丰满人妻熟妇乱又伦精品不卡| 欧美性感艳星| 1000部很黄的大片| 欧美国产日韩亚洲一区| 超碰av人人做人人爽久久 | www.www免费av| 成人三级黄色视频| 国产av麻豆久久久久久久| 国模一区二区三区四区视频| 日韩成人在线观看一区二区三区| 日日夜夜操网爽| 免费看十八禁软件| 丁香欧美五月| 成人精品一区二区免费| 免费观看的影片在线观看| 一a级毛片在线观看| 欧美高清成人免费视频www| 一本久久中文字幕| 欧美bdsm另类| 亚洲成av人片在线播放无| 亚洲最大成人手机在线| 久久精品国产自在天天线| 国产亚洲精品综合一区在线观看| 黄片大片在线免费观看| 一a级毛片在线观看| 亚洲国产日韩欧美精品在线观看 | 日本与韩国留学比较| 免费人成在线观看视频色| 久久久久国内视频| 99国产极品粉嫩在线观看|