1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        2021年,快速了解 ES2022 新特性(二)

        共 10627字,需瀏覽 22分鐘

         ·

        2021-11-17 22:29

        點擊上方?前端瓶子君,關(guān)注公眾號

        回復(fù)算法,加入前端編程面試算法每日一題群



        接著上一篇快速了解ES特性之一(ES7-ES8)[3] ,今天我們主要來講ES新特性之 ES9 。上篇中我們已經(jīng)講了ES的由來,版本對應(yīng)規(guī)則等等內(nèi)容,這里我就不再贅述。讓我們直接開始吧

        快速了解ES特性 是我的系列文章,現(xiàn)在已有

        1. 快速了解ES特性之一(ES7-ES8)[4]
        2. 快速了解ES特性之二(ES9)[5]

        ES2018 / ES9

        Lifting template literal restriction 提升模板文字限制

        字符串模板語法是 ES6 的特性(很不巧的是,我根據(jù) 已完成的ES提案[6] 這里來講的,所以沒有寫 ES6 相關(guān)的內(nèi)容,后面會寫一個來補充)。在 ES6 的版本中,我們不能在帶標(biāo)簽的模板字符串中插入像 \unicode 之類的 錯誤 轉(zhuǎn)義字符,如果使用這類錯誤的轉(zhuǎn)義字符導(dǎo)致 bad escape sequence: \unicode 的錯誤。在 ES9 中則放開了這些限制,讓這些錯誤的轉(zhuǎn)義也可以正確的執(zhí)行。下面我們舉例說明一下

        function?hi(strings)?{
        ??console.log(strings);
        }
        let?words?=?hi`hi,?\ustar;`;
        復(fù)制代碼

        這里的 \ustar 很明顯不是一個正確的 Unicode ,我們這里使用 es-check[7] 指定 es6 來檢驗一下是否正確

        es-check?es6?test.js
        //?SyntaxError:?Bad?character?escape?sequence?(4:21)
        復(fù)制代碼

        很明顯和我們上文中說的錯誤一樣,無法正確識別轉(zhuǎn)義字符。我們這次將 es-check[8] 版本指定為 es9 ,再次檢測,no errors!

        es-check?es9?test.js
        //?ES-Check:?there?were?no?ES?version?matching?errors!
        復(fù)制代碼

        類似的像 \x 打頭的非十六進(jìn)制、 \123 這種錯誤的轉(zhuǎn)義,現(xiàn)在在 ES9 中都是 ok 的。

        s (dotAll) flag for regular expressions

        在正則表達(dá)式模式中,我們可以使用點 . 匹配任意的單個字符。但是這里面卻有兩個例外,默認(rèn):

        • . 不匹配 星體字符
        • . 不匹配 行終止符

        默認(rèn)不匹配 星體字符,我們可以通過給正則設(shè)置 u (unicode) 這個標(biāo)志來解決這個問題。但是對于 行終止符 來說,卻沒有一個類似的 flag 來解決這個問題。按照正常的正則語義,點 . 可以匹配任意字符,但實際上只能識別下面列出的 行終止符

        • U+000A 換行 (LF) (\n)
        • U+000D 回車 (CR) (\r)
        • U+2028 線分隔符
        • U+2029 段落分隔符

        在實際的場景中,還有一些字符可以被認(rèn)為是 行終止符 ,比如說:

        • U+000B 垂直制表符 (\v)
        • U+000C 換頁 (\f)
        • U+0085 下一行

        java 中,我們可以指定 flag Pattern.DOTALL 來讓 . 匹配所有;在 C# 則用 RegexOptions.Singleline 來匹配所有。所以 es9 新增了一個 flag s,來補充上面的場景。下面我們舉例來說明一下

        const?str?=?`
        hello
        world
        `
        ;
        const?r1?=?/hello.world/;
        console.log(r1.test(str),?r1.dotAll,?r1.flags);
        //?false?false
        const?r2?=?/hello.world/s;?//?添加?'s'?flag
        console.log(r2.test(str),?r2.dotAll,?r2.flags);
        //?true?true?s
        復(fù)制代碼

        有的同學(xué)可能會有這樣的疑問,這里為啥叫 s ,s 代表的 singleline 不會和 m ( multiline ) 沖突嗎 ?用官方的話來說:s 代表就是 singleline,也是 dotAll,含義一致。我們不好意思加一個新的標(biāo)記來做這件事情。s ( dotAll )表示的是讓 . 可以匹配任意字符,和 m ( multiline ) 標(biāo)記不沖突。大家愛咋用就咋用 ??

        RegExp named capture groups 正則命名捕獲組

        這個特性就比較花哨了,在以往的代碼中,假如我們要匹配一個日期中的年月日,我們可能是這樣做的

        const?str?=?"2021-10-24";
        const?r1?=?/(\d{4})-(\d{2})-(\d{2})/;
        const?groups?=?r1.exec(str);
        console.log("year:",?groups[1],?"month:",?groups[2],?"day:",?groups[3]);
        //?year:?2021?month:?10?day:?24
        復(fù)制代碼

        沒毛病啊,老鐵 ??,我所知道的幾門語言都是這樣做的。在這個語法出來之前,我都沒有思考過直接用上面的語法寫有啥毛病。按照定式思維,大家都這樣做,那這樣做就是對的。但是這個用官方的話來說:我們?nèi)绻闯R?guī)的寫法來寫正則,我們在使用這個 groups 的時候,假如我要獲取 月份 這個值,那么就需要仔細(xì)看一下這個正則表達(dá)式,我們用 括號 包的月份這個值,數(shù)一下,在第二個,按照正則的規(guī)則,groups 的第 0 個是表達(dá)式匹配的整串,要獲取后面分組出來的值需要 +1 ,所以我們要獲取 月份 這個值的索引應(yīng)該是 2 ,最終結(jié)果:groups[2] 。是不是很麻煩,還很容易錯?我:黑人問號.jpg。要這么說也沒毛病,現(xiàn)在我們來看看這個規(guī)范是怎么樣的:在先前分組的內(nèi)容前面加上一個 ?<給分組取的別名>,整的在一起就是 (?<給分組取的別名>...) 。我們把上面的示例修改一下

        const?str?=?"2021-10-24";
        const?r1?=?/(?\d{4})-(?\d{2})-(?\d{2})/;
        const?exec?=?r1.exec(str);
        console.log("year:",?exec[1],?"month:",?exec[2],?"day:",?exec[3]);
        console.log("year:",?exec.groups.year,?"month:",?exec.groups.month,?"day:",?exec.groups.day);
        //?const?{?groups:?{?year,?month,?day?}?}?=?exec;
        //?console.log("year:",?year,?"month:",?month,?"day:",?day);
        //?year:?2021?month:?10?day:?24
        //?year:?2021?month:?10?day:?24
        復(fù)制代碼

        是不是花哨起來了?no,no,no。這并不是全部,我們還可以進(jìn)行更花哨的匹配。如果我們需要匹配一個復(fù)雜重復(fù)字符串,比如我們需要匹配一個文本是否包含 aaabbbccc任何字符aaabbbccc任何字符aaabbbccc ,常規(guī)的寫法如下

        const?str?=?'asjdhkjlhsdkjaaabbbcccahsdkjashdjhsaaaabbbcccasjhdkljdhjkdaaaabbbcccashdlkj';
        const?r1?=?/a{3,}b{3}c{3,}.+a{3,}b{3}c{3,}.+a{3,}b{3}c{3,}/;
        const?result?=?r1.test(str);
        console.log(result);
        //?true
        復(fù)制代碼

        是不是感覺上面的正則有些繁瑣呢?這里我們可以使用這個命名捕獲進(jìn)行更加花哨的使用,這也是命名捕獲的一個新特性,如果我們需要匹配一個和前某個表達(dá)式一樣的結(jié)果,我們可以在表達(dá)式中用 \k 來替換,而不是重新寫一次一樣的表達(dá)式

        const?str?=?'asjdhkjlhsdkjaaabbbcccahsdkjashdjhsaaaabbbcccasjhdkljdhjkdaaaabbbcccashdlkj';
        const?r1?=?/(?a{3,}b{3}c{3,}).+\k.+\k/;
        const?result?=?r1.test(str);
        console.log(result);
        //?true
        復(fù)制代碼

        現(xiàn)在看起來是不是要好很多呢?上面的例子比較簡單,如果遇上更加復(fù)雜的情況,這個特性可以幫我們少寫很多重復(fù)的規(guī)則,并且更加的準(zhǔn)確,減少出錯的概率。

        這個命名捕獲同樣適用于字符串替換,我們還是用上面的日期做示例吧。假如我們需要把一個日期從 yyyy-MM-dd 變成 dd/MM/yyyy ,傳統(tǒng)的寫法是

        const?str?=?"2021-10-24";
        const?r1?=?/(\d{4})-(\d{2})-(\d{2})/;
        const?rd?=?str.replace(r1,"$3/$2/$1");
        console.log(rd);
        //?24/10/2021
        復(fù)制代碼

        我們修改成命名捕獲

        const?str?=?"2021-10-24";
        const?r1?=?/(?\d{4})-(?\d{2})-(?\d{2})/;
        const?rd?=?str.replace(r1,"$/$/$");
        console.log(rd);
        //?24/10/2021
        復(fù)制代碼

        確實更加快速確準(zhǔn),且不易出錯

        Rest/Spread Properties

        ES6 中我們已經(jīng)有了對數(shù)組的解構(gòu)賦值的剩余元素和數(shù)組字符串的展開方法。在 ES9 中則增加了對象的解構(gòu)賦值剩余屬性和對象字面量的展開。這個沒有啥多說的,直接舉例吧

        const?obj?=?{
        ??x:?1,?y:?2,?z:?3,?a:?"x",?b:?"y",?c:?"z",
        };
        const?{?x,?y,?z,?...letter?}?=?obj;
        console.log(x,?y,?z,?letter);
        //?1?2?3?{?a:?'x',?b:?'y',?c:?'z'?}
        復(fù)制代碼

        這個 Rest Properties ,我不知道用那個詞來準(zhǔn)確描述它,但是用起來卻是很順手。就如上面例子中的,我們從對象中解出 x, y, z ,并用 ... 這個展開符,將剩下的 a, b, c 重新組合到了新的對象 letter 中,原始的 obj 被吃光抹盡,所有都被提取出來了。所以 Rest Properties 就是讓 x, y, z 出來接客,讓剩下的 a, b, cletter 中休息?????

        我們接著講展開,使用上面的例子

        //?...
        const?objClone?=?{
        ??x,?y,?z,?...letter,
        };
        console.log(objClone);
        //?{?x:?1,?y:?2,?z:?3,?a:?'x',?b:?'y',?c:?'z'?}
        復(fù)制代碼

        這里展開符就和其義一毛一樣了,我們把 letter 里面的 a, b, c ,展開成一個個的屬性復(fù)制給 objClone 。這里就沒有什么理解偏差,展開符嘛,不就是把這些元素啊,屬性啊,拿出來給新的對象嗎?

        RegExp Lookbehind Assertions 正則表達(dá)式回溯斷言

        ES9 之前 EMACScript 正則只支持先行斷言,到了 ES9 正式支持后行斷言。這里我不多做展開講,因為這個不涉及特殊的語法,后面我會單獨寫一篇文章來講解 正則表達(dá)式 ,各語言基本通用,一把梭哈。

        下面我就簡簡單單舉個例子:假如我們需要匹配一個字符串 xyz 只有當(dāng)它前面是 uvw 時才匹配

        在沒有后行斷言的時候,如果要匹配,我們一般要這樣寫

        const?str?=?"rstuvwxyz123";
        const?r?=?/uvw(xyz)/;
        const?result?=?r.exec(str);
        console.log(result);
        //?[?'uvwxyz',?'xyz',?index:?3,?input:?'rstuvwxyz123',?groups:?undefined?]
        復(fù)制代碼

        有了后行斷言之后

        const?str?=?"rstuvwxyz123";
        const?r?=?/(?<=uvw)xyz/;
        const?result?=?r.exec(str);
        console.log(result);
        //?[?'xyz',?index:?6,?input:?'rstuvwxyz123',?groups:?undefined?]
        復(fù)制代碼

        有的同學(xué)肯定就疑惑了?上面那種不是更簡單嗎 ?? 。我覺得有道理,所以我把結(jié)果打印了一手。如果我們僅僅判斷一下是否匹配,確實用第一種方式,如果我們需要匹配結(jié)果,這兩種寫法就有了區(qū)別。如果使用后行斷言,uvw 是不會出現(xiàn)在匹配結(jié)果中的。

        上面我們講的僅僅只是后行斷言的 正面斷言 ,還有與之相反的 負(fù)面斷言(反向否定查找) 。我們接著使用上面的例子,但是這次我們需要的是 xyz 前面不是 uvw 時才匹配

        const?str?=?"rstuvwxyz123";
        const?r?=?/(?;
        const?result?=?r.exec(str);
        console.log(result);
        //?null
        復(fù)制代碼

        現(xiàn)在 xyz 前面緊挨著 uvw ,所以啥都匹配不到,我們修改一下,在 uvw 中間插入一個 0

        const?str?=?"rstuv0wxyz123";
        const?r?=?/(?;
        const?result?=?r.exec(str);
        console.log(result);
        //?[?'xyz',?index:?7,?input:?'rstuv0wxyz123',?groups:?undefined?]
        復(fù)制代碼

        現(xiàn)在就我們可以匹配到了

        RegExp Unicode Property Escapes 正則表達(dá)式中的 Unicode 屬性轉(zhuǎn)義

        我們在使用正則表達(dá)式的時候,常常需要匹配出不同的語言文字特殊符號等。比如說我們常見的需求:某個表單中不能夠輸入 emoji 或者其他的特殊字符,一丟丟的其他語種啊之類的,按照先前的寫法,我們常常得引入三方庫來匹配這些 奇怪的字符 ,但是這些 奇怪的字符 的范圍一直在不停的變化,所以我們引入的這些庫就存在需要經(jīng)常更新的問題。比如 emoji 就是更新狂魔,要匹配 emoji 就不得不不斷更新 emoji 匹配庫才能正確的過濾掉它們?,F(xiàn)在我們只需要這樣

        const?str?=?"hi,???";
        const?r1?=?/\p{Emoji}/gu;
        console.log(r1.exec(str));
        //?['??',?index:?4,?input:?'hi,???',?groups:?undefined]
        復(fù)制代碼

        就可以輕易的匹配到 emoji 表情,???有的同學(xué)可能直接就黑人問號.jpg了,對的,你沒有看錯,只需要這樣你就可以匹配到 emoji 了,這里也涉及了一丟丟 Unicode Emoji 的東西,想了解詳情的同學(xué),可以在 這兒[9] 查看到詳情和更多類似花括號包裹的 Emoji 這樣的東西,比如更常用的 Emoji_Presentation

        如果我想要匹配不是 Emoji 的呢?我們只需要把小 p 換成大 P 即可,是不是很簡單呢?

        const?str?=?"hi,???";
        const?r2?=?/(\P{Emoji})*/gu;
        console.log(r2.exec(str));
        //?['hi,?',?'?',?index:?0,?input:?'hi,???',?groups:?undefined]
        復(fù)制代碼

        這個特性很強,但是建議先不急著用,em em em,畢竟也得看瀏覽器嘛。當(dāng)然這個特性也不止這點東西,想要了解更多這個特性的同學(xué),可以到這兒 MDN \- Unicode property escapes[10] 仔細(xì)研讀,我也不多講了,大家加油

        Promise.prototype.finally

        這個就真的沒啥講頭了咯,這個方法是在 Promise then 或者 catch 執(zhí)行完之后執(zhí)行。一般就用來修改加載狀態(tài)或者某種用完就需要關(guān)閉的資源,比如:

        this.loading?=?true;
        xxxApi
        ??.listUser()
        ??.then((resp)?=>?{
        ????//?do?something...
        ??})
        ??.catch((e)?=>?{
        ????//?do?something...
        ??})
        ??.finally(()?=>?{
        ????this.loading?=?false;
        ??});
        復(fù)制代碼

        不單單只是上面說的兩種場景,如果我們需要在任務(wù)執(zhí)行完做某件事的時候,都可以用這個方法實現(xiàn)。

        Asynchronous Iteration 異步迭代器

        ES9 中,新增了 for-await-of 的用法。對于同步的迭代器,假如我們有一個 Promise 數(shù)組,要等著 Promise 元素一個個執(zhí)行完,如果按我們之前的方式

        function?newPromise(delay)?{
        ??return?new?Promise((resolve)?=>?{
        ????setTimeout(()?=>?{
        ??????console.log(`resolve:`,?delay);
        ??????resolve(delay);
        ????},?delay);
        ??});
        }

        async?function?test()?{
        ??const?arr?=?[newPromise(3000),?newPromise(2000),?newPromise(4000)];
        ??const?before?=?Date.now();
        ??for?(const?item?of?arr)?{
        ????console.log(Date.now(),?await?newPromise(1234));
        ????console.log(Date.now(),?await?item);
        ??}
        ??console.log(Date.now()?-?before);
        }
        test();
        //?resolve:?1234
        //?1635088618117?1234
        //?resolve:?2000
        //?resolve:?3000
        //?1635088619374?3000
        //?resolve:?4000
        //?resolve:?1234
        //?1635088621117?1234
        //?1635088622369?2000
        //?resolve:?1234
        //?1635088622369?1234
        //?1635088623616?4000
        //?5500
        復(fù)制代碼

        如果我們換成 for-await-of

        async?function?test2()?{
        ??const?arr?=?[newPromise(3000),?newPromise(2000),?newPromise(4000)];
        ??const?before?=?Date.now();
        ??for?await?(const?item?of?arr)?{
        ????console.log(Date.now(),?await?newPromise(1234));
        ????console.log(Date.now(),?item);
        ??}
        ??console.log(Date.now()?-?before);
        }
        test2();
        //?resolve:?2000
        //?resolve:?3000
        //?resolve:?4000
        //?resolve:?1234
        //?1635088545345?1234
        //?1635088546584?3000
        //?resolve:?1234
        //?1635088546584?1234
        //?1635088547826?2000
        //?resolve:?1234
        //?1635088547826?1234
        //?1635088549066?4000
        //?6733
        復(fù)制代碼

        如果就單單看結(jié)果而言,基本沒差,最終結(jié)果都一樣。但實際的執(zhí)行方式還是有差別:

        • 直接在循環(huán)中 await 的方式,是每一個獨立的 Promise 的等待,在第一個的打印中我們可以看出來,所有的任務(wù)根據(jù) delay 的時長,依次 resolve
        • 使用 for-await-of 會將數(shù)組的統(tǒng)一處理,然后再執(zhí)行循環(huán)體內(nèi)的代碼。

        說到底還是往事件循環(huán)里推事件的時機不同,實際業(yè)務(wù)場景中的使用,還得看各位同學(xué)的需求,不同的寫法還是有差別的,別弄錯了就成。

        說完同步,現(xiàn)在我們來說說 異步迭代器 ,在 ES9 中新增了一個 Symbol.asyncIterator[11]符號用來給對象自定義默認(rèn)的異步迭代器。

        下面我們舉個例子來創(chuàng)建一個異步可迭代對象

        const?ai?=?{
        ??//?整一個方法用來結(jié)束
        ??dispose()?{
        ????this.disposed?=?true;
        ??},
        ??[Symbol.asyncIterator]()?{
        ????return?{
        ??????//?下面的方法都用上箭頭函數(shù),免得手寫that
        ??????next:?()?=>?{
        ????????return?new?Promise((resolve,?_)?=>?{
        ??????????setTimeout(()?=>?{
        ????????????resolve({
        ??????????????done:?!!this.disposed,
        ??????????????value:?Date.now(),
        ????????????});
        ??????????},?200);
        ????????});
        ??????},
        ????};
        ??},
        };

        async?function?test()?{
        ??for?await?(const?it?of?ai)?{
        ????console.log(it);
        ??}
        }

        test();
        setTimeout(()?=>?{
        ??ai.dispose();
        },?1000);?//?一秒后結(jié)束

        //?1635170851461
        //?1635170851679
        //?1635170851881
        //?1635170852084
        復(fù)制代碼

        上面的例子中,我們在一個對象中,聲明了一個 Symbol.asyncIterator 的屬性方法,這個屬性方法返回一個對象,對象中包含一個 next 方法??雌饋硎遣皇呛苁煜ぃ课覀兟暶饕粋€同步迭代器,也是這樣做的。再看看這個方法的返回值,如果使用同步迭代器,我們直接返回 { value , done } 即可,value 表示實際的值,done 是個布爾值,用來標(biāo)記迭代器是否迭代完成。在異步迭代器中,我們返回的是一個 Promise 對象,返回的內(nèi)容則是 Promise resolve({ value , done })valuedone 的含義和上述同步迭代器一致。

        有的同學(xué)可能想,這么寫是不是太麻煩了,我們在同步迭代器中可以這樣寫

        const?iterator?=?{
        ??[Symbol.iterator]:?function*?()?{
        ????yield?`a`;
        ????yield?`b`;
        ????yield?`c`;
        ??},
        };
        for?(const?it?of?iterator)?{
        ??console.log(it);
        }
        //?a
        //?b
        //?c
        復(fù)制代碼

        那在異步迭代器中是不是也可以這樣寫?答案當(dāng)然是肯定的咯,我們只需要在 function 前面加個 async 用來表示是個異步迭代器即可

        const?asyncIterator?=?{
        ??[Symbol.asyncIterator]:?async?function*?()?{
        ????yield?`a`;
        ????yield?`b`;
        ????yield?`c`;
        ??},
        };

        (async?()?=>?{
        ??for?await?(const?x?of?asyncIterator)?{
        ????console.log(x);
        ??}
        })();
        //?a
        //?b
        //?c
        復(fù)制代碼

        看起來是不是 ojbk ?同樣

        function*?it()?{
        ??yield?`a`;
        ??yield?`b`;
        ??yield?`c`;
        }

        for?(const?i?of?it())?{
        ??console.log(i);
        }
        //?a
        //?b
        //?c
        async?function*?ait()?{
        ??yield?`a`;
        ??yield?`b`;
        ??yield?`c`;
        }

        (async?()?=>?{
        ??for?await?(const?i?of?ait())?{
        ????console.log(i);
        ??}
        })();
        //?a
        //?b
        //?c
        復(fù)制代碼

        這個看起來是不是感覺N多語言都有這個?看起來就是標(biāo)準(zhǔn)的 Stream 實現(xiàn),大家都大同小異,這樣也挺好,方便理解嘛,一個懂了,其他的基本也就ok了

        總結(jié)

        文章到這兒又要和大家說再見了,寥寥幾個特性有的時候真的恨不得寫個幾萬字,因為涉及的東西實在是太多了,不是簡單幾句就能說明白的。但是呢,這個時間它不允許啊,我也就只能含淚和大家說晚安了。

        這篇文章也寫了我?guī)滋?,寫寫這,寫寫那兒的,總算也是寫完了。感覺這個 ES9 全是正則相關(guān)的 ??,文章里面我給自己留了一個作業(yè),有空水一篇正則使用的文章。這個正則我相信很多同學(xué)都是迷迷糊糊的,我見過不少N年經(jīng)驗的對正則也不甚了解。所以這個正則,我肯定是要水的,盡請期待一下吧,不說包會,至少能夠和別人吹吹牛皮。


        如果文章對您有幫助的話,歡迎 點贊評論 、 關(guān)注收藏 、 分享 ,您的支持是我碼字的動力,萬分感謝?。?!??

        如果文章內(nèi)容出現(xiàn)錯誤的地方,歡迎指正,交流,謝謝??

        最后,大家可以 點擊這兒[12] 加入QQ群 FlutterCandies??[13] 和各路大佬們進(jìn)行交流哦,這里大家說話都超好聽的


        關(guān)于本文

        來源:盡管如此世界依然美麗

        https://juejin.cn/post/7023037816204427272


        最后

        歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
        回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會很認(rèn)真的解答喲!
        回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
        回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
        如果這篇文章對你有幫助,在看」是最大的支持
        ?》》面試官也在看的算法資料《《
        “在看和轉(zhuǎn)發(fā)”就是最大的支持


        瀏覽 42
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91丨九色丨 黑色JK在线 无码群交东京热 | 91麻豆视频免费 | 亚洲熟女少妇乱综合图片区 | 在线a视频 | 青青草国产一区二区三区 | 国产骚 | 欧美裸体走秀XXXXXX | 午夜福利无码视频 | 天天草比 | 少妇体内灌满精子 |