<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>




      前言

      最新的 ECMAScript 都已經(jīng)到發(fā)布到 2019 版了。

      我們應(yīng)該有的態(tài)度是: Stay hungry ! Stay young !

      從接觸 vue 到工作中用到 vue 將近 2 年了,在開發(fā) vue 項(xiàng)目中用到了很多 es6 的 api ,es6 給我的開發(fā)帶來了很大便利。

      本文只總結(jié)小汪在工作和面試中經(jīng)常遇到的 ES6 及之后的新 api 。

      有空就得多總結(jié),一邊總結(jié),一邊重溫學(xué)習(xí)!?。?br>
      正文

      1 let 和 const

      let 的作用域與 const 命令相同:只在聲明所在的塊級作用域內(nèi)有效。且不存在變量提升 。

      1.1 let

      let 所聲明的變量,可以改變。
      let a = 123 a = 456 // 正確,可以改變 let b = [123] b = [456] // 正確,可以改變
      1.2 const

      const 聲明一個只讀的常量。一旦聲明,常量的值就不能改變。

      簡單類型的數(shù)據(jù)(數(shù)值、字符串、布爾值),不可以變動
      const a = 123 a = 456 // 報錯,不可改變 const b = [123] b = [456] // 報錯,不可以重新賦值,不可改變
      復(fù)合類型的數(shù)據(jù)(主要是對象和數(shù)組),可以這樣子變動
      const a = [123] a.push(456) // 成功 const b = {} b.name = 'demo' // 成功
      1.3 不存在變量提升
      { let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1
      所以 for循環(huán)的計(jì)數(shù)器,就很合適使用 let 命令。
      let a = []; for (let i = 0; i < 10; i++) { a[i] = function () {
      console.log(i); }; } a[6](); // 6
      1.4 推薦

      對于 數(shù)值、字符串、布爾值 經(jīng)常會變的,用 let 聲明。

      對象、數(shù)組和函數(shù)用 const 來聲明。
      // 如經(jīng)常用到的導(dǎo)出 函數(shù) export const funA = function(){ // .... }
      2 解構(gòu)(Destructuring)

      2.1 數(shù)組

      一次性聲明多個變量:
      let [a, b, c] = [1, 2, 3]; console.log(a) // 1 console.log(b) // 2
      console.log(c) // 3
      結(jié)合擴(kuò)展運(yùn)算符:
      let [head, ...tail] = [1, 2, 3, 4]; console.log(head) // 1 console.log(tail)
      // [2, 3, 4]
      解構(gòu)賦值允許指定默認(rèn)值:
      let [foo = true] = []; foo // true let [x, y = 'b'] = ['a']; // x='a', y='b'
      2.2 對象

      解構(gòu)不僅可以用于數(shù)組,還可以用于對象。
      let { a, b } = { a: "aaa", b: "bbb" }; a // "aaa" b // "bbb"
      數(shù)組中,變量的取值由它 排列的位置 決定;而對象中,變量必須與 屬性 同名,才能取到正確的值。

      對象的解構(gòu)也可以指定默認(rèn)值。
      let {x = 3} = {}; x // 3 let {x, y = 5} = {x: 1}; x // 1 y // 5
      2.3 字符串

      字符串也可以解構(gòu)賦值。這是因?yàn)榇藭r,字符串被轉(zhuǎn)換成了一個類似數(shù)組的對象。
      const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o"
      2.4 用途

      * 交換變量的值 let x = 1; let y = 2; [x, y] = [y, x];
      * 從函數(shù)返回多個值 // 返回一個數(shù)組 function example() { let [a, b, c] = [1, 2, 3] return
      [a, b, c] } let [a, b, c] = example(); // 返回一個對象 function example() { return {
      foo: 1, bar: 2 }; } let { foo, bar } = example();
      * 函數(shù)參數(shù)的默認(rèn)值 function funA (a = 1, b = 2){ return a + b; } funA(3) // 5 因?yàn)?a 是
      3, b 是 2 funA(3,3) // 6 因?yàn)?a 是 3, b 是 3
      * 輸入模塊的指定方法
      加載模塊時,往往需要指定輸入哪些方法。解構(gòu)賦值使得輸入語句非常清晰。
      const { SourceMapConsumer, SourceNode } = require("source-map");
      在 utils.js 中:
      export const function A (){ console.log('A') } export const function B (){
      console.log('B') } export const function C (){ console.log('C') }
      在 組件中引用時:
      import { A, B, C } from "./utils.js" //調(diào)用 A() // 輸出 A
      3. 模板字符串(template string)

      模板字符串(template string)用反引號(`)標(biāo)識。

      3.1 純字符串

      所有模板字符串的空格和換行,都是被保留的.
      console.log(`輸出值為 N, 換行`) // "輸出值為 N 換行"
      3.2 字符串中加變量

      模板字符串中嵌入變量,需要將變量名寫在 ${ } 之中
      let x = 1; let y = 2; console.log(`輸出值為:${x}`) // "輸出值為:1"
      console.log(`輸出值為:${x + y}`) // "輸出值為:3"
      3.3 模板字符串之中還能調(diào)用函數(shù)。
      function fn() { return "Hello World"; } console.log(`輸出值為:${fn()}`) //
      "輸出值為:Hello World"
      4. 字符串函數(shù)擴(kuò)展

      * includes():返回布爾值,表示是否找到了參數(shù)字符串。
      * startsWith():返回布爾值,表示參數(shù)字符串是否在原字符串的頭部。
      * endsWith():返回布爾值,表示參數(shù)字符串是否在原字符串的尾部。 let s = 'Hello world!';
      s.startsWith('Hello') // true s.endsWith('!') // true s.includes('o') // true
      這三個方法都支持第二個參數(shù),表示開始搜索的位置。
      let s = 'Hello world!'; s.startsWith('world', 6) // true s.endsWith('Hello',
      5) // true s.includes('Hello', 6) // false
      5. 數(shù)值擴(kuò)展

      5.1 指數(shù)運(yùn)算符

      ES2016 新增了一個指數(shù)運(yùn)算符(**)。
      2 ** 2 // 4 2 ** 3 // 8
      這個運(yùn)算符的一個特點(diǎn)是右結(jié)合,而不是常見的左結(jié)合。多個指數(shù)運(yùn)算符連用時,是從最右邊開始計(jì)算的。
      // 相當(dāng)于 2 ** (3 ** 2) 2 ** 3 ** 2 // 512
      上面代碼中,首先計(jì)算的是第二個指數(shù)運(yùn)算符,而不是第一個。

      指數(shù)運(yùn)算符可以與等號結(jié)合,形成一個新的賦值運(yùn)算符(**=)。
      let a = 1.5; a **= 2; // 等同于 a = a * a; let b = 4; b **= 3; // 等同于 b = b * b *
      b;
      6. 函數(shù)的擴(kuò)展

      除了在解構(gòu)中說到的函數(shù)參數(shù)的默認(rèn)值,還有不少經(jīng)常會用到的方法。

      6. 1 rest 參數(shù)

      ES6 引入 rest 參數(shù)(形式為...變量名),用于獲取函數(shù)的多余參數(shù),這樣就不需要使用 arguments 對象了。rest
      參數(shù)搭配的變量是一個數(shù)組,該變量將多余的參數(shù)放入數(shù)組中。
      function add(...values) { let sum = 0; for (let val of values) { sum += val; }
      return sum; } add(2, 5, 3) // 10
      上面代碼的 add 函數(shù)是一個求和函數(shù),利用 rest 參數(shù),可以向該函數(shù)傳入任意數(shù)目的參數(shù)。

      注意,rest 參數(shù)之后不能再有其他參數(shù)(即只能是最后一個參數(shù)),否則會報錯。
      // 報錯 function f(a, ...b, c) { // ... }
      6.2 箭頭函數(shù)

      ES6 允許使用“箭頭”(=>)定義函數(shù)。
      const f = v => v; console.log('輸出值:', f(3)) // 輸出值: 3 // 等同于 const f =
      function (v) { return v; };
      如果箭頭函數(shù)不需要參數(shù)或需要多個參數(shù),就使用一個圓括號代表參數(shù)部分。
      // 等同于 const f = function () { return 5 }; const sum = (num1, num2) => num1 +
      num2; // 等同于 const sum = function(num1, num2) { return num1 + num2; };
      如果箭頭函數(shù)的代碼塊部分多于一條語句,就要使用大括號將它們括起來,并且使用 return 語句返回。
      const sum = (num1, num2) => { return num1 + num2; }
      箭頭函數(shù)的一個用處是簡化回調(diào)函數(shù)。
      const square = n => n * n; // 正常函數(shù)寫法 [1,2,3].map(function (x) { return x * x;
      }); // 箭頭函數(shù)寫法 [1,2,3].map(x => x * x);
      注意: 函數(shù)體內(nèi)的 this 對象,就是定義時所在的對象,而不是使用時所在的對象。

      this 對象的指向是可變的,但是在箭頭函數(shù)中,它是固定的。
      function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); }
      let id = 21; foo.call({ id: 42 }); // id: 42
      上面代碼中,setTimeout 的參數(shù)是一個箭頭函數(shù),這個箭頭函數(shù)的定義生效是在 foo 函數(shù)生成時,而它的真正執(zhí)行要等到 100
      毫秒后。如果是普通函數(shù),執(zhí)行時 this 應(yīng)該指向全局對象window,這時應(yīng)該輸出 21。但是,箭頭函數(shù)導(dǎo)致 this
      總是指向函數(shù)定義生效時所在的對象(本例是{ id: 42}),所以輸出的是 42。

      7. 數(shù)組的擴(kuò)展

      擴(kuò)展運(yùn)算符(spread)是三個點(diǎn)(...)。它好比 rest 參數(shù)的逆運(yùn)算,將一個數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列。

      7.1 數(shù)組合并的新寫法。
      const arr1 = ['a', 'b']; const arr2 = ['c']; const arr3 = ['d', 'e']; // ES5
      的合并數(shù)組 arr1.concat(arr2, arr3); // [ 'a', 'b', 'c', 'd', 'e' ] // ES6 的合并數(shù)組
      [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
      7.2 函數(shù)調(diào)用。
      function add(x, y) { return x + y; } const numbers = [4, 4]; add(...numbers)
      // 8
      7.3 復(fù)制數(shù)組的簡便寫法。
      const a1 = [1, 2]; // 寫法一 const a2 = [...a1]; a2[0] = 2; a1 // [1, 2] // 寫法二
      const [...a2] = a1; a2[0] = 2; a1 // [1, 2]
      上面的兩種寫法,a2 都是 a1 的克隆,且不會修改原來的數(shù)組。

      7.4 將字符串轉(zhuǎn)為真正的數(shù)組。
      [...'hello'] // [ "h", "e", "l", "l", "o" ]
      7.5 數(shù)組實(shí)例的 entries(),keys() 和 values()

      用 for...of 循環(huán)進(jìn)行遍歷,唯一的區(qū)別是 keys() 是對鍵名的遍歷、values() 是對鍵值的遍歷,entries() 是對鍵值對的遍歷。
      for (let index of ['a', 'b'].keys()) { console.log(index); } // 0 // 1 for
      (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b' for (let
      [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a"
      // 1 "b"
      7.6 includes()

      Array.prototype.includes 方法返回一個布爾值,表示某個數(shù)組是否包含給定的值,與字符串的 includes 方法類似。ES2016
      引入了該方法。
      [1, 2, 3].includes(2) // true [1, 2, 3].includes(4) // false [1, 2,
      NaN].includes(NaN) // true
      該方法的第二個參數(shù)表示搜索的起始位置,默認(rèn)為 0。如果第二個參數(shù)為負(fù)數(shù),則表示倒數(shù)的位置,如果這時它大于數(shù)組長度(比如第二個參數(shù)為 -4,但數(shù)組長度為 3
      ),則會重置為從 0 開始。
      [1, 2, 3].includes(3, 3); // false [1, 2, 3].includes(3, -1); // true
      8. 對象的擴(kuò)展

      8.1 屬性和方法 的簡潔表示法
      let birth = '2000/01/01'; const Person = { name: '張三', //等同于birth: birth
      birth, // 等同于hello: function ()... hello() { console.log('我的名字是', this.name); }
      };
      8.2 Object.assign()

      Object.assign方法用于對象的合并,將源對象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對象(target)。
      const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 };
      Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
      Object.assign方法的第一個參數(shù)是目標(biāo)對象,后面的參數(shù)都是源對象。

      注意,如果目標(biāo)對象與源對象有同名屬性,或多個源對象有同名屬性,則后面的屬性會覆蓋前面的屬性。
      const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 =
      { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
      Object.assign 方法實(shí)行的是淺拷貝,而不是深拷貝。
      const obj1 = {a: {b: 1}}; const obj2 = Object.assign({}, obj1); obj1.a.b = 2;
      obj2.a.b // 2
      上面代碼中,源對象 obj1 的 a 屬性的值是一個對象,Object.assign 拷貝得到的是這個對象的引用。這個對象的任何變化,都會反映到目標(biāo)對象上面。

      9. Set

      ES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set。它類似于數(shù)組,但是成員的值都是唯一的,沒有重復(fù)的值。

      Set 本身是一個構(gòu)造函數(shù),用來生成 Set 數(shù)據(jù)結(jié)構(gòu)。
      // 基本用法 const s = new Set(); [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); for
      (let i of s) { console.log(i); } // 2 3 5 4 // 去除數(shù)組的重復(fù)成員 const array = [1, 1,
      2, 3, 4, 4] [...new Set(array)] // [1, 2, 3, 4]
      10. Promise 對象

      Promise 是異步編程的一種解決方案。

      Promise 對象代表一個異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。?br>
      Promise 對象的狀態(tài)改變,只有兩種可能:從 pending 變?yōu)?fulfilled 和從 pending 變?yōu)?br> rejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會再變了,會一直保持這個結(jié)果,這時就稱為 resolved(已定型)
      const someAsyncThing = function(flag) { return new Promise(function(resolve,
      reject) { if(flag){ resolve('ok'); }else{ reject('error') } }); };
      someAsyncThing(true).then((data)=> { console.log('data:',data); // 輸出 'ok'
      }).catch((error)=>{ console.log('error:', error); // 不執(zhí)行 })
      someAsyncThing(false).then((data)=> { console.log('data:',data); // 不執(zhí)行
      }).catch((error)=>{ console.log('error:', error); // 輸出 'error' })
      上面代碼中,someAsyncThing 函數(shù)成功返回 ‘OK’, 失敗返回 ‘error’, 只有失敗時才會被 catch 捕捉到。

      最簡單實(shí)現(xiàn):
      // 發(fā)起異步請求 fetch('/api/todos') .then(res => res.json()) .then(data => ({ data
      })) .catch(err => ({ err }));
      來看一道有意思的面試題:
      setTimeout(function() { console.log(1) }, 0); new Promise(function
      executor(resolve) { console.log(2); for( var i=0 ; i<10000 ; i++ ) { i == 9999
      && resolve(); } console.log(3); }).then(function() { console.log(4); });
      console.log(5);
      這道題應(yīng)該考察 JavaScript 的運(yùn)行機(jī)制的。
      首先先碰到一個 setTimeout,于是會先設(shè)置一個定時,在定時結(jié)束后將傳遞這個函數(shù)放到任務(wù)隊(duì)列里面,因此開始肯定不會輸出 1 。
      然后是一個 Promise,里面的函數(shù)是直接執(zhí)行的,因此應(yīng)該直接輸出 2 3 。
      然后,Promise 的 then 應(yīng)當(dāng)會放到當(dāng)前 tick 的最后,但是還是在當(dāng)前 tick 中。
      因此,應(yīng)當(dāng)先輸出 5,然后再輸出 4 。
      最后在到下一個 tick,就是 1 。
      答案:“2 3 5 4 1”

      11. async 函數(shù)

      ES2017 標(biāo)準(zhǔn)引入了 async 函數(shù),使得異步操作變得更加方便。

      async 函數(shù)的使用方式,直接在普通函數(shù)前面加上 async,表示這是一個異步函數(shù),在要異步執(zhí)行的語句前面加上
      await,表示后面的表達(dá)式需要等待。async 是 Generator 的語法糖

      *
      * async 函數(shù)內(nèi)部 return 語句返回的值,會成為 then 方法回調(diào)函數(shù)的參數(shù)。 async function f() { return
      'hello world'; } f().then(v => console.log(v)) // "hello world"
      上面代碼中,函數(shù) f 內(nèi)部 return 命令返回的值,會被 then 方法回調(diào)函數(shù)接收到。

      *
      * async 函數(shù)內(nèi)部拋出錯誤,會導(dǎo)致返回的 Promise 對象變?yōu)?reject 狀態(tài)。拋出的錯誤對象會被 catch 方法回調(diào)函數(shù)接收到。
      async function f() { throw new Error('出錯了'); } f().then( result =>
      console.log(result), error => console.log(error) ) // Error: 出錯了
      *
      * async 函數(shù)返回的 Promise 對象,必須等到內(nèi)部所有 await 命令后面的 Promise 對象執(zhí)行完,才會發(fā)生狀態(tài)改變,除非遇到
      return 語句或者拋出錯誤。也就是說,只有 async 函數(shù)內(nèi)部的異步操作執(zhí)行完,才會執(zhí)行 then 方法指定的回調(diào)函數(shù)。
      下面是一個例子: async function getTitle(url) { let response = await fetch(url); let
      html = await response.text(); return
      html.match(/<title>([\s\S]+)<\/title>/i)[1]; }
      getTitle('https://tc39.github.io/ecma262/').then(console.log('完成')) //
      "ECMAScript 2017 Language Specification"
      上面代碼中,函數(shù) getTitle 內(nèi)部有三個操作:抓取網(wǎng)頁、取出文本、匹配頁面標(biāo)題。只有這三個操作全部完成,才會執(zhí)行 then 方法里面的
      console.log。

      *
      * 在 vue 中,我們可能要先獲取 token ,之后再用 token 來請求用戶數(shù)據(jù)什么的,可以這樣子用: methods:{ getToken()
      { return new Promise((resolve, reject) => { this.$http.post('/token') .then(res
      => { if (res.data.code === 200) { resolve(res.data.data) } else { reject() } })
      .catch(error => { console.error(error); }); }) }, getUserInfo(token) { return
      new Promise((resolve, reject) => { this.$http.post('/userInfo',{ token: token
      }) .then(res => { if (res.data.code === 200) { resolve(res.data.data) } else {
      reject() } }) .catch(error => { console.error(error); }); }) }, async
      initData() { let token = await this.getToken() this.userInfo =
      this.getUserInfo(token) }, }
      12. import 和 export

      import 導(dǎo)入模塊、export 導(dǎo)出模塊
      // example2.js // 導(dǎo)出默認(rèn), 有且只有一個默認(rèn) export default const example2 = { name : 'my
      name', age : 'my age', getName = function(){ return 'my name' } } //全部導(dǎo)入 //
      名字可以修改 import people from './example2.js'
      -------------------我是一條華麗的分界線--------------------------- // example1.js // 部分導(dǎo)出
      export let name = 'my name' export let age = 'my age' export let getName =
      function(){ return 'my name'} // 導(dǎo)入部分 // 名字必須和 定義的名字一樣。 import {name, age} from
      './example1.js' //有一種特殊情況,即允許你將整個模塊當(dāng)作單一對象進(jìn)行導(dǎo)入 //該模塊的所有導(dǎo)出都會作為對象的屬性存在 import * as
      example from "./example1.js" console.log(example.name) console.log(example.age)
      console.log(example.getName())
      -------------------我是一條華麗的分界線--------------------------- // example3.js //
      有導(dǎo)出默認(rèn), 有且只有一個默認(rèn),// 又有部分導(dǎo)出 export default const example3 = { birthday : '2018 09
      20' } export let name = 'my name' export let age = 'my age' export let getName
      = function(){ return 'my name'} // 導(dǎo)入默認(rèn)與部分 import example3, {name, age} from
      './example1.js'
      總結(jié):
      1.當(dāng)用 export default people 導(dǎo)出時,就用 import people 導(dǎo)入(不帶大括號) 2.一個文件里,有且只能有一個
      export default。但可以有多個 export。 3.當(dāng)用 export name 時,就用 import { name }導(dǎo)入(記得帶上大括號)
      4.當(dāng)一個文件里,既有一個 export default people, 又有多個 export name 或者 export age 時,導(dǎo)入就用
      import people, { name, age } 5.當(dāng)一個文件里出現(xiàn) n 多個 export 導(dǎo)出很多模塊,導(dǎo)入時除了一個一個導(dǎo)入,也可以用
      import * as example
      13. Class

      對于 Class ,小汪用在 react 中較多。

      13.1基本用法:
      //定義類 class FunSum { constructor(x, y) { this.x = x; this.y = y; } sum() {
      console.log( this.x +this.y') } } // 使用的時候,也是直接對類使用new命令,跟構(gòu)造函數(shù)的用法完全一致。 let f =
      new FunSum(10, 20); f.sum() // 30
      13.2 繼承
      class ColorPoint extends Point { constructor(x, y, color) { super(x, y); //
      調(diào)用父類的constructor(x, y) this.color = color; } toString() { return this.color + '
      ' + super.toString(); // 調(diào)用父類的toString() } }
      上面代碼中,constructor 方法和 toString 方法之中,都出現(xiàn)了super關(guān)鍵字,它在這里表示父類的構(gòu)造函數(shù),用來新建父類的 this 對象。

      子類必須在 constructor 方法中調(diào)用 super 方法,否則新建實(shí)例時會報錯。這是因?yàn)樽宇愖约旱?this
      對象,必須先通過父類的構(gòu)造函數(shù)完成塑造,得到與父類同樣的實(shí)例屬性和方法,然后再對其進(jìn)行加工,加上子類自己的實(shí)例屬性和方法。如果不調(diào)用 super
      方法,子類就得不到 this 對象。
      class Point { /* ... */ } class ColorPoint extends Point { constructor() { } }
      let cp = new ColorPoint(); // ReferenceError
      上面代碼中,ColorPoint 繼承了父類 Point,但是它的構(gòu)造函數(shù)沒有調(diào)用 super 方法,導(dǎo)致新建實(shí)例時報錯。

      最后

      總結(jié)和寫博客的過程就是學(xué)習(xí)的過程,是一個享受的過程 ?。。?br>
      好了,面試和工作中用到 ES6 精粹幾乎都在這了。

      如果你是 JavaScript 語言的初學(xué)者,建議先看 《JavaScript 語言入門教程》
      <https://wangdoc.com/javascript/>

      你以為本文就這么結(jié)束了 ? 精彩在后面 ?。?!



      如果你覺得該文章對你有幫助,歡迎到我的 github star 一下,謝謝。

      github 地址 <https://github.com/biaochenxuying/blog>

      參考文章:

      ECMAScript 6 標(biāo)準(zhǔn)入門 <http://es6.ruanyifeng.com/>

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點(diǎn)信息
      問題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          一级特黄色片 | 黄污视频免费看 | 漂亮少妇啪啪x88AV | 自拍偷拍国内 | 日韩电影一区二区三区三线免费观看 | 快点使劲对白露脸叫床 | 国产精品女生 | 丰满年轻岳乱妇免费观看 | 高清国产一区二区三区四区五区 | 99久久丫e6热精品 |