精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

面試 | 深拷貝的終極探索(99%的人都不知道)

開發 前端
本文我將給大家破解深拷貝的謎題,由淺入深,環環相扣,總共涉及4種深拷貝方式,每種方式都有自己的特點和個性。

劃重點,這是一道面試必考題,我靠這道題刷掉了多少面試者✧(≖ ◡ ≖✿)嘿嘿

首先這是一道非常棒的面試題,可以考察面試者的很多方面,比如基本功,代碼能力,邏輯能力,而且進可攻,退可守,針對不同級別的人可以考察不同難度,比如漂亮妹子就出1☆題,要是個帥哥那就得上5☆了,(*^__^*) 嘻嘻……

無論面試者多么優秀,漂亮的回答出問題,我總能夠瀟灑的再拋出一個問題,看著面試者露出驚異的眼神,默默一轉身,深藏功與名。

本文我將給大家破解深拷貝的謎題,由淺入深,環環相扣,總共涉及4種深拷貝方式,每種方式都有自己的特點和個性。

深拷貝 VS 淺拷貝

再開始之前需要先給同學科普下什么是深拷貝,和深拷貝有關系的另個一術語是淺拷貝又是什么意思呢?如果對這部分部分內容了解的同學可以跳過

其實深拷貝和淺拷貝都是針對的引用類型,JS中的變量類型分為值類型(基本類型)和引用類型;對值類型進行復制操作會對值進行一份拷貝,而對引用類型賦值,則會進行地址的拷貝,最終兩個變量指向同一份數據 

  1. // 基本類型  
  2. var a = 1;  
  3. var b = a;  
  4. a = 2;  
  5. console.log(a, b); // 2, 1 ,a b指向不同的數據  
  6. // 引用類型指向同一份數據  
  7. var a = {c: 1};  
  8. var b = a;  
  9. a.c = 2;  
  10. console.log(a.c, b.c); // 2, 2 全是2,a b指向同一份數據  

對于引用類型,會導致a b指向同一份數據,此時如果對其中一個進行修改,就會影響到另外一個,有時候這可能不是我們想要的結果,如果對這種現象不清楚的話,還可能造成不必要的bug

