<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一篇文章一次性搞定JavaScript 從 ES6 到 ES12的基礎(chǔ)框架知識

          共 16007字,需瀏覽 33分鐘

           ·

          2022-11-01 20:15

          英文 | https://medium.com/@bluetch/javascript-es6-es7-es8-es9-es10-es11-and-es12-519d8be7d48c


          前言
          Javascript 是前端三劍客技術(shù)最重要的技能之一。每個學(xué)習(xí)前端的人,這個JavaScript技術(shù)是必須要學(xué)的。隨著技術(shù)不斷更新迭代,所以現(xiàn)在有一些新的知識來支持我們?nèi)W(xué)習(xí) ES6 ~ ES12。
          一、ECMAScript簡介
          ECMA 規(guī)范由各方組成,包括瀏覽器供應(yīng)商,他們會開會推動 JavaScript 提案。
          二、ES6 (ES2015)
          1.Class
          JavaScript 是一種使用原型鏈的語言。
          早期,類似OO的概念是通過原型鏈做出來的,相當(dāng)復(fù)雜。Class 終于在 ES6 中推出。
          class Animal {   constructor(name, color) {     this.name = name;     this.color = color;   }   // This is a property on the prototype chain   toString() {     console.log('name:' + this.name + ', color:' + this.color);
          } }
          var animal = new Animal('myDog', 'yellow'); // instantiateanimal.toString(); // name: myDog, color: yellow
          console.log(animal.hasOwnProperty('name')); //trueconsole.log(animal.hasOwnProperty('toString')); // falseconsole.log(animal.__proto__.hasOwnProperty('toString')); // true
          class Cat extends Animal { constructor(action) { // The subclass must call the super function in the constructor, otherwise an error will be reported when new comes out // If the constructor was not written originally, the default constructor with super will be automatically generated super('cat','white'); this.action = action; } toString() { console.log(super.toString()); }}
          var cat = new Cat('catch')cat.toString();
          console.log(cat instanceof Cat); // trueconsole.log(cat instanceof Animal); // true

          2. 模塊

          每個模塊都有自己的命名空間以避免沖突,使用導(dǎo)入和導(dǎo)出來導(dǎo)入和導(dǎo)出。

          基本上將 .js 文件視為模塊。

          3.箭頭函數(shù)

          () => {…},是函數(shù)的縮寫。最重要的是,他可以確保這始終指向自己

          不再寫 var self = this、var that = this 等等!

          const add = (a, b) => { return a + b};
          const res = add(1, 2); // 3
          // If the syntax is simple, `{}` and `return` can be omitted. It will look neaterconst minus = (a, b) => a - b;const res1 = minus(3, 1); // 2

          4.函數(shù)參數(shù)默認值

          如果函數(shù)不傳遞參數(shù),則使用默認值,更簡潔的寫法。

          function example(height = 50, width = 40) {      const newH = height * 10;     const newW = width * 10;     return newH + newW;}
          example(); // 900 (50*10 + 40*10)

          5. 模板字面量

          過去,長字符串的組合是通過 + 號來連接的。

          它的可讀性很差,使用模板字符串,它更容易閱讀。

          const firstName = 'Ken';const lastName = 'Huang';// not use template literalconst name = 'Hello, My name is' + firstName + ', ' + lastName;// use template literalconst nameWithLiteralString = `Hello, My name is ${firstName}, ${lastName}`;

          6.解構(gòu)賦值

          允許 JavaScript 輕松地從數(shù)組和對象中獲取內(nèi)容。

          const arr = [1, 2, 3, 4, 5];const [one, two, three] = arr;console.log(one); // 1console.log(two); // 2console.log(three); // 3
          // To skip certain valuesconst [first,,,,last] = arr;console.log(first); // 1console.log(last); // 5
          // Objects can also be destructurized and assignedconst student = { name: 'Ken Huang', age: 38, city: 'Taipei'};const {name, age, city} = student;console.log(name); // "Ken Huang"console.log(age); // "38"console.log(city); // "Taipei"

          7.擴展運算符

          它是用三點(...)表示,Array是可以擴展的,如果是Object,會按照key-value進行擴展。

          const stuendts = ['Angel', 'Ryan']; const people = ['Sara', ...stuendts, 'Kelly', 'Eason'];conslog.log(people); // ["Sara", "Angel", "Ryan", "Kelly", "Eason"]

          8. 對象屬性簡寫

          如果構(gòu)成對象的字段名稱與前面段落中的變量相同,則可以省略該值,看起來更流線型。

          const name = 'Angel', age = 18, city = 'ChangHwa';
          // Before ES6, we must write like thisconst customer = { name: name, age: age, city: city} // // {name: 'Angel', age: 18, city: 'ChangHwa'}
          // After ES6, we can do itconst newCustomer = { name, age, city} // {name: '小明Angel, age: 18, city: 'ChangHwa'}

          9. Promise

          Promise 是一種異步(非同步)寫法的解決方案,比原來的回調(diào)寫法更加優(yōu)雅。

          早期是開源社區(qū)的套件,后來被納入語言標(biāo)準(zhǔn)。

          早期回調(diào) hell……

          使用 Promise 后,回調(diào) hell 扁平化

          const waitSecond = new Promise((resolve, reject) => {    setTimeout(resolve, 1000);});waitSecond.then( () => {    console.log('hello World after 1 second.');     // output this line after 1 second    return waitSecond;}).then( () => {    console.log('Hell World after 2 sceond.');    // output this line after 2second})

          并且ES8(ES2017)發(fā)布了更完美的async,await,直接讓異步寫得像同步一樣。

          缺點是當(dāng)思路落到復(fù)雜的業(yè)務(wù)邏輯上時,有時會錯過await,在運行時發(fā)現(xiàn)錯誤。

          10. let, const 替換 var

          let:通用變量,可以被覆蓋

          const:一旦聲明,其內(nèi)容不可修改。因為數(shù)組和對象都是指標(biāo),所以它們的內(nèi)容可以增加或減少, 但不改變其指標(biāo).

          早期,JavaScript的var作用域是全局的。

          也就是說,變量是在使用后聲明的,執(zhí)行的時候會自動提到頂層,后面會賦值。

          更容易受到污染。

          console.log(a); // undefinedvar a = 10;

          使用 let 或 const

          console.log(a); // ReferenceError: Cannot access 'a' before initializationlet a = 10;

          三、ES7 (ES2016)

          1.Array.prototype.includes()

          用于判斷數(shù)組是否包含指定值,如果是,則返回true;否則,返回假。

          和之前indexOf的用法一樣,可以認為是返回一個布爾值,語義上更加清晰。

          const arr = [1, 2, 3, 4, 5];// Check if there is the number 3 in the arrayarr.include(3); // true
          if (arr.include(3)) { ... }// ... Equivalent to the previous writing of indexOfarr.indexOf(3); // 2 (return its array position)// If you want to write it in the if, you must add `> -1`, which is not as clear as the include in ES7 in terms of semanticsif (arr.indexOf(3) > -1) { ... }

          2. 冪運算符

          console.log(2**10); // 1024// equal toconsole.log(Math.pow(2, 10)); // 1024

          四、ES8 (ES2017)

          1.async, await

          異步函數(shù)是使用 async 關(guān)鍵字聲明的函數(shù),并且允許在其中使用 await 關(guān)鍵字。async 和 await 關(guān)鍵字使異步的、基于 Promise 的行為能夠以更簡潔的方式編寫,避免了顯式配置 Promise 鏈的需要。

          async test() {    try {        const result = await otherAsyncFunction();        console.log(result); // output result    } catch(e) {        console.log(e); // Can catch errors if otherAsyncFunction() throws an error    }}

          2. Object.values()

          返回對象自身屬性的所有值,不包括繼承的值。

          const exampleObj = {a: 1, b: 2, c: 3, d:4};console.log(Object.value(exampleObj)); // [1, 2, 3, 4];
          // To do the same thing before, use the following notation. much verboseconst values = Object.keys(exampleObj).map(key => exampleObj[key]);

          3. Object.entries()

          返回可枚舉鍵,即傳入對象本身的值。

          const exampleObj = {a: 1, b: 2, c: 3, d:4};console.log(Object.entries(exampleObj)); // [["a", 1], ["b", 2], ["c", 3], ["d", 4]];
          // Usually used with forfor (const [key, value] of Object.entries(exampleObj)) { console.log(`key: ${key}, value: ${value}`);}// key: a, value: 1// key: b, value: 2// key: c, value: 3// key: d, value: 4

          4. 字符串 padStart() & padEnd()

          你可以在字符串的開頭或結(jié)尾添加其他內(nèi)容,并將其填充到指定的長度。

          過去,這些功能通常是通過通用的輔助工具包(如 lodash)引入的,并將它們放在一起。

          本機語法現(xiàn)在直接提供:

          String.padStart(fillingLength, FillingContent);// 如果要填充的內(nèi)容過多,超過了“填充長度”,會從最左邊填充到長度上限,超出的部分會被截斷

          最常用的情況應(yīng)該是金額,填寫指定長度,不足加0。

          // padStart'100'.padStart(5, 0); // 00100// If the content to be padded exceeds the "padding length". Then fill in from the left to the upper limit of the length'100'.padStart(5, '987'); // 98100
          // padEnd'100'.padEnd(5, 9); // 10099// If the content to be padded exceeds the "padding length". Then fill in from the right to the upper limit of the length'100'.padStart(5, '987'); // 10098

          5.尾隨逗號

          允許在函數(shù)參數(shù)列表末尾使用逗號

          [    "foo",+   "baz",    "bar",-   "baz",  ]

          6. Object.getOwnPropertyDescriptors()

          獲取你自己的描述符,一般的開發(fā)業(yè)務(wù)需求通常不會用到。

          const exampleObj = {a: 1, b: 2, c: 3, d:4};Object.getOwnPropertyDescriptors(exampleObj);// {a: {…}, b: {…}, c: {…}, d: {…}}// a: {value: 1, writable: true, enumerable: true, configurable: true}// b: {value: 2, writable: true, enumerable: true, configurable: true}// c: {value: 3, writable: true, enumerable: true, configurable: true}// d: {value: 4, writable: true, enumerable: true, configurable: true}// __proto__: Object

          7. 共享數(shù)組緩沖區(qū)

          SharedArrayBuffer 是一個固定長度的原始二進制數(shù)據(jù)緩沖區(qū),類似于 ArrayBuffer。

          可用于在共享內(nèi)存上創(chuàng)建數(shù)據(jù)。與 ArrayBuffer 不同,SharedArrayBuffer 不能分離。

          /** * @param length size,unit byte * @returns {SharedArrayBuffer} the default value is 0。 */const sab = new SharedArrayBuffer(length);

          8. Atomics object

          Atomics 對象,它提供了一組靜態(tài)方法來對 SharedArrayBuffer 執(zhí)行原子操作。

          原子的所有屬性和函數(shù)都是靜態(tài)的,就像數(shù)學(xué)一樣,出不來新的。

          如果一個多線程同時在同一個位置讀寫數(shù)據(jù),原子操作保證了正在操作的數(shù)據(jù)如預(yù)期的那樣:即在上一個子操作結(jié)束后執(zhí)行下一個,操作不中斷。

          可以說是針對Node.Js中多線程Server的開發(fā)而加強的功能,在前端開發(fā)中使用的機會相當(dāng)?shù)汀?/span>

          chrome 已經(jīng)提供了支持

          五、ES9 (ES2018)

          1.循環(huán)等待

          在異步函數(shù)中,有時需要在同步 for 循環(huán)中使用異步(非同步)函數(shù)。

          async function process(array) {  for (const i of array) {    await doSomething(i);  }}
          async function process(array) { array.forEach(async i => { await doSomething(i); });}

          上面的代碼不會像預(yù)期的那樣輸出期望的結(jié)果。

          for循環(huán)本身還是同步的,會在循環(huán)中的異步函數(shù)完成之前執(zhí)行整個for循環(huán),然后將里面的異步函數(shù)逐一執(zhí)行。

          ES9 增加了異步迭代器,允許 await 與 for 循環(huán)一起使用,逐步執(zhí)行異步操作。

          async function process(array) {  for await (const i of array) {    doSomething(i);  }}

          2.promise.finally()

          無論是成功(.then())還是失敗(.catch()),Promise 后面都會執(zhí)行的部分。

          function process() {  process1()  .then(process2)  .then(process3)  .catch(err => {    console.log(err);  })  .finally(() => {    console.log(`it must execut no matter success or fail`);  });}

          3. Rest, Spread

          在 ES2015 中,Rest 不定長度參數(shù)…,可以轉(zhuǎn)換成數(shù)組傳入。

          function restParams(p1, p2, ...p3) {    console.log(p1); // 1    console.log(p2); // 2    console.log(p3); // [3, 4, 5]}restParams(1, 2, 3, 4, 5);

          而傳播則與其他相反,將數(shù)組轉(zhuǎn)換為單獨的參數(shù)。

          例如,Math.max() 返回傳入數(shù)字中的最大值。

          const values = [19, 90, -2, 6, 25];console.log( Math.max(...values) ); // 90

          它還提供了對Objects進行解構(gòu)賦值的功能。

          const myObject = {  a: 1,  b: 2,  c: 3};const { a, ...r } = myObject;// a = 1// r = { b: 2, c: 3 }
          // Can also be used in function input parametersfunction restObjectInParam({ a, ...r }) { console.log(a); // 1 console.log(r); // {b: 2, c: 3}}
          restObjectInParam({ a: 1, b: 2, c: 3});

          4. 正則表達式組

          RegExp 可以返回匹配的數(shù)據(jù)包

          const regExpDate = /([0-9]{4})-([0-9]{2})-([0-9]{2})/;const match      = regExpDate.exec('2020-06-25');const year       = match[1]; // 2020const month      = match[2]; // 06const day        = match[3]; // 25

          5.正則表達式前瞻否定

          TBD

          6.正則表達式 dotAll

          . 表示匹配除輸入以外的任何符號,添加這些標(biāo)志后,允許匹配輸入。

          /hello.world/.test('hello\nworld');  // false/hello.world/s.test('hello\nworld'); // true

          六、ES10 (ES2019)

          1.更友好的 JSON.stringify

          如果輸入是 Unicode 但超出范圍,則 JSON.stringify 最初會返回格式錯誤的 Unicode 字符串。

          現(xiàn)在是第 3 階段的提案,使其成為有效的 Unicode 并以 UTF-8 呈現(xiàn)

          2. Array.prototype.flat() & Array.prototype.flatMap()

          展平陣列

          const arr1 = [1, 2, [3, 4]];arr1.flat(); // [1, 2, 3, 4]
          const arr2 = [1, 2, [3, 4, [5, 6]]];arr2.flat(); // [1, 2, 3, 4, [5, 6]]// Pass in a number in flat, representing the flattening deptharr2.flat(2); // [1, 2, 3, 4, 5, 6]

          flatMap(),相當(dāng)于reduce with concat,可以展平一個維度

          let arr = ["早安", "", "今天天氣不錯"]
          arr.map(s => s.split(""))// [["早", "安"], [""], ["今", "天", "天", "氣", "不", "錯"]]
          arr.flatMap(s => s.split(''));// ["早", "安", "", "今", "天", "天", "氣", "不", "錯"]

          3. String.prototype.trimStart() & String.prototype.trimEnd()

          trimStart() 方法從字符串的開頭刪除空格,trimLeft() 是此方法的別名。

          const greeting = ‘ Hello world! ‘;console.log(greeting);// expected output: “ Hello world! “;console.log(greeting.trimStart());// expected output: “Hello world! “;

          trimEnd() 方法從字符串末尾刪除空格,trimRight() 是此方法的別名。

          const greeting = '   Hello world!   ';console.log(greeting);// expected output: "   Hello world!   ";console.log(greeting.trimEnd());// expected output: "   Hello world!";

          4. Object.fromEntries()

          Object.fromEntries() 方法將鍵值對列表轉(zhuǎn)換為對象。

          const entries = new Map([  ['foo', 'bar'],  ['baz', 42]]);const obj = Object.fromEntries(entries);console.log(obj);// expected output: Object { foo: "bar", baz: 42 }

          5. String.prototype.matchAll

          matchAll() 方法返回將字符串與正則表達式匹配的所有結(jié)果的迭代器,包括捕獲組。

          const regexp = /t(e)(st(\d?))/g;const str = 'test1test2';const array = [...str.matchAll(regexp)];console.log(array[0]);// expected output: Array ["test1", "e", "st1", "1"]console.log(array[1]);// expected output: Array ["test2", "e", "st2", "2"]

          6.fixed catch 綁定

          在使用catch之前,不管有用與否,一定要傳入一個eparameter來表示接收到的錯誤。

          如果現(xiàn)在不用,可以省略。

          try {...} catch(e) {...}
          // If e is not used, it can be omittedtry {...} catch {...}

          7. BigInt(新數(shù)字類型)

          BigInt 值,有時也稱為 BigInt,是一個 bigint 原語,通過將 n 附加到整數(shù)文字的末尾,或通過調(diào)用 BigInt() 函數(shù)(沒有 new 運算符)并給它一個整數(shù)值或字符串來創(chuàng)建 價值。

          ES5:String, Number, Boolean, Null, Undefined

          ES6 新增:Symbol,到ES6就一共有6 種類型

          ES10 新增:BigInt,就達到 7 種類型

          const theBiggestInt = 9007199254740991n;
          const alsoHuge = BigInt(9007199254740991);// ? 9007199254740991n
          const hugeString = BigInt("9007199254740991");// ? 9007199254740991n
          const hugeHex = BigInt("0x1fffffffffffff");// ? 9007199254740991n
          const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");// ? 9007199254740991n

          七、ES11 (ES2020)

          1.Promise.allSettled()

          Promise.allSettled() 方法返回一個在所有給定的 Promise 都已實現(xiàn)或拒絕后實現(xiàn)的 Promise,并帶有一組對象,每個對象都描述了每個 Promise 的結(jié)果。

          它通常用于當(dāng)你有多個不依賴于彼此成功完成的異步任務(wù),或者你總是想知道每個 Promise 的結(jié)果時。

          相比之下,Promise.all() 返回的 Promise 可能更合適,如果任務(wù)相互依賴/如果你想立即拒絕其中任何一個拒絕。

          const promise1 = Promise.resolve(3);const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));const promises = [promise1, promise2];Promise.allSettled(promises).  then((results) => results.forEach((result) => console.log(result.status)));// expected output:// "fulfilled"// "rejected"

          2. 可選鏈接?

          在開發(fā)中,很容易遇到先判斷數(shù)據(jù)是否存在,判斷是否寫入。

          const isUserExist = user && user.info;if (isUserExist) {     username = user.info.name; }

          如果返回的數(shù)據(jù)為null或者用戶對象下沒有.intounder,則會拋出Uncaught TypeError: Cannot read property...。

          導(dǎo)致程序無法繼續(xù)執(zhí)行

          使用 ?,語法更簡單

          const username = user?.info?.name;

          如果存在,獲取name的值,如果不存在,賦值undefined

          與 || 一起使用,只需一行!

          const username = user?.name || 'guest';

          3. Nullish 合并運算符 ??

          在JavaScript中,遇到0、null、undefuded時會自動轉(zhuǎn)為false。

          但有時0其實是一個正常的值,只能容錯undefined和null

          /** * user = { *    level: 0 * } */const level = user.level || 'no level'; // output as no level instead of expected 0// to fix it, it must use if simple processingconst level = user.level !== undefined && user.level !== null ? user.level : 'no level';

          但是使用??,你可以保持簡潔

          const username = user.level ?? 'no level'; // output 0. if level is not available, it becomes 'no level'.

          4.Dynamic-import

          從字面上看,應(yīng)該很容易理解,就是在需要的時候加載相關(guān)的邏輯。

          el.onclick = () => {    import(`/js/current-logic.js`)    .then((module) => {        module.doSomthing();    })    .catch((err) => {        handleError(err);    })}

          5. GlobalThis

          全局 globalThis 屬性包含全局 this 值,類似于全局對象。

          過去的做法是:

          // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThisconst getGlobal = function () {   if (typeof self !== 'undefined') { return self; }   if (typeof window !== 'undefined') { return window; }   if (typeof global !== 'undefined') { return global; }   throw new Error('unable to locate global object'); }; 
          var globals = getGlobal();

          現(xiàn)在,我們可以這樣做:

          function canMakeHTTPRequest() {  return typeof globalThis.XMLHttpRequest === 'function';}console.log(canMakeHTTPRequest());// expected output (in a browser): true

          八、ES12 (ES2021)

          1.Promise.any()

          Promise.any() 接受一個可迭代的 Promise 對象。它返回一個單一的 Promise,只要 iterable 中的任何一個 Promise 完成,就會返回一個 Promise,并帶有已完成的 Promise 的值。

          如果可迭代的實現(xiàn)中沒有任何承諾(如果所有給定的承諾都被拒絕),則返回的承諾會被 AggregateError 拒絕,AggregateError 是 Error 的一個新子類,它將單個錯誤組合在一起。

          const p1 = new Promise((resolve) => {  setTimeout(() => {    resolve('p1 resolved value')  }, 1000)})const p2 = new Promise((resolve) => {  setTimeout(() => {    resolve('p2 resolved value')  }, 500)})const p3 = new Promise((resolve) => {  setTimeout(() => {    resolve('p3 resolved value')  }, 1800)})Promise.any([p1, p2, p3]).then(value=>{  console.log(value)}) // p2 resolved value

          2. 邏輯賦值運算符

          在開發(fā)過程中,我們可以使用 ES2020 中提出的邏輯運算符 ||、&& 和 ??(Nullish coalescing operator)來解決一些問題。

          而 ES2021 會提出 ||= , &&= , ??= ,概念類似于 += :

          let b = 2b += 1 // equal to b = b + 1let a = nulla ||= 'some random text'  // a become to'some random text'// equal a = a || 'some random text'let c = 'some random texts'c &&= null  // c become to null// equal to c = c && nulllet d = nulld ??= false  // d become to false// equal to d = d ?? false

          3. WeakRef

          WeakRef 對象包含對對象的弱引用,該對象稱為其目標(biāo)或引用對象。對對象的弱引用是不會阻止對象被垃圾收集器回收的引用。

          相反,普通(或強)引用將對象保存在內(nèi)存中,當(dāng)一個對象不再有任何強引用時,JavaScript 引擎的垃圾收集器可能會銷毀該對象并回收其內(nèi)存。

          如果發(fā)生這種情況,你將無法再從弱引用中獲取對象。

          此示例啟動一個顯示在 DOM 元素中的計數(shù)器,當(dāng)該元素不再存在時停止:

          class Counter {  constructor(element) {    // Remember a weak reference to the DOM element    this.ref = new WeakRef(element);    this.start();  }
          start() { if (this.timer) { return; }
          this.count = 0;
          const tick = () => { // Get the element from the weak reference, if it still exists const element = this.ref.deref(); if (element) { element.textContent = ++this.count; } else { // The element doesn't exist anymore console.log("The element is gone."); this.stop(); this.ref = null; } };
          tick(); this.timer = setInterval(tick, 1000); }
          stop() { if (this.timer) { clearInterval(this.timer); this.timer = 0; } }}
          const counter = new Counter(document.getElementById("counter"));setTimeout(() => { document.getElementById("counter").remove();}, 5000);

          到這里,今天要跟你分享的內(nèi)容就全部結(jié)束了,這些都是我的一些練習(xí)和學(xué)習(xí)筆記總結(jié),希望對你有用。

          寫在最后

          今天分享的內(nèi)容,如果覺得有用的話,請記得點贊我,關(guān)注我,并將這篇文章與你的開發(fā)者朋友一起來分享它。

          最后,感謝你的閱讀。

          如果你身邊還有想學(xué)習(xí)前端開發(fā)的朋友,也請將我們的公眾號分享給他,也許對他的學(xué)習(xí)有幫助。

          學(xué)習(xí)更多技能

          請點擊下方公眾號

          瀏覽 74
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91人妻网 | 成人三级电影久久 | 爱爱视频在线看 | 国产又爽 又黄 免费观看视频 | 一区二区电影网 |