那么如何切斷a和b之間的關系呢,可以拷貝一份a的數據,根據拷貝的層級不同可以分為淺拷貝和深拷貝,淺拷貝就是只進行一層拷貝,深拷貝就是無限層級拷貝 

  1. var a1 = {b: {c: {}};  
  2. var a2 = shallowClone(a1); // 淺拷貝  
  3. a2.b.c === a1.b.c // true  
  4. var a3 = clone(a3); // 深拷貝  
  5. a3.b.c === a1.b.c // false  

淺拷貝的實現非常簡單,而且還有多種方法,其實就是遍歷對象屬性的問題,這里只給出一種,如果看不懂下面的方法,或對其他方法感興趣,可以看我的這篇文章 

  1. function shallowClone(source) {  
  2. var target = {};  
  3. for(var i in source) { 
  4. if (source.hasOwnProperty(i)) {  
  5. target[i] = source[i];  
  6.  
  7.  
  8. return target;  
  9.  

最簡單的深拷貝

深拷貝的問題其實可以分解成兩個問題,淺拷貝+遞歸,什么意思呢?假設我們有如下數據

  1. var a1 = {b: {c: {d: 1}}; 

只需稍加改動上面淺拷貝的代碼即可,注意區別 

  1. function clone(source) {  
  2. var target = {};  
  3. for(var i in source) {  
  4. if (source.hasOwnProperty(i)) {  
  5. if (typeof source[i] === 'object') {  
  6. target[i] = clone(source[i]); // 注意這里  
  7. else {  
  8. target[i] = source[i];  
  9.  
  10.  
  11.  
  12. return target;  
  13.  

大部分人都能寫出上面的代碼,但當我問上面的代碼有什么問題嗎?就很少有人答得上來了,聰明的你能找到問題嗎?

其實上面的代碼問題太多了,先來舉幾個例子吧

  • 沒有對參數做檢驗
  • 判斷是否對象的邏輯不夠嚴謹
  • 沒有考慮數組的兼容

(⊙o⊙),下面我們來看看各個問題的解決辦法,首先我們需要抽象一個判斷對象的方法,其實比較常用的判斷對象的方法如下,其實下面的方法也有問題,但如果能夠回答上來那就非常不錯了,如果完美的解決辦法感興趣,不妨看看這里吧 

  1. function isObject(x) {  
  2. return Object.prototype.toString.call(x) === '[object Object]' 
  3.  

函數需要校驗參數,如果不是對象的話直接返回 

  1. function clone(source) {  
  2. if (!isObject(source)) return source;  
  3. // xxx  
  4.  

關于第三個問題,嗯,就留給大家自己思考吧,本文為了減輕大家的負擔,就不考慮數組的情況了,其實ES6之后還要考慮set, map, weakset, weakmap,/(ㄒoㄒ)/~~

其實吧這三個都是小問題,其實遞歸方法最大的問題在于爆棧,當數據的層次很深是就會棧溢出

下面的代碼可以生成指定深度和每層廣度的代碼,這段代碼我們后面還會再次用到 

  1. function createData(deep, breadth) {  
  2. var data = {};  
  3. var temp = data;  
  4. for (var i = 0; i < deep; i++) { 
  5. temp = temp['data'] = {};  
  6. for (var j = 0; j < breadth; j++) { 
  7. temp[j] = j;  
  8.  
  9.  
  10. return data;  
  11.  
  12. createData(1, 3); // 1層深度,每層有3個數據 {data: {0: 0, 1: 1, 2: 2}}  
  13. createData(3, 0); // 3層深度,每層有0個數據 {data: {data: {data: {}}}}  

當clone層級很深的話就會棧溢出,但數據的廣度不會造成溢出 

  1. clone(createData(1000)); // ok  
  2. clone(createData(10000)); // Maximum call stack size exceeded  
  3. clone(createData(10, 100000)); // ok 廣度不會溢出  

其實大部分情況下不會出現這么深層級的數據,但這種方式還有一個致命的問題,就是循環引用,舉個例子 

  1. var a = {};  
  2. a.a = a;  
  3. clone(a) // Maximum call stack size exceeded 直接死循環了有沒有,/(ㄒoㄒ)/~~  

關于循環引用的問題解決思路有兩種,一直是循環檢測,一種是暴力破解,關于循環檢測大家可以自己思考下;關于暴力破解我們會在下面的內容中詳細講解

一行代碼的深拷貝

有些同學可能見過用系統自帶的JSON來做深拷貝的例子,下面來看下代碼實現 

  1. function cloneJSON(source) {  
  2. return JSON.parse(JSON.stringify(source));  
  3.  

其實我第一次簡單這個方法的時候,由衷的表示佩服,其實利用工具,達到目的,是非常聰明的做法

下面來測試下cloneJSON有沒有溢出的問題,看起來cloneJSON內部也是使用遞歸的方式 

  1. cloneJSON(createData(10000)); // Maximum call stack size exceeded 

既然是用了遞歸,那循環引用呢?并沒有因為死循環而導致棧溢出啊,原來是JSON.stringify內部做了循環引用的檢測,正是我們上面提到破解循環引用的第一種方法:循環檢測 

  1. var a = {};  
  2. a.a = a;  
  3. cloneJSON(a) // Uncaught TypeError: Converting circular structure to JSON  

破解遞歸爆棧

其實破解遞歸爆棧的方法有兩條路,第一種是消除尾遞歸,但在這個例子中貌似行不通,第二種方法就是干脆不用遞歸,改用循環,當我提出用循環來實現時,基本上90%的前端都是寫不出來的代碼的,這其實讓我很震驚

舉個例子,假設有如下的數據結構

  1. var a = { 
  2.     a1: 1, 
  3.     a2: { 
  4.         b1: 1, 
  5.         b2: { 
  6.             c1: 1 
  7.         } 
  8.    } 
  9.  

這不就是一個樹嗎,其實只要把數據橫過來看就非常明顯了

  1.  /   \ 
  2. a1   a2         
  3. |    / \          
  4. 1   b1 b2      
  5.     |   |         
  6.     1  c1 
  7.         | 
  8.         1    

用循環遍歷一棵樹,需要借助一個棧,當棧為空時就遍歷完了,棧里面存儲下一個需要拷貝的節點

首先我們往棧里放入種子數據,key用來存儲放哪一個父元素的那一個子元素拷貝對象

然后遍歷當前節點下的子元素,如果是對象就放到棧里,否則直接拷貝 

  1. function cloneLoop(x) { 
  2.     const root = {}; 
  3.  
  4.     // 棧 
  5.     const loopList = [ 
  6.         { 
  7.             parent: root, 
  8.             key: undefined, 
  9.             data: x, 
  10.         } 
  11.     ]; 
  12.  
  13.     while(loopList.length) { 
  14.         // 深度優先 
  15.         const node = loopList.pop(); 
  16.         const parent = node.parent; 
  17.         const key = node.key
  18.         const data = node.data; 
  19.  
  20.         // 初始化賦值目標,key為undefined則拷貝到父元素,否則拷貝到子元素 
  21.         let res = parent; 
  22.         if (typeof key !== 'undefined') { 
  23.             res = parent[key] = {}; 
  24.         } 
  25.  
  26.         for(let k in data) { 
  27.             if (data.hasOwnProperty(k)) { 
  28.                 if (typeof data[k] === 'object') { 
  29.                     // 下一次循環 
  30.                     loopList.push({ 
  31.                         parent: res, 
  32.                         key: k, 
  33.                         data: data[k], 
  34.                     }); 
  35.                 } else { 
  36.                     res[k] = data[k]; 
  37.                 } 
  38.             } 
  39.         } 
  40.     } 
  41.  
  42.     return root; 
  43.  

改用循環后,再也不會出現爆棧的問題了,但是對于循環引用依然無力應對

破解循環引用

有沒有一種辦法可以破解循環應用呢?別著急,我們先來看另一個問題,上面的三種方法都存在的一個問題就是引用丟失,這在某些情況下也許是不能接受的

舉個例子,假如一個對象a,a下面的兩個鍵值都引用同一個對象b,經過深拷貝后,a的兩個鍵值會丟失引用關系,從而變成兩個不同的對象,o(╯□╰)o 

  1. var b = 1;  
  2. var a = {a1: b, a2: b};  
  3. a.a1 === a.a2 // true  
  4. var c = clone(a);  
  5. c.a1 === c.a2 // false  

如果我們發現個新對象就把這個對象和他的拷貝存下來,每次拷貝對象前,都先看一下這個對象是不是已經拷貝過了,如果拷貝過了,就不需要拷貝了,直接用原來的,這樣我們就能夠保留引用關系了,✧(≖ ◡ ≖✿)嘿嘿

但是代碼怎么寫呢,o(╯□╰)o,別急往下看,其實和循環的代碼大體一樣,不一樣的地方我用// ==========標注出來了

引入一個數組uniqueList用來存儲已經拷貝的數組,每次循環遍歷時,先判斷對象是否在uniqueList中了,如果在的話就不執行拷貝邏輯了

find是抽象的一個函數,其實就是遍歷uniqueList 

  1. // 保持引用關系 
  2. function cloneForce(x) { 
  3.     // ============= 
  4.     const uniqueList = []; // 用來去重 
  5.     // ============= 
  6.  
  7.     let root = {}; 
  8.  
  9.     // 循環數組 
  10.     const loopList = [ 
  11.         { 
  12.             parent: root, 
  13.             key: undefined, 
  14.             data: x, 
  15.         } 
  16.     ]; 
  17.  
  18.     while(loopList.length) { 
  19.         // 深度優先 
  20.         const node = loopList.pop(); 
  21.         const parent = node.parent; 
  22.         const key = node.key
  23.         const data = node.data; 
  24.  
  25.         // 初始化賦值目標,key為undefined則拷貝到父元素,否則拷貝到子元素 
  26.         let res = parent; 
  27.         if (typeof key !== 'undefined') { 
  28.             res = parent[key] = {}; 
  29.         } 
  30.          
  31.         // ============= 
  32.         // 數據已經存在 
  33.         let uniqueData = find(uniqueList, data); 
  34.         if (uniqueData) { 
  35.             parent[key] = uniqueData.target; 
  36.             break; // 中斷本次循環 
  37.         } 
  38.  
  39.         // 數據不存在 
  40.         // 保存源數據,在拷貝數據中對應的引用 
  41.         uniqueList.push({ 
  42.             source: data, 
  43.             target: res, 
  44.         }); 
  45.         // ============= 
  46.      
  47.         for(let k in data) { 
  48.             if (data.hasOwnProperty(k)) { 
  49.                 if (typeof data[k] === 'object') { 
  50.                     // 下一次循環 
  51.                     loopList.push({ 
  52.                         parent: res, 
  53.                         key: k, 
  54.                         data: data[k], 
  55.                     }); 
  56.                 } else { 
  57.                     res[k] = data[k]; 
  58.                 } 
  59.             } 
  60.         } 
  61.     } 
  62.  
  63.     return root; 
  64.  
  65. function find(arr, item) { 
  66.     for(let i = 0; i < arr.length; i++) { 
  67.         if (arr[i].source === item) { 
  68.             return arr[i]; 
  69.         } 
  70.     } 
  71.  
  72.     return null
  73.  

下面來驗證一下效果,amazing 

  1. var b = 1;  
  2. var a = {a1: b, a2: b};  
  3. a.a1 === a.a2 // true  
  4. var c = cloneForce(a);  
  5. c.a1 === c.a2 // true  

接下來再說一下如何破解循環引用,等一下,上面的代碼好像可以破解循環引用啊,趕緊驗證一下

驚不驚喜,(*^__^*) 嘻嘻…… 

  1. var a = {};  
  2. a.a = a;  
  3. cloneForce(a)  

看起來完美的cloneForce是不是就沒問題呢?cloneForce有兩個問題

第一個問題,所謂成也蕭何,敗也蕭何,如果保持引用不是你想要的,那就不能用cloneForce了;

第二個問題,cloneForce在對象數量很多時會出現很大的問題,如果數據量很大不適合使用cloneForce

性能對比

上邊的內容還是有點難度,下面我們來點更有難度的,對比一下不同方法的性能

我們先來做實驗,看數據,影響性能的原因有兩個,一個是深度,一個是每層的廣度,我們采用固定一個變量,只讓一個變量變化的方式來測試性能

測試的方法是在指定的時間內,深拷貝執行的次數,次數越多,證明性能越好

下面的runTime是測試代碼的核心片段,下面的例子中,我們可以測試在2秒內運行clone(createData(500, 1)的次數 

  1. function runTime(fn, time) { 
  2.     var stime = Date.now(); 
  3.     var count = 0; 
  4.     while(Date.now() - stime < time) { 
  5.         fn(); 
  6.         count++; 
  7.     } 
  8.  
  9.     return count
  10.  
  11. runTime(function () { clone(createData(500, 1)) }, 2000);  

下面來做第一個測試,將廣度固定在100,深度由小到大變化,記錄1秒內執行的次數 

深度 clone cloneJSON cloneLoop cloneForce
500 351 212 338 372
1000 174 104 175 143
1500 116 67 112 82
2000 92 50 88 69

 

將上面的數據做成表格可以發現,一些規律

  • 隨著深度變小,相互之間的差異在變小
  • clone和cloneLoop的差別并不大
  • cloneLoop > cloneForce > cloneJSON

 

 

 

 

我們先來分析下各個方法的時間復雜度問題,各個方法要做的相同事情,這里就不計算,比如循環對象,判斷是否為對象

  • clone時間 = 創建遞歸函數 + 每個對象處理時間
  • cloneJSON時間 = 循環檢測 + 每個對象處理時間 * 2 (遞歸轉字符串 + 遞歸解析)
  • cloneLoop時間 = 每個對象處理時間
  • cloneForce時間 = 判斷對象是否緩存中 + 每個對象處理時間

cloneJSON的速度只有clone的50%,很容易理解,因為其會多進行一次遞歸時間

cloneForce由于要判斷對象是否在緩存中,而導致速度變慢,我們來計算下判斷邏輯的時間復雜度,假設對象的個數是n,則其時間復雜度為O(n2),對象的個數越多,cloneForce的速度會越慢

1 + 2 + 3 ... + n = n^2/2 - 1

關于clone和cloneLoop這里有一點問題,看起來實驗結果和推理結果不一致,其中必有蹊蹺

接下來做第二個測試,將深度固定在10000,廣度固定為0,記錄2秒內執行的次數 

寬度 clone cloneJSON cloneLoop cloneForce
0 13400 3272 14292 989

排除寬度的干擾,來看看深度對各個方法的影響

  • 隨著對象的增多,cloneForce的性能低下凸顯
  • cloneJSON的性能也大打折扣,這是因為循環檢測占用了很多時間
  • cloneLoop的性能高于clone,可以看出遞歸新建函數的時間和循環對象比起來可以忽略不計

下面我們來測試一下cloneForce的性能極限,這次我們測試運行指定次數需要的時間 

  1. var data1 = createData(2000, 0); 
  2. var data2 = createData(4000, 0); 
  3. var data3 = createData(6000, 0); 
  4. var data4 = createData(8000, 0); 
  5. var data5 = createData(10000, 0); 
  6.  
  7. cloneForce(data1) 
  8. cloneForce(data2) 
  9. cloneForce(data3) 
  10. cloneForce(data4) 
  11. cloneForce(data5)  

通過測試發現,其時間成指數級增長,當對象個數大于萬級別,就會有300ms以上的延遲

 

 

 

 

總結

尺有所短寸有所長,無關乎好壞優劣,其實每種方法都有自己的優缺點,和適用場景,人盡其才,物盡其用,方是真理

下面對各種方法進行對比,希望給大家提供一些幫助 

  clone cloneJSON cloneLoop cloneForce
難度 ☆☆ ☆☆☆ ☆☆☆☆
兼容性 ie6 ie8 ie6 ie6
循環引用 一層 不支持 一層 支持
棧溢出 不會 不會
保持引用
適合場景 一般數據拷貝 一般數據拷貝 層級很多 保持引用關系

本文的靈感都來自于@jsmini/clone,如果大家想使用文中的4種深拷貝方式,可以直接使用@jsmini/clone這個庫 

  1. // npm install --save @jsmini/clone  
  2. import { clone, cloneJSON, cloneLoop, cloneForce } from '@jsmini/clone' 

本文為了簡單和易讀,示例代碼中忽略了一些邊界情況,如果想學習生產中的代碼,請閱讀@jsmini/clone的源碼

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2020-07-29 09:53:09

VSCode編碼工具插件

2023-01-13 16:48:48

前端開發JavaScript

2021-07-22 09:28:35

DockerLinux命令

2022-06-19 14:38:55

Python

2022-10-31 18:38:24

MySQL數據訂單表

2021-09-24 14:20:25

開發技能工具

2025-02-18 00:05:00

2022-06-23 13:13:36

GitHub開發技巧

2025-02-04 17:33:00

2020-12-21 09:00:04

MySQL緩存SQL

2020-08-04 09:57:52

JS開發前端

2025-10-28 04:10:00

Web開發工具

2020-12-21 09:44:53

MySQL查詢緩存數據庫

2017-10-22 15:34:34

手機內存清理內存手機

2023-10-11 08:16:42

客戶端服務器內容

2021-01-12 12:33:20

Pandas技巧代碼

2021-11-12 10:05:19

跳表BAT面試

2024-10-22 09:03:35

前端signalAPI

2024-05-15 18:59:01

JavaScript語言原型

2020-11-12 10:16:32

企業信息化
點贊
收藏

51CTO技術棧公眾號

逼特逼视频在线| 国产精品一国产精品最新章节| av永久免费观看| 亚洲a成人v| 亚洲午夜久久久| 你懂的网址一区二区三区| 亚洲专区第一页| 亚洲视频精品| 中文欧美在线视频| 97精品人人妻人人| 播放一区二区| 亚洲一区二区三区中文字幕在线 | eeuss中文| 日本精品久久久久久| 琪琪一区二区三区| 韩国视频理论视频久久| 99自拍偷拍视频| 老司机aⅴ在线精品导航| 欧美日韩国产大片| 日本少妇高潮喷水视频| 免费**毛片在线| 久久综合久久久久88| 亚洲sss综合天堂久久| 日本va欧美va国产激情| 欧美一区在线看| 亚洲天堂一区二区三区| 在线观看免费视频黄| 国产精品久久久久久吹潮| 午夜精品福利视频网站| 在线观看免费黄色片| 国产黄色片在线观看| av中文字幕在线不卡| 亚洲精品欧美日韩| 怡红院成永久免费人全部视频| 亚洲黄页一区| 欧美另类极品videosbest最新版本| 国产成人精品无码免费看夜聊软件| 亚洲精品一区国产| 91精品在线一区二区| av五月天在线| 3d欧美精品动漫xxxx无尽| 天天免费综合色| 屁屁影院ccyy国产第一页| 日韩三级影院| 国产精品国产三级国产普通话蜜臀| 九九九九精品| 老牛影视av牛牛影视av| 国产精品一区二区三区网站| 国产色综合天天综合网| 中文在线观看免费高清| 视频一区二区中文字幕| 欧美最近摘花xxxx摘花| 五月天婷婷综合网| 亚洲精品一级| 992tv成人免费视频| 国产精品theporn动漫| 欧美精品国产| 欧美精品电影免费在线观看| 久久久精品一区二区涩爱| 伊人久久大香线| 蜜臀久久99精品久久久久久宅男| 精品视频第一页| 色男人天堂综合再现| 中文字幕综合一区| 日韩一区二区不卡视频| 欧美黄色一级视频| 久久久久久久久久久91| 亚州国产精品视频| 久久久久国产精品一区二区| 日本a级片电影一区二区| 免费的毛片视频| 日本在线播放一区二区三区| 国产精品永久免费在线| 国产精品人妻一区二区三区| 国产精品99久久久久久宅男| 国产精品国产三级国产专区53 | 欧美mv日韩mv国产| www国产视频| 久久97视频| 色偷偷偷亚洲综合网另类| 一级免费黄色录像| 一区在线视频| 日本不卡高字幕在线2019| 中文字幕乱码视频| 国产不卡在线播放| 欧美18视频| 99re热久久这里只有精品34| 亚洲欧美福利一区二区| 久久这里只有精品23| 欧美一区久久久| 欧美日韩dvd在线观看| 无码人妻丰满熟妇啪啪网站| 少妇高潮一区二区三区| 中文字幕日韩精品有码视频| 波多野结衣爱爱视频| 夜夜嗨一区二区| 国产精品免费一区豆花| 成 人片 黄 色 大 片| 久久综合资源网| 中文一区一区三区免费| 免费毛片b在线观看| 欧美人与性动xxxx| 久久久久国产精品无码免费看| 欧美码中文字幕在线| 九九热精品视频国产| 黄色一级视频免费看| 国产精品羞羞答答xxdd| 日本一区二区三区四区在线观看| 午夜影院免费在线| 欧美主播一区二区三区| 国产一级免费片| 欧美激情偷拍自拍| 4k岛国日韩精品**专区| 99国产精品99| 中文字幕乱码一区二区免费| 免费在线观看视频a| 国产午夜久久av| 国产一区二区三区丝袜| 久久精品无码人妻| 狠狠色丁香久久婷婷综| 欧美一区二区三区四区五区六区| 国产乱码在线| 日韩一区二区在线播放| 国产一级久久久久毛片精品| 好吊视频一区二区三区四区| 国产精品欧美日韩| 清纯唯美亚洲色图| 亚洲综合精品久久| aaaaaaaa毛片| 四季av一区二区凹凸精品| 欧美洲成人男女午夜视频| 亚洲AV无码一区二区三区少妇| 国产精品素人一区二区| 中文字幕日本最新乱码视频| 91综合久久爱com| 久热精品视频在线观看一区| 最近中文字幕在线免费观看| www日韩大片| 国模无码视频一区二区三区| 凹凸成人在线| 欧美黑人巨大xxx极品| 91在线观看喷潮| 欧美国产1区2区| 欧美性猛交久久久乱大交小说| 亚洲毛片免费看| 91av在线精品| 色天堂在线视频| 欧美性生交xxxxx久久久| 中文字幕精品视频在线| 亚洲精品麻豆| 国模精品一区二区三区| av蜜臀在线| 亚洲国产欧美一区二区丝袜黑人| 亚洲国产综合久久| 97国产一区二区| 国产美女网站在线观看| 五月天亚洲一区| 日本欧美一级片| 黄色毛片在线观看| 欧美无砖专区一中文字| 黑人と日本人の交わりビデオ| 日韩高清不卡一区二区三区| 亚洲二区三区四区| 亚洲精品66| 久久99亚洲热视| 黄色aaa大片| 精品国产户外野外| 一区二区三区四区免费| 秋霞午夜鲁丝一区二区老狼| 日韩欧美激情一区二区| 四虎精品在线观看| 久久99久国产精品黄毛片入口| 亚洲a视频在线| 精品成人乱色一区二区| 小早川怜子久久精品中文字幕| 日本伊人色综合网| 中国 免费 av| 精品人人人人| 国产精品av在线播放| 日本暖暖在线视频| 日韩一区二区三区视频在线| 日本系列第一页| 久久精品人人做人人爽人人| 999久久久精品视频| 国产一区亚洲| 欧美三级电影在线播放| 电影中文字幕一区二区| 欧美精品九九久久| 成年在线电影| 日韩欧美www| 青青视频在线免费观看| 亚洲三级视频在线观看| 99久久国产精| 乱一区二区av| 免费av手机在线观看| 日本一区二区在线看| 国产精品.com| 欧美高清xxx| 国模视频一区二区| 黄色在线视频网站| 精品亚洲一区二区三区四区五区 | 成人影音在线| 中日韩午夜理伦电影免费 | 精品视频久久久久| 欧美国产视频在线| av网页在线观看| 九九视频精品免费| 国产主播在线看| 欧美jizzhd精品欧美巨大免费| 欧美日韩在线一二三| 日韩免费高清视频网站| 国产精品成人一区二区三区吃奶| 国产盗摄精品一区二区酒店| 日韩中文字幕国产| 日韩偷拍自拍| 亚洲精品一区二区三区在线观看 | 欧美精品18+| 丰满人妻老熟妇伦人精品| 一区二区成人在线| 成人黄色短视频| 久久久91精品国产一区二区精品 | 亚洲 欧美 综合 另类 中字| 日韩一级毛片| 欧美日韩在线不卡一区| 久草视频中文在线| 日韩精品人妻中文字幕| 国产美女av一区二区三区| 日本在线视频www| 亚洲激情精品| 成人网站免费观看入口| 在线中文字幕第一区| 亚洲二区三区四区| 欧美日韩第一| 欧美精品免费观看二区| 美女视频亚洲色图| 国产精品亚洲不卡a| 欧美日韩午夜电影网| 91精品久久久久久久久不口人| 少妇一区视频| 日韩av电影在线播放| 蜜桃麻豆影像在线观看| 久久久久久久久久久免费精品| 午夜羞羞小视频在线观看| 久久夜色撩人精品| 国产精品剧情| 久久精品久久久久久| 成人video亚洲精品| 久久久91精品国产| 3d玉蒲团在线观看| 欧美日韩国产第一页| 欧美xxxx免费虐| 国内精品在线一区| 国产无遮挡裸体视频在线观看| 97视频网站入口| 亚洲天堂资源| 日本亚洲精品在线观看| 日韩电影大全网站| 国产精品综合久久久| 久久影视精品| 91在线免费看网站| 一区二区精彩视频| 精品国产乱码久久久久软件 | 欧美视频一区二区在线观看| 国产日韩在线免费观看| 欧美日韩专区在线| av免费观看网址| 欧美成人性福生活免费看| 亚洲精品成人区在线观看| 亚洲精品成人免费| 久久久久久青草| 精品国产自在精品国产浪潮| 国内外激情在线| 久久久久久久久久久久av| 秋霞伦理一区| 国产精品久久久久久久久免费看 | 99热免费精品在线观看| 久久精品免费一区二区| 免播放器亚洲一区| 少妇精品无码一区二区| 91丨九色丨黑人外教| 亚洲无人区码一码二码三码的含义| 国产精品久久福利| 免费观看一级视频| 色综合天天狠狠| 国产露脸91国语对白| 亚洲精品一线二线三线| 99se视频在线观看| 久久久久久久久亚洲| 日韩欧美一区二区三区免费观看| 成人黄色短视频在线观看| 国产欧美自拍一区| 亚洲精品久久久久久一区二区| 欧美黄在线观看| 日韩av一二三四| 国产成人鲁色资源国产91色综| 人妻丰满熟妇av无码久久洗澡| 国产精品―色哟哟| 久久久久无码国产精品| 91福利精品视频| 丰满少妇在线观看bd| 中文字幕日韩视频| 九色porny丨首页入口在线| 国产日韩av高清| 亚洲精品进入| wwwjizzjizzcom| 日本不卡一区二区三区高清视频| www日本在线观看| 国产精品久久久久久久久果冻传媒 | www国产成人| 欧美日韩综合一区二区| 在线看不卡av| 天天摸天天碰天天爽天天弄| 久久亚洲成人精品| 九九九伊在线综合永久| 国产精品一 二 三| 欧美国产三区| 色噜噜狠狠一区二区三区狼国成人| 久久这里只有精品6| 久久精品国产亚洲AV无码麻豆| 欧美日韩一区中文字幕| 欧美捆绑视频| 隔壁老王国产在线精品| 国产麻豆精品| 在线看视频不卡| 日本系列欧美系列| 亚洲综合自拍网| 亚洲午夜私人影院| h狠狠躁死你h高h| 久久精品在线播放| 亚洲毛片在线免费| 亚洲精品二区| 麻豆精品国产传媒mv男同 | 中文字幕一区二区三区蜜月 | 久久福利精品| 西西大胆午夜视频| 午夜精品视频在线观看| 国产成人三级在线观看视频| 免费不卡欧美自拍视频| 日本久久久久| 在线不卡视频一区二区| 蜜臀av一区二区| 伊人影院综合网| 欧美系列在线观看| 91在线播放网站| 国产精品永久免费| 999久久久国产精品| 在线黄色免费看| 自拍偷拍欧美激情| 国产情侣激情自拍| 久久综合电影一区| 欧美电影院免费观看| 国产日韩欧美大片| 国产成人av影院| 国产一级在线免费观看| 亚洲第一精品电影| 手机在线观看av网站| 蜜桃视频在线观看91| 久久久久.com| 美女100%露胸无遮挡| 欧美精三区欧美精三区| 精品国产丝袜高跟鞋| av一区二区三区在线观看| 国内精品久久久久久久97牛牛| 中文字幕一区三区久久女搜查官| 黄色精品在线看| youjizz在线播放| 成人精品一区二区三区电影免费| 天天射天天综合网| 中文字幕在线播放一区二区| 精品国产91久久久久久| 黄色软件在线| 91精品视频免费| 日韩午夜黄色| 亚洲精品一区二区三区影院忠贞| 欧美日韩在线直播| 草莓福利社区在线| 精品一区二区久久久久久久网站| 久久激情综合| 国产日产精品一区二区三区的介绍| 日韩欧美一二三区| 一本大道色婷婷在线| 亚洲欧洲久久| 粉嫩aⅴ一区二区三区四区| 青草视频在线观看免费| 深夜福利亚洲导航| 国产精品任我爽爆在线播放| 久久久久久久久久福利| 最好看的中文字幕久久| 五月婷婷六月激情| 国产精品香蕉在线观看| 好吊日精品视频| 99精品全国免费观看| 欧美第一区第二区| 先锋欧美三级| 男人天堂新网址| 欧美国产日韩亚洲一区| 动漫av一区二区三区| 国产精品免费视频xxxx| 中文精品在线| 三级在线观看免费大全|