日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

深入理解JavaScript系列(18):面向对象编程之ECMAScript实现

發布時間:2024/4/15 javascript 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解JavaScript系列(18):面向对象编程之ECMAScript实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://www.cnblogs.com/TomXu/archive/2012/02/06/2330609.html

介紹

本章是關于ECMAScript面向對象實現的第2篇,第1篇我們討論的是概論和CEMAScript的比較,如果你還沒有讀第1篇,在進行本章之前,我強烈建議你先讀一下第1篇,因為本篇實在太長了(35頁)。

英文原文:http://dmitrysoshnikov.com/ecmascript/chapter-7-2-oop-ecmascript-implementation/

注:由于篇幅太長了,難免出現錯誤,時刻保持修正中。

在概論里,我們延伸到了ECMAScript,現在,當我們知道它OOP實現時,我們再來準確定義一下:

ECMAScript is an object-oriented programming language supporting delegating inheritance based on prototypes. ECMAScript是一種面向對象語言,支持基于原型的委托式繼承。

我們將從最基本的數據類型來分析,首先要了解的是ECMAScript用原始值(primitive values)和對象(objects)來區分實體,因此有些文章里說的“在JavaScript里,一切都是對象”是錯誤的(不完全對),原始值就是我們這里要討論的一些數據類型。

數據類型

雖然ECMAScript是可以動態轉化類型的動態弱類型語言,它還是有數據類型的。也就是說,一個對象要屬于一個實實在在的類型。 標準規范里定義了9種數據類型,但只有6種是在ECMAScript程序里可以直接訪問的,它們是:Undefined、Null、Boolean、String、Number、Object。

另外3種類型只能在實現級別訪問(ECMAScript對象是不能使用這些類型的)并用于規范來解釋一些操作行為、保存中間值。這3種類型是:Reference、List和Completion。

因此,Reference是用來解釋delete、typeof、this這樣的操作符,并且包含一個基對象和一個屬性名稱;List描述的是參數列表的行為(在new表達式和函數調用的時候);Completion是用來解釋行為break、continue、return和throw語句的。

原始值類型

回頭來看6中用于ECMAScript程序的數據類型,前5種是原始值類型,包括Undefined、Null、Boolean、String、Number、Object。 原始值類型例子:

var a = undefined; var b = null; var c = true; var d = 'test'; var e = 10;

這些值是在底層上直接實現的,他們不是object,所以沒有原型,沒有構造函數。

大叔注:這些原生值和我們平時用的(Boolean、String、Number、Object)雖然名字上相似,但不是同一個東西。所以typeof(true)和typeof(Boolean)結果是不一樣的,因為typeof(Boolean)的結果是function,所以函數Boolean、String、Number是有原型的(下面的讀寫屬性章節也會提到)。

想知道數據是哪種類型用typeof是最好不過了,有個例子需要注意一下,如果用typeof來判斷null的類型,結果是object,為什么呢?因為null的類型是定義為Null的。

alert(typeof null); // "object"

顯示"object"原因是因為規范就是這么規定的:對于Null值的typeof字符串值返回"object“。

規范沒有想象解釋這個,但是Brendan Eich (JavaScript發明人)注意到null相對于undefined大多數都是用于對象出現的地方,例如設置一個對象為空引用。但是有些文檔里有些氣人將之歸結為bug,而且將該bug放在Brendan Eich也參與討論的bug列表里,結果就是任其自然,還是把typeof null的結果設置為object(盡管262-3的標準是定義null的類型是Null,262-5已經將標準修改為null的類型是object了)。

Object類型

接著,Object類型(不要和Object構造函數混淆了,現在只討論抽象類型)是描述 ECMAScript對象的唯一一個數據類型。

Object is an unordered collection of key-value pairs. 對象是一個包含key-value對的無序集合

對象的key值被稱為屬性,屬性是原始值和其他對象的容器。如果屬性的值是函數我們稱它為方法 。

例如:

var x = { // 對象"x"有3個屬性: a, b, c a: 10, // 原始值 b: {z: 100}, // 對象"b"有一個屬性z c: function () { // 函數(方法) alert('method x.c'); } }; alert(x.a); // 10alert(x.b); // [object Object]alert(x.b.z); // 100x.c(); // 'method x.c'

動態性

正如我們在第17章中指出的,ES中的對象是完全動態的。這意味著,在程序執行的時候我們可以任意地添加,修改或刪除對象的屬性。

例如:

var foo = {x: 10}; // 添加新屬性foo.y = 20; console.log(foo); // {x: 10, y: 20} // 將屬性值修改為函數foo.x = function () { console.log('foo.x'); }; foo.x(); // 'foo.x' // 刪除屬性delete foo.x; console.log(foo); // {y: 20}

有些屬性不能被修改——(只讀屬性、已刪除屬性或不可配置的屬性)。 我們將稍后在屬性特性里講解。

另外,ES5規范規定,靜態對象不能擴展新的屬性,并且它的屬性頁不能刪除或者修改。他們是所謂的凍結對象,可以通過應用Object.freeze(o)方法得到。

var foo = {x: 10}; // 凍結對象Object.freeze(foo); console.log(Object.isFrozen(foo)); // true // 不能修改foo.x = 100; // 不能擴展foo.y = 200; // 不能刪除delete foo.x; console.log(foo); // {x: 10}

在ES5規范里,也使用Object.preventExtensions(o)方法防止擴展,或者使用Object.defineProperty(o)方法來定義屬性:

var foo = {x : 10}; Object.defineProperty(foo, "y", { value: 20, writable: false, // 只讀 configurable: false // 不可配置}); // 不能修改foo.y = 200; // 不能刪除delete foo.y; // false // 防治擴展Object.preventExtensions(foo); console.log(Object.isExtensible(foo)); // false // 不能添加新屬性foo.z = 30; console.log(foo); {x: 10, y: 20}

內置對象、原生對象及宿主對象

有必要需要注意的是規范還區分了這內置對象、元素對象和宿主對象。

內置對象和元素對象是被ECMAScript規范定義和實現的,兩者之間的差異微不足道。所有ECMAScript實現的對象都是原生對象(其中一些是內置對象、一些在程序執行的時候創建,例如用戶自定義對象)。內置對象是原生對象的一個子集、是在程序開始之前內置到ECMAScript里的(例如,parseInt, Match等)。所有的宿主對象是由宿主環境提供的,通常是瀏覽器,并可能包括如window、alert等。

注意,宿主對象可能是ES自身實現的,完全符合規范的語義。從這點來說,他們能稱為“原生宿主”對象(盡快很理論),不過規范沒有定義“原生宿主”對象的概念。

Boolean,String和Number對象

另外,規范也定義了一些原生的特殊包裝類,這些對象是:

  • 布爾對象
  • 字符串對象
  • 數字對象
  • 這些對象的創建,是通過相應的內置構造器創建,并且包含原生值作為其內部屬性,這些對象可以轉換省原始值,反之亦然。

    var c = new Boolean(true); var d = new String('test'); var e = new Number(10); // 轉換成原始值 // 使用不帶new關鍵字的函數с = Boolean(c); d = String(d); e = Number(e); // 重新轉換成對象с = Object(c); d = Object(d); e = Object(e);

    此外,也有對象是由特殊的內置構造函數創建: Function(函數對象構造器)、Array(數組構造器) RegExp(正則表達式構造器)、Math(數學模塊)、 Date(日期的構造器)等等,這些對象也是Object對象類型的值,他們彼此的區別是由內部屬性管理的,我們在下面討論這些內容。

    字面量Literal

    對于三個對象的值:對象(object),數組(array)和正則表達式(regular expression),他們分別有簡寫的標示符稱為:對象初始化器、數組初始化器、和正則表達式初始化器:

    // 等價于new Array(1, 2, 3); // 或者array = new Array(); // array[0] = 1; // array[1] = 2; // array[2] = 3;var array = [1, 2, 3]; // 等價于 // var object = new Object(); // object.a = 1; // object.b = 2; // object.c = 3;var object = {a: 1, b: 2, c: 3}; // 等價于new RegExp("^\\d+$", "g")var re = /^\d+$/g;

    注意,如果上述三個對象進行重新賦值名稱到新的類型上的話,那隨后的實現語義就是按照新賦值的類型來使用,例如在當前的Rhino和老版本SpiderMonkey 1.7的實現上,會成功以new關鍵字的構造器來創建對象,但有些實現(當前Spider/TraceMonkey)字面量的語義在類型改變以后卻不一定改變。

    var getClass = Object.prototype.toString; Object = Number; var foo = new Object; alert([foo, getClass.call(foo)]); // 0, "[object Number]" var bar = {}; // Rhino, SpiderMonkey 1.7中 - 0, "[object Number]" // 其它: still "[object Object]", "[object Object]"alert([bar, getClass.call(bar)]); // Array也是一樣的效果Array = Number; foo = new Array; alert([foo, getClass.call(foo)]); // 0, "[object Number]" bar = []; // Rhino, SpiderMonkey 1.7中 - 0, "[object Number]" // 其它: still "", "[object Object]"alert([bar, getClass.call(bar)]); // 但對RegExp,字面量的語義是不被改變的。 semantics of the literal // isn't being changed in all tested implementations RegExp = Number; foo = new RegExp; alert([foo, getClass.call(foo)]); // 0, "[object Number]" bar = /(?!)/g; alert([bar, getClass.call(bar)]); // /(?!)/g, "[object RegExp]"

    正則表達式字面量和RegExp對象

    注意,下面2個例子在第三版的規范里,正則表達式的語義都是等價的,regexp字面量只在一句里存在,并且再解析階段創建,但RegExp構造器創建的卻是新對象,所以這可能會導致出一些問題,如lastIndex的值在測試的時候結果是錯誤的:

    for (var k = 0; k < 4; k++) { var re = /ecma/g; alert(re.lastIndex); // 0, 4, 0, 4 alert(re.test("ecmascript")); // true, false, true, false} // 對比 for (var k = 0; k < 4; k++) { var re = new RegExp("ecma", "g"); alert(re.lastIndex); // 0, 0, 0, 0 alert(re.test("ecmascript")); // true, true, true, true}

    注:不過這些問題在第5版的ES規范都已經修正了,不管是基于字面量的還是構造器的,正則都是創建新對象

    關聯數組

    各種文字靜態討論,JavaScript對象(經常是用對象初始化器{}來創建)被稱為哈希表哈希表或其它簡單的稱謂:哈希(Ruby或Perl里的概念), 管理數組(PHP里的概念),詞典 (Python里的概念)等。

    只有這樣的術語,主要是因為他們的結構都是相似的,就是使用“鍵-值”對來存儲對象,完全符合“關聯數組 ”或“哈希表 ”理論定義的數據結構。 此外,哈希表抽象數據類型通常是在實現層面使用。

    但是,盡管術語上來描述這個概念,但實際上這個是錯誤,從ECMAScript來看:ECMAScript只有一個對象以及類型以及它的子類型,這和“鍵-值”對存儲沒有什么區別,因此在這上面沒有特別的概念。 因為任何對象的內部屬性都可以存儲為鍵-值”對:

    var a = {x: 10}; a['y'] = 20; a.z = 30; var b = new Number(1); b.x = 10; b.y = 20; b['z'] = 30; var c = new Function(''); c.x = 10; c.y = 20; c['z'] = 30; // 等等,任意對象的子類型"subtype"

    此外,由于在ECMAScript中對象可以是空的,所以"hash"的概念在這里也是不正確的:

    Object.prototype.x = 10; var a = {}; // 創建空"hash" alert(a["x"]); // 10, 但不為空alert(a.toString); // function a["y"] = 20; // 添加新的鍵值對到 "hash"alert(a["y"]); // 20 Object.prototype.y = 20; // 添加原型屬性 delete a["y"]; // 刪除alert(a["y"]); // 但這里key和value依然有值 – 20

    請注意, ES5標準可以讓我們創建沒原型的對象(使用Object.create(null)方法實現)對,從這個角度來說,這樣的對象可以稱之為哈希表:

    var aHashTable = Object.create(null); console.log(aHashTable.toString); // 未定義

    此外,一些屬性有特定的getter / setter方法,所以也可能導致混淆這個概念:

    var a = new String("foo"); a['length'] = 10; alert(a['length']); // 3

    然而,即使認為“哈希”可能有一個“原型”(例如,在Ruby或Python里委托哈希對象的類),在ECMAScript里,這個術語也是不對的,因為2個表示法之間沒有語義上的區別(即用點表示法a.b和a["b"]表示法)。

    在ECMAScript中的“property屬性”的概念語義上和"key"、數組索引、方法沒有分開的,這里所有對象的屬性讀寫都要遵循統一的規則:檢查原型鏈。

    在下面Ruby的例子中,我們可以看到語義上的區別:

    a = {} a.class # Hash a.length # 0 # new "key-value" paira['length'] = 10; # 語義上,用點訪問的是屬性或方法,而不是key a.length # 1 # 而索引器訪問訪問的是hash里的key a['length'] # 10 # 就類似于在現有對象上動態聲明Hash類 # 然后聲明新屬性或方法 class Hash def z 100 end end # 新屬性可以訪問 a.z # 100 # 但不是"key" a['z'] # nil

    ECMA-262-3標準并沒有定義“哈希”(以及類似)的概念。但是,有這樣的結構理論的話,那可能以此命名的對象。

    對象轉換

    將對象轉化成原始值可以用valueOf方法,正如我們所說的,當函數的構造函數調用做為function(對于某些類型的),但如果不用new關鍵字就是將對象轉化成原始值,就相當于隱式的valueOf方法調用:

    var a = new Number(1); var primitiveA = Number(a); // 隱式"valueOf"調用var alsoPrimitiveA = a.valueOf(); // 顯式調用 alert([ typeof a, // "object" typeof primitiveA, // "number" typeof alsoPrimitiveA // "number"]);

    這種方式允許對象參與各種操作,例如:

    var a = new Number(1); var b = new Number(2); alert(a + b); // 3 // 甚至 var c = { x: 10, y: 20, valueOf: function () { return this.x + this.y; } }; var d = { x: 30, y: 40, // 和c的valueOf功能一樣 valueOf: c.valueOf }; alert(c + d); // 100

    valueOf的默認值會根據根據對象的類型改變(如果不被覆蓋的話),對某些對象,他返回的是this——例如:Object.prototype.valueOf(),還有計算型的值:Date.prototype.valueOf()返回的是日期時間:

    var a = {}; alert(a.valueOf() === a); // true, "valueOf"返回this var d = new Date(); alert(d.valueOf()); // timealert(d.valueOf() === d.getTime()); // true

    此外,對象還有一個更原始的代表性——字符串展示。 這個toString方法是可靠的,它在某些操作上是自動使用的:

    var a = { valueOf: function () { return 100; }, toString: function () { return '__test'; } }; // 這個操作里,toString方法自動調用alert(a); // "__test" // 但是這里,調用的卻是valueOf()方法alert(a + 10); // 110 // 但,一旦valueOf刪除以后 // toString又可以自動調用了delete a.valueOf; alert(a + 10); // "_test10"

    Object.prototype上定義的toString方法具有特殊意義,它返回的我們下面將要討論的內部[[Class]]屬性值。

    和轉化成原始值(ToPrimitive)相比,將值轉化成對象類型也有一個轉化規范(ToObject)。

    一個顯式方法是使用內置的Object構造函數作為function來調用ToObject(有些類似通過new關鍵字也可以):

    var n = Object(1); // [object Number]var s = Object('test'); // [object String] // 一些類似,使用new操作符也可以var b = new Object(true); // [object Boolean] // 應用參數new Object的話創建的是簡單對象var o = new Object(); // [object Object] // 如果參數是一個現有的對象 // 那創建的結果就是簡單返回該對象var a = []; alert(a === new Object(a)); // truealert(a === Object(a)); // true

    關于調用內置構造函數,使用還是不適用new操作符沒有通用規則,取決于構造函數。 例如Array或Function當使用new操作符的構造函數或者不使用new操作符的簡單函數使用產生相同的結果的:

    var a = Array(1, 2, 3); // [object Array]var b = new Array(1, 2, 3); // [object Array]var c = [1, 2, 3]; // [object Array] var d = Function(''); // [object Function]var e = new Function(''); // [object Function]

    有些操作符使用的時候,也有一些顯示和隱式轉化:

    var a = 1; var b = 2; // 隱式var c = a + b; // 3, numbervar d = a + b + '5' // "35", string // 顯式var e = '10'; // "10", stringvar f = +e; // 10, numbervar g = parseInt(e, 10); // 10, number // 等等

    屬性的特性

    所有的屬性(property) 都可以有很多特性(attributes)。

  • {ReadOnly}——忽略向屬性賦值的寫操作嘗,但只讀屬性可以由宿主環境行為改變——也就是說不是“恒定值” ;
  • {DontEnum}——屬性不能被for..in循環枚舉
  • {DontDelete}——糊了delete操作符的行為被忽略(即刪不掉);
  • {Internal}——內部屬性,沒有名字(僅在實現層面使用),ECMAScript里無法訪問這樣的屬性。
  • 注意,在ES5里{ReadOnly},{DontEnum}和{DontDelete}被重新命名為[[Writable]],[[Enumerable]]和[[Configurable]],可以手工通過Object.defineProperty或類似的方法來管理這些屬性。

    ?

    var foo = {}; Object.defineProperty(foo, "x", { value: 10, writable: true, // 即{ReadOnly} = false enumerable: false, // 即{DontEnum} = true configurable: true // 即{DontDelete} = false}); console.log(foo.x); // 10 // 通過descriptor獲取特性集attributesvar desc = Object.getOwnPropertyDescriptor(foo, "x"); console.log(desc.enumerable); // falseconsole.log(desc.writable); // true // 等等

    內部屬性和方法

    對象也可以有內部屬性(實現層面的一部分),并且ECMAScript程序無法直接訪問(但是下面我們將看到,一些實現允許訪問一些這樣的屬性)。 這些屬性通過嵌套的中括號[[ ]]進行訪問。我們來看其中的一些,這些屬性的描述可以到規范里查閱到。

    每個對象都應該實現如下內部屬性和方法:

  • [[Prototype]]——對象的原型(將在下面詳細介紹)
  • [[Class]]——字符串對象的一種表示(例如,Object Array ,Function Object,Function等);用來區分對象
  • [[Get]]——獲得屬性值的方法
  • [[Put]]——設置屬性值的方法
  • [[CanPut]]——檢查屬性是否可寫
  • [[HasProperty]]——檢查對象是否已經擁有該屬性
  • [[Delete]]——從對象刪除該屬性
  • [[DefaultValue]]返回對象對于的原始值(調用valueOf方法,某些對象可能會拋出TypeError異常)。
  • 通過Object.prototype.toString()方法可以間接得到內部屬性[[Class]]的值,該方法應該返回下列字符串: "[object " + [[Class]] + "]" 。例如:

    var getClass = Object.prototype.toString; getClass.call({}); // [object Object]getClass.call([]); // [object Array]getClass.call(new Number(1)); // [object Number] // 等等

    這個功能通常是用來檢查對象用的,但規范上說宿主對象的[[Class]]可以為任意值,包括內置對象的[[Class]]屬性的值,所以理論上來看是不能100%來保證準確的。例如,document.childNodes.item(...)方法的[[Class]]屬性,在IE里返回"String",但其它實現里返回的確實"Function"。

    // in IE - "String", in other - "Function"alert(getClass.call(document.childNodes.item));

    構造函數

    因此,正如我們上面提到的,在ECMAScript中的對象是通過所謂的構造函數來創建的。

    Constructor is a function that creates and initializes the newly created object. 構造函數是一個函數,用來創建并初始化新創建的對象。

    對象創建(內存分配)是由構造函數的內部方法[[Construct]]負責的。該內部方法的行為是定義好的,所有的構造函數都是使用該方法來為新對象分配內存的。

    而初始化是通過新建對象上下上調用該函數來管理的,這是由構造函數的內部方法[[Call]]來負責任的。

    注意,用戶代碼只能在初始化階段訪問,雖然在初始化階段我們可以返回不同的對象(忽略第一階段創建的tihs對象):

    function A() { // 更新新創建的對象 this.x = 10; // 但返回的是不同的對象 return [1, 2, 3]; } var a = new A(); console.log(a.x, a); undefined, [1, 2, 3]

    引用15章函數——創建函數的算法小節,我們可以看到該函數是一個原生對象,包含[[Construct]] ]和[[Call]] ]屬性以及顯示的prototype原型屬性——未來對象的原型(注:NativeObject是對于native object原生對象的約定,在下面的偽代碼中使用)。

    F = new NativeObject(); F.[[Class]] = "Function" .... // 其它屬性 F.[[Call]] = <reference to function> // function自身 F.[[Construct]] = internalConstructor // 普通的內部構造函數 .... // 其它屬性 // F構造函數創建的對象原型__objectPrototype = {}; __objectPrototype.constructor = F // {DontEnum}F.prototype = __objectPrototype

    [[Call]] ]是除[[Class]]屬性(這里等同于"Function" )之外區分對象的主要方式,因此,對象的內部[[Call]]屬性作為函數調用。 這樣的對象用typeof運算操作符的話返回的是"function"。然而它主要是和原生對象有關,有些情況的實現在用typeof獲取值的是不一樣的,例如:window.alert (...)在IE中的效果:

    // IE瀏覽器中 - "Object", "object", 其它瀏覽器 - "Function", "function"alert(Object.prototype.toString.call(window.alert)); alert(typeof window.alert); // "Object"

    內部方法[[Construct]]是通過使用帶new運算符的構造函數來激活的,正如我們所說的這個方法是負責內存分配和對象創建的。如果沒有參數,調用構造函數的括號也可以省略:

    function A(x) { // constructor А this.x = x || 10; } // 不傳參數的話,括號也可以省略var a = new A; // or new A();alert(a.x); // 10 // 顯式傳入參數xvar b = new A(20); alert(b.x); // 20

    我們也知道,構造函數(初始化階段)里的shis被設置為新創建的對象 。

    讓我們研究一下對象創建的算法。

    對象創建的算法

    內部方法[[Construct]] 的行為可以描述成如下:

    F.[[Construct]](initialParameters): O = new NativeObject(); // 屬性[[Class]]被設置為"Object"O.[[Class]] = "Object" // 引用F.prototype的時候獲取該對象gvar __objectPrototype = F.prototype; // 如果__objectPrototype是對象,就:O.[[Prototype]] = __objectPrototype // 否則:O.[[Prototype]] = Object.prototype; // 這里O.[[Prototype]]是Object對象的原型 // 新創建對象初始化的時候應用了F.[[Call]] // 將this設置為新創建的對象O // 參數和F里的initialParameters是一樣的R = F.[[Call]](initialParameters); this === O; // 這里R是[[Call]]的返回值 // 在JS里看,像這樣: // R = F.apply(O, initialParameters); // 如果R是對象return R // 否則return O

    請注意兩個主要特點:

  • 首先,新創建對象的原型是從當前時刻函數的prototype屬性獲取的(這意味著同一個構造函數創建的兩個創建對象的原型可以不同是因為函數的prototype屬性也可以不同)。
  • 其次,正如我們上面提到的,如果在對象初始化的時候,[[Call]]返回的是對象,這恰恰是用于整個new操作符的結果:
  • function A() {} A.prototype.x = 10; var a = new A(); alert(a.x); // 10 – 從原型上得到 // 設置.prototype屬性為新對象 // 為什么顯式聲明.constructor屬性將在下面說明A.prototype = { constructor: A, y: 100 }; var b = new A(); // 對象"b"有了新屬性alert(b.x); // undefinedalert(b.y); // 100 – 從原型上得到 // 但a對象的原型依然可以得到原來的結果alert(a.x); // 10 - 從原型上得到 function B() { this.x = 10; return new Array(); } // 如果"B"構造函數沒有返回(或返回this) // 那么this對象就可以使用,但是下面的情況返回的是arrayvar b = new B(); alert(b.x); // undefinedalert(Object.prototype.toString.call(b)); // [object Array]

    讓我們來詳細了解一下原型

    原型

    每個對象都有一個原型(一些系統對象除外)。原型通信是通過內部的、隱式的、不可直接訪問[[Prototype]]原型屬性來進行的,原型可以是一個對象,也可以是null值。

    屬性構造函數(Property constructor)

    上面的例子有有2個重要的知識點,第一個是關于函數的constructor屬性的prototype屬性,在函數創建的算法里,我們知道constructor屬性在函數創建階段被設置為函數的prototype屬性,constructor屬性的值是函數自身的重要引用:

    function A() {} var a = new A(); alert(a.constructor); // function A() {}, by delegationalert(a.constructor === A); // true

    通常在這種情況下,存在著一個誤區:constructor構造屬性作為新創建對象自身的屬性是錯誤的,但是,正如我們所看到的的,這個屬性屬于原型并且通過繼承來訪問對象。

    通過繼承constructor屬性的實例,可以間接得到的原型對象的引用:

    function A() {} A.prototype.x = new Number(10); var a = new A(); alert(a.constructor.prototype); // [object Object] alert(a.x); // 10, 通過原型 // 和a.[[Prototype]].x效果一樣alert(a.constructor.prototype.x); // 10 alert(a.constructor.prototype.x === a.x); // true

    但請注意,函數的constructor和prototype屬性在對象創建以后都可以重新定義的。在這種情況下,對象失去上面所說的機制。如果通過函數的prototype屬性去編輯元素的prototype原型的話(添加新對象或修改現有對象),實例上將看到新添加的屬性。

    然而,如果我們徹底改變函數的prototype屬性(通過分配一個新的對象),那原始構造函數的引用就是丟失,這是因為我們創建的對象不包括constructor屬性:

    function A() {} A.prototype = { x: 10 }; var a = new A(); alert(a.x); // 10alert(a.constructor === A); // false!

    因此,對函數的原型引用需要手工恢復:

    function A() {} A.prototype = { constructor: A, x: 10 }; var a = new A(); alert(a.x); // 10alert(a.constructor === A); // true

    注意雖然手動恢復了constructor屬性,和原來丟失的原型相比,{DontEnum}特性沒有了,也就是說A.prototype里的for..in循環語句不支持了,不過第5版規范里,通過[[Enumerable]] 特性提供了控制可枚舉狀態enumerable的能力。

    var foo = {x: 10}; Object.defineProperty(foo, "y", { value: 20, enumerable: false // aka {DontEnum} = true}); console.log(foo.x, foo.y); // 10, 20 for (var k in foo) { console.log(k); // only "x"} var xDesc = Object.getOwnPropertyDescriptor(foo, "x"); var yDesc = Object.getOwnPropertyDescriptor(foo, "y"); console.log( xDesc.enumerable, // true yDesc.enumerable // false);

    顯式prototype和隱式[[Prototype]]屬性

    通常,一個對象的原型通過函數的prototype屬性顯式引用是不正確的,他引用的是同一個對象,對象的[[Prototype]]屬性:

    a.[[Prototype]] ----> Prototype <---- A.prototype

    此外, 實例的[[Prototype]]值確實是在構造函數的prototype屬性上獲取的。

    然而,提交prototype屬性不會影響已經創建對象的原型(只有在構造函數的prototype屬性改變的時候才會影響到),就是說新創建的對象才有有新的原型,而已創建對象還是引用到原來的舊原型(這個原型已經不能被再被修改了)。

    // 在修改A.prototype原型之前的情況a.[[Prototype]] ----> Prototype <---- A.prototype // 修改之后A.prototype ----> New prototype // 新對象會擁有這個原型a.[[Prototype]] ----> Prototype // 引導的原來的原型上

    例如:

    function A() {} A.prototype.x = 10; var a = new A(); alert(a.x); // 10 A.prototype = { constructor: A, x: 20 y: 30 }; // 對象a是通過隱式的[[Prototype]]引用從原油的prototype上獲取的值alert(a.x); // 10alert(a.y) // undefined var b = new A(); // 但新對象是從新原型上獲取的值alert(b.x); // 20alert(b.y) // 30

    因此,有的文章說“動態修改原型將影響所有的對象都會擁有新的原型”是錯誤的,新原型僅僅在原型修改以后的新創建對象上生效。

    這里的主要規則是:對象的原型是對象的創建的時候創建的,并且在此之后不能修改為新的對象,如果依然引用到同一個對象,可以通過構造函數的顯式prototype引用,對象創建以后,只能對原型的屬性進行添加或修改。

    非標準的__proto__屬性

    然而,有些實現(例如SpiderMonkey),提供了不標準的__proto__顯式屬性來引用對象的原型:

    function A() {} A.prototype.x = 10; var a = new A(); alert(a.x); // 10 var __newPrototype = { constructor: A, x: 20, y: 30 }; // 引用到新對象A.prototype = __newPrototype; var b = new A(); alert(b.x); // 20alert(b.y); // 30 // "a"對象使用的依然是舊的原型alert(a.x); // 10alert(a.y); // undefined // 顯式修改原型a.__proto__ = __newPrototype; // 現在"а"對象引用的是新對象alert(a.x); // 20alert(a.y); // 30

    注意,ES5提供了Object.getPrototypeOf(O)方法,該方法直接返回對象的[[Prototype]]屬性——實例的初始原型。 然而,和__proto__相比,它只是getter,它不允許set值。

    var foo = {}; Object.getPrototypeOf(foo) == Object.prototype; // true

    對象獨立于構造函數

    因為實例的原型獨立于構造函數和構造函數的prototype屬性,構造函數完成了自己的主要工作(創建對象)以后可以刪除。原型對象通過引用[[Prototype]]屬性繼續存在:

    function A() {} A.prototype.x = 10; var a = new A(); alert(a.x); // 10 // 設置A為null - 顯示引用構造函數A = null; // 但如果.constructor屬性沒有改變的話, // 依然可以通過它創建對象var b = new a.constructor(); alert(b.x); // 10 // 隱式的引用也刪除掉delete a.constructor.prototype.constructor; delete b.constructor.prototype.constructor; // 通過A的構造函數再也不能創建對象了 // 但這2個對象依然有自己的原型alert(a.x); // 10alert(b.x); // 10

    instanceof操作符的特性

    我們是通過構造函數的prototype屬性來顯示引用原型的,這和instanceof操作符有關。該操作符是和原型鏈一起工作的,而不是構造函數,考慮到這一點,當檢測對象的時候往往會有誤解:

    if (foo instanceof Foo) { ... }

    這不是用來檢測對象foo是否是用Foo構造函數創建的,所有instanceof運算符只需要一個對象屬性——foo.[[Prototype]],在原型鏈中從Foo.prototype開始檢查其是否存在。instanceof運算符是通過構造函數里的內部方法[[HasInstance]]來激活的。

    讓我們來看看這個例子:

    function A() {} A.prototype.x = 10; var a = new A(); alert(a.x); // 10 alert(a instanceof A); // true // 如果設置原型為nullA.prototype = null; // ..."a"依然可以通過a.[[Prototype]]訪問原型alert(a.x); // 10 // 不過,instanceof操作符不能再正常使用了 // 因為它是從構造函數的prototype屬性來實現的alert(a instanceof A); // 錯誤,A.prototype不是對象

    另一方面,可以由構造函數來創建對象,但如果對象的[[Prototype]]屬性和構造函數的prototype屬性的值設置的是一樣的話,instanceof檢查的時候會返回true:

    function B() {} var b = new B(); alert(b instanceof B); // true function C() {} var __proto = { constructor: C }; C.prototype = __proto; b.__proto__ = __proto; alert(b instanceof C); // truealert(b instanceof B); // false

    原型可以存放方法并共享屬性

    大部分程序里使用原型是用來存儲對象的方法、默認狀態和共享對象的屬性。

    事實上,對象可以擁有自己的狀態 ,但方法通常是一樣的。 因此,為了內存優化,方法通常是在原型里定義的。 這意味著,這個構造函數創建的所有實例都可以共享找個方法。

    function A(x) { this.x = x || 100; } A.prototype = (function () { // 初始化上下文 // 使用額外的對象 var _someSharedVar = 500; function _someHelper() { alert('internal helper: ' + _someSharedVar); } function method1() { alert('method1: ' + this.x); } function method2() { alert('method2: ' + this.x); _someHelper(); } // 原型自身 return { constructor: A, method1: method1, method2: method2 }; })(); var a = new A(10); var b = new A(20); a.method1(); // method1: 10a.method2(); // method2: 10, internal helper: 500 b.method1(); // method1: 20b.method2(); // method2: 20, internal helper: 500 // 2個對象使用的是原型里相同的方法alert(a.method1 === b.method1); // truealert(a.method2 === b.method2); // true

    讀寫屬性

    正如我們提到,讀取和寫入屬性值是通過內部的[[Get]]和[[Put]]方法。這些內部方法是通過屬性訪問器激活的:點標記法或者索引標記法:

    // 寫入foo.bar = 10; // 調用了[[Put]] console.log(foo.bar); // 10, 調用了[[Get]]console.log(foo['bar']); // 效果一樣

    讓我們用偽代碼來看一下這些方法是如何工作的:

    [[Get]]方法

    [[Get]]也會從原型鏈中查詢屬性,所以通過對象也可以訪問原型中的屬性。

    O.[[Get]](P): // 如果是自己的屬性,就返回if (O.hasOwnProperty(P)) { return O.P; } // 否則,繼續分析原型var __proto = O.[[Prototype]]; // 如果原型是null,返回undefined // 這是可能的:最頂層Object.prototype.[[Prototype]]是nullif (__proto === null) { return undefined; } // 否則,對原型鏈遞歸調用[[Get]],在各層的原型中查找屬性 // 直到原型為nullreturn __proto.[[Get]](P)

    請注意,因為[[Get]]在如下情況也會返回undefined:

    if (window.someObject) { ... }

    這里,在window里沒有找到someObject屬性,然后會在原型里找,原型的原型里找,以此類推,如果都找不到,按照定義就返回undefined。

    注意:in操作符也可以負責查找屬性(也會查找原型鏈):

    if ('someObject' in window) { ... }

    這有助于避免一些特殊問題:比如即便someObject存在,在someObject等于false的時候,第一輪檢測就通不過。

    [[Put]]方法

    [[Put]]方法可以創建、更新對象自身的屬性,并且掩蓋原型里的同名屬性。

    O.[[Put]](P, V): // 如果不能給屬性寫值,就退出if (!O.[[CanPut]](P)) { return; } // 如果對象沒有自身的屬性,就創建它 // 所有的attributes特性都是falseif (!O.hasOwnProperty(P)) { createNewProperty(O, P, attributes: { ReadOnly: false, DontEnum: false, DontDelete: false, Internal: false }); } // 如果屬性存在就設置值,但不改變attributes特性O.P = V return;

    例如:

    Object.prototype.x = 100; var foo = {}; console.log(foo.x); // 100, 繼承屬性 foo.x = 10; // [[Put]]console.log(foo.x); // 10, 自身屬性 delete foo.x; console.log(foo.x); // 重新是100,繼承屬性

    請注意,不能掩蓋原型里的只讀屬性,賦值結果將忽略,這是由內部方法[[CanPut]]控制的。

    // 例如,屬性length是只讀的,我們來掩蓋一下length試試 function SuperString() { /* nothing */ } SuperString.prototype = new String("abc"); var foo = new SuperString(); console.log(foo.length); // 3, "abc"的長度 // 嘗試掩蓋foo.length = 5; console.log(foo.length); // 依然是3

    但在ES5的嚴格模式下,如果掩蓋只讀屬性的話,會保存TypeError錯誤。

    屬性訪問器

    內部方法[[Get]]和[[Put]]在ECMAScript里是通過點符號或者索引法來激活的,如果屬性標示符是合法的名字的話,可以通過“.”來訪問,而索引方運行動態定義名稱。

    var a = {testProperty: 10}; alert(a.testProperty); // 10, 點alert(a['testProperty']); // 10, 索引 var propertyName = 'Property'; alert(a['test' + propertyName]); // 10, 動態屬性通過索引的方式

    這里有一個非常重要的特性——屬性訪問器總是使用ToObject規范來對待“.”左邊的值。這種隱式轉化和這句“在JavaScript中一切都是對象”有關系,(然而,當我們已經知道了,JavaScript里不是所有的值都是對象)。

    如果對原始值進行屬性訪問器取值,訪問之前會先對原始值進行對象包裝(包括原始值),然后通過包裝的對象進行訪問屬性,屬性訪問以后,包裝對象就會被刪除。

    例如:

    var a = 10; // 原始值 // 但是可以訪問方法(就像對象一樣)alert(a.toString()); // "10" // 此外,我們可以在a上創建一個心屬性a.test = 100; // 好像是沒問題的 // 但,[[Get]]方法沒有返回該屬性的值,返回的卻是undefinedalert(a.test); // undefined

    那么,為什么整個例子里的原始值可以訪問toString方法,而不能訪問新創建的test屬性呢?

    答案很簡單:

    首先,正如我們所說,使用屬性訪問器以后,它已經不是原始值了,而是一個包裝過的中間對象(整個例子是使用new Number(a)),而toString方法這時候是通過原型鏈查找到的:

    // 執行a.toString()的原理: 1. wrapper = new Number(a); 2. wrapper.toString(); // "10"3. delete wrapper;

    接下來,[[Put]]方法創建新屬性時候,也是通過包裝裝的對象進行的:

    // 執行a.test = 100的原理: 1. wrapper = new Number(a); 2. wrapper.test = 100; 3. delete wrapper;

    我們看到,在第3步的時候,包裝的對象以及刪除了,隨著新創建的屬性頁被刪除了——刪除包裝對象本身。

    然后使用[[Get]]獲取test值的時候,再一次創建了包裝對象,但這時候包裝的對象已經沒有test屬性了,所以返回的是undefined:

    // 執行a.test的原理: 1. wrapper = new Number(a); 2. wrapper.test; // undefined

    這種方式解釋了原始值的讀取方式,另外,任何原始值如果經常用在訪問屬性的話,時間效率考慮,都是直接用一個對象替代它;與此相反,如果不經常訪問,或者只是用于計算的話,到可以保留這種形式。

    繼承

    我們知道,ECMAScript是使用基于原型的委托式繼承。鏈和原型在原型鏈里已經提到過了。其實,所有委托的實現和原型鏈的查找分析都濃縮到[[Get]]方法了。

    如果你完全理解[[Get]]方法,那JavaScript中的繼承這個問題將不解自答了。

    經常在論壇上談論JavaScript中的繼承時,我都是用一行代碼來展示,事實上,我們不需要創建任何對象或函數,因為該語言已經是基于繼承的了,代碼如下:

    alert(1..toString()); // "1"

    我們已經知道了[[Get]]方法和屬性訪問器的原理了,我們來看看都發生了什么:

  • 首先,從原始值1,通過new Number(1)創建包裝對象
  • 然后toString方法是從這個包裝對象上繼承得到的
  • 為什么是繼承的? 因為在ECMAScript中的對象可以有自己的屬性,包裝對象在這種情況下沒有toString方法。 因此它是從原理里繼承的,即Number.prototype。

    注意有個微妙的地方,在上面的例子中的兩個點不是一個錯誤。第一點是代表小數部分,第二個才是一個屬性訪問器:

    1.toString(); // 語法錯誤! (1).toString(); // OK 1..toString(); // OK 1['toString'](); // OK

    原型鏈

    讓我們展示如何為用戶定義對象創建原型鏈,非常簡單:

    function A() { alert('A.[[Call]] activated'); this.x = 10; } A.prototype.y = 20; var a = new A(); alert([a.x, a.y]); // 10 (自身), 20 (繼承) function B() {} // 最近的原型鏈方式就是設置對象的原型為另外一個新對象B.prototype = new A(); // 修復原型的constructor屬性,否則的話是A了 B.prototype.constructor = B; var b = new B(); alert([b.x, b.y]); // 10, 20, 2個都是繼承的 // [[Get]] b.x: // b.x (no) --> // b.[[Prototype]].x (yes) - 10 // [[Get]] b.y // b.y (no) --> // b.[[Prototype]].y (no) --> // b.[[Prototype]].[[Prototype]].y (yes) - 20 // where b.[[Prototype]] === B.prototype, // and b.[[Prototype]].[[Prototype]] === A.prototype

    這種方法有兩個特性:

    首先,B.prototype將包含x屬性。乍一看這可能不對,你可能會想x屬性是在A里定義的并且B構造函數也是這樣期望的。盡管原型繼承正常情況是沒問題的,但B構造函數有時候可能不需要x屬性,與基于class的繼承相比,所有的屬性都復制到后代子類里了。

    盡管如此,如果有需要(模擬基于類的繼承)將x屬性賦給B構造函數創建的對象上,有一些方法,我們后來來展示其中一種方式。

    其次,這不是一個特征而是缺點——子類原型創建的時候,構造函數的代碼也執行了,我們可以看到消息"A.[[Call]] activated"顯示了兩次——當用A構造函數創建對象賦給B.prototype屬性的時候,另外一場是a對象創建自身的時候!

    下面的例子比較關鍵,在父類的構造函數拋出的異常:可能實際對象創建的時候需要檢查吧,但很明顯,同樣的case,也就是就是使用這些父對象作為原型的時候就會出錯。

    function A(param) { if (!param) { throw 'Param required'; } this.param = param; } A.prototype.x = 10; var a = new A(20); alert([a.x, a.param]); // 10, 20 function B() {} B.prototype = new A(); // Error

    此外,在父類的構造函數有太多代碼的話也是一種缺點。

    解決這些“功能”和問題,程序員使用原型鏈的標準模式(下面展示),主要目的就是在中間包裝構造函數的創建,這些包裝構造函數的鏈里包含需要的原型。

    function A() { alert('A.[[Call]] activated'); this.x = 10; } A.prototype.y = 20; var a = new A(); alert([a.x, a.y]); // 10 (自身), 20 (集成) function B() { // 或者使用A.apply(this, arguments) B.superproto.constructor.apply(this, arguments); } // 繼承:通過空的中間構造函數將原型連在一起var F = function () {}; F.prototype = A.prototype; // 引用B.prototype = new F(); B.superproto = A.prototype; // 顯示引用到另外一個原型上, "sugar" // 修復原型的constructor屬性,否則的就是A了B.prototype.constructor = B; var b = new B(); alert([b.x, b.y]); // 10 (自身), 20 (集成)

    注意,我們在b實例上創建了自己的x屬性,通過B.superproto.constructor調用父構造函數來引用新創建對象的上下文。

    我們也修復了父構造函數在創建子原型的時候不需要的調用,此時,消息"A.[[Call]] activated"在需要的時候才會顯示。

    為了在原型鏈里重復相同的行為(中間構造函數創建,設置superproto,恢復原始構造函數),下面的模板可以封裝成一個非常方面的工具函數,其目的是連接原型的時候不是根據構造函數的實際名稱。

    function inherit(child, parent) { var F = function () {}; F.prototype = parent.prototype child.prototype = new F(); child.prototype.constructor = child; child.superproto = parent.prototype; return child; }

    因此,繼承:

    function A() {} A.prototype.x = 10; function B() {} inherit(B, A); // 連接原型 var b = new B(); alert(b.x); // 10, 在A.prototype查找到

    也有很多語法形式(包裝而成),但所有的語法行都是為了減少上述代碼里的行為。

    例如,如果我們把中間的構造函數放到外面,就可以優化前面的代碼(因此,只有一個函數被創建),然后重用它:

    var inherit = (function(){ function F() {} return function (child, parent) { F.prototype = parent.prototype; child.prototype = new F; child.prototype.constructor = child; child.superproto = parent.prototype; return child; }; })();

    由于對象的真實原型是[[Prototype]]屬性,這意味著F.prototype可以很容易修改和重用,因為通過new F創建的child.prototype可以從child.prototype的當前值里獲取[[Prototype]]:

    function A() {} A.prototype.x = 10; function B() {} inherit(B, A); B.prototype.y = 20; B.prototype.foo = function () { alert("B#foo"); }; var b = new B(); alert(b.x); // 10, 在A.prototype里查到 function C() {} inherit(C, B); // 使用"superproto"語法糖 // 調用父原型的同名方法 C.ptototype.foo = function () { C.superproto.foo.call(this); alert("C#foo"); }; var c = new C(); alert([c.x, c.y]); // 10, 20 c.foo(); // B#foo, C#foo

    注意,ES5為原型鏈標準化了這個工具函數,那就是Object.create方法。ES3可以使用以下方式實現:

    Object.create || Object.create = function (parent, properties) { function F() {} F.prototype = parent; var child = new F; for (var k in properties) { child[k] = properties[k].value; } return child; }
    // 用法var foo = {x: 10}; var bar = Object.create(foo, {y: {value: 20}}); console.log(bar.x, bar.y); // 10, 20

    此外,所有模仿現在基于類的經典繼承方式都是根據這個原則實現的,現在可以看到,它實際上不是基于類的繼承,而是連接原型的一個很方便的代碼重用。

    結論

    本章內容已經很充分和詳細了,希望這些資料對你有用,并且消除你對ECMAScript的疑問,如果你有任何問題,請留言,我們一起討論。

    其它參考

    • 4.2 — Language Overview;
    • 4.3 — Definitions;
    • 7.8.5 — Regular Expression Literals;
    • 8 — Types;
    • 9 — Type Conversion;
    • 11.1.4 — Array Initialiser;
    • 11.1.5 — Object Initialiser;
    • 11.2.2 — The new Operator;
    • 13.2.1 — [[Call]];
    • 13.2.2 — [[Construct]];
    • 15 — Native ECMAScript Objects.

    轉載于:https://www.cnblogs.com/softlover/articles/2612303.html

    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

    總結

    以上是生活随笔為你收集整理的深入理解JavaScript系列(18):面向对象编程之ECMAScript实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    色综合在 | 九九国产精品视频 | 青青河边草免费观看完整版高清 | 一区二区在线影院 | 亚洲免费观看视频 | 99精品视频观看 | av黄色免费在线观看 | 亚洲日本va午夜在线电影 | 精品日韩中文字幕 | 久久久久国产精品www | 久久久精品国产免费观看一区二区 | 色av婷婷 | 波多野结衣网址 | 国产精品v欧美精品v日韩 | 久久99爱视频 | 日韩欧美一级二级 | 91精品啪啪| 久久伊人爱 | 麻豆国产网站 | av在线影片| 中文在线a天堂 | 国产精品免费观看国产网曝瓜 | 国产精品久久久久久久电影 | 国产综合精品久久 | 久草免费色站 | 久久视频精品 | 亚洲少妇影院 | 欧美精品乱码99久久影院 | 色综合久久88色综合天天人守婷 | av大全在线看 | 国产精品九九九九九九 | 激情五月在线 | 国产精国产精品 | 久久精品99久久久久久2456 | 天天av资源 | 亚洲精品欧洲精品 | 欧美激情视频一区 | 91九色成人蝌蚪首页 | 亚州欧美精品 | 一区二区三区在线播放 | 免费看精品久久片 | 久艹视频在线免费观看 | 欧美一区二区三区激情视频 | 欧美日韩久久不卡 | av网站在线观看免费 | 日韩欧美电影网 | 久久国产精品久久久久 | 成人黄色电影在线播放 | 色婷婷国产在线 | 九九免费观看全部免费视频 | 黄色com| 久久久久久久99 | 国产午夜精品一区 | 中文在线字幕免 | 中文不卡视频在线 | 久久国产精品二国产精品中国洋人 | 国产成在线观看免费视频 | 亚洲一区免费在线 | 国产高清绿奴videos | 国内精品国产三级国产aⅴ久 | 婷婷网在线 | 成人在线观看影院 | 国产伦精品一区二区三区无广告 | 免费看麻豆 | 久久tv| 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 最新av免费在线 | 久久视频在线观看免费 | 久久99国产一区二区三区 | 一级片黄色片网站 | 激情片av | 免费看色的网站 | 亚州黄色一级 | 国内精品久久久精品电影院 | 精品久久电影 | 亚洲久草在线视频 | 超碰人人射| 天天综合色网 | 在线看黄色的网站 | 天天干国产 | 婷婷电影在线观看 | 中文字幕日韩精品有码视频 | 亚洲91中文字幕无线码三区 | 日韩在线 一区二区 | 一区二区三区在线免费观看视频 | 天天舔天天射天天操 | 亚洲国产中文字幕在线观看 | 久久神马影院 | 日韩在线 | 免费在线观看亚洲视频 | 免费成人在线网站 | 高清一区二区三区av | 嫩草91影院 | 狠狠操夜夜操 | 成人免费在线视频 | 日本中文乱码卡一卡二新区 | 麻豆视频免费网站 | 四虎影视成人永久免费观看亚洲欧美 | 啪啪资源 | 久久久一本精品99久久精品66 | 久久久久电影网站 | 国产精品久久久久久久久久尿 | 国产精在线| 久久久精品高清 | 五月婷婷丁香在线观看 | 国产123av| 中文字幕视频观看 | 久久国产日韩 | 日韩另类在线 | 国产91精品在线观看 | 九九免费精品视频在线观看 | 草久久久| 香蕉91视频 | av免费在线观 | 午夜色大片在线观看 | 综合网天天 | 五月婷婷视频 | 不卡电影免费在线播放一区 | 日本黄色大片免费 | 伊人开心激情 | 久久无码av一区二区三区电影网 | 国产剧情在线一区 | 国产美女精品人人做人人爽 | 天天艹天天 | 精品亚洲成a人在线观看 | 8x成人在线 | 久久在线影院 | 久久这里只有精品1 | 欧美一区二区在线看 | 亚洲精品国精品久久99热 | 香蕉影院在线观看 | 精品国产1区2区 | 中文资源在线观看 | 片黄色毛片黄色毛片 | 麻豆传媒视频在线播放 | 久久精品视频播放 | 国产露脸91国语对白 | 91亚洲精品在线观看 | 精品国产一区二区三区久久久久久 | 一区二区三区日韩在线观看 | 992tv又爽又黄的免费视频 | 天天综合狠狠精品 | 3d黄动漫免费看 | 国产麻豆剧传媒免费观看 | 国产亚洲小视频 | 18国产精品白浆在线观看免费 | 国产美女精品人人做人人爽 | 一区二区三区四区五区在线 | 午夜在线看片 | 久草视频在线观 | 欧美激情第一区 | www欧美色| 成年人黄色在线观看 | 中国精品少妇 | 免费又黄又爽 | 婷婷在线视频 | 欧美成亚洲 | 日韩欧美视频一区二区 | 99在线播放 | 一区久久久| 免费福利在线观看 | 久久久久久国产精品免费 | 久久公开免费视频 | 麻豆91视频 | 日本久久久久久久久久久 | 日日爽| 97国产情侣爱久久免费观看 | 福利一区二区三区四区 | 久久五月情影视 | 麻豆 videos| 天天亚洲综合 | 91香蕉视频黄色 | 99视频精品在线 | 深爱激情五月网 | www色com | 97超视频在线观看 | 六月丁香激情综合 | 天天天操天天天干 | 日本激情视频中文字幕 | 久久精品91视频 | 久久免费精品一区二区三区 | 久久综合九色综合97_ 久久久 | 美女视频久久 | 日韩网站一区 | ww亚洲ww亚在线观看 | 嫩模bbw搡bbbb搡bbbb | 97视频在线免费观看 | 天天干天天碰 | 精品一区二区三区久久 | 91成人精品观看 | 91人人人| 毛片永久免费 | 国产精品24小时在线观看 | 国产九色在线播放九色 | www.福利| 美女视频久久 | av在线播放中文字幕 | 欧美性生活一级片 | 国产剧情一区二区 | 国产午夜麻豆影院在线观看 | 久久久2o19精品 | 日本特黄一级片 | 一级成人免费视频 | 天天曰夜夜爽 | 91视频午夜 | 欧美男男激情videos | 久久国产成人午夜av影院潦草 | 国产亚洲91 | 中文永久免费观看 | 日日激情 | 久久一区二区三区超碰国产精品 | 天天色综合1 | 国产精品久久久久毛片大屁完整版 | 久久a级片 | 在线免费观看黄 | 亚洲高清国产视频 | 亚洲激情视频 | 国产这里只有精品 | 日韩美女一级片 | 国产精品9999久久久久仙踪林 | 91九色视频在线观看 | 黄色高清视频在线观看 | 在线观看av大片 | 黄网站色视频 | 婷婷深爱五月 | 亚洲国产精品免费 | 亚洲精品在线观看的 | 国产 视频 久久 | 中文字幕久久久精品 | 日韩天天干 | 日韩毛片在线一区二区毛片 | 精品国产一区二区三区四区vr | 91av免费看| 91中文在线观看 | 国产成人一区二区三区在线观看 | 91在线视频免费观看 | 91国内在线| 日日夜夜网 | 久久久电影 | 粉嫩av一区二区三区四区在线观看 | 97精品超碰一区二区三区 | 中文字幕在线观看你懂的 | 亚洲永久精品视频 | 一区二区三区韩国免费中文网站 | 2018好看的中文在线观看 | 欧美va日韩va | 国内精品久久久久影院日本资源 | 狠狠干夜夜 | 色夜影院| 综合色久| 91资源在线视频 | 激情欧美一区二区三区 | 日韩在线视频一区 | 亚洲国产精品免费 | 蜜臀久久99静品久久久久久 | 日韩电影一区二区三区在线观看 | 久久成人高清 | 九九热免费视频在线观看 | 中文字幕在线一区观看 | 午夜成人影视 | 黄色成人91 | 欧美一二三区在线观看 | 天天操天天曰 | 精品一区二区6 | 制服丝袜天堂 | 日韩午夜小视频 | 伊人www22综合色 | 最近的中文字幕大全免费版 | 91视频免费国产 | 国产久草在线观看 | 久久精品2 | 日韩午夜电影网 | 日韩av成人在线 | 天天射色综合 | 亚洲电影在线看 | av黄色av| 国产99一区视频免费 | 91av视频在线观看免费 | 深夜免费福利网站 | h久久| 国产高清视频 | 岛国av在线免费 | 狠狠插狠狠干 | 中文字幕精品三区 | 国产精品久久久av | 久久精品亚洲 | 成人av高清 | 国产91在线播放 | 国产xxxx| 水蜜桃亚洲一二三四在线 | 黄色av播放 | 久久精品99视频 | 在线a人v观看视频 | 欧美久久久久久久久久 | 国产黑丝一区二区 | 精品国产自在精品国产精野外直播 | 岛国精品一区二区 | 精品电影一区二区 | 亚洲成av人影院 | 国产自在线观看 | 激情婷婷久久 | 久艹视频在线观看 | 精品久久五月天 | 一区二区三区精品在线视频 | 国产精品一区二区久久 | 亚洲国产精品500在线观看 | 久久国内精品99久久6app | 国产不卡在线观看视频 | 五月婷婷影院 | www99久久| 波多野结衣一区二区三区中文字幕 | 国产这里只有精品 | 91x色| 亚洲午夜久久久久久久久电影网 | 午夜视频一区二区 | 中文字幕中文中文字幕 | www.亚洲视频| 狠狠操狠狠干2017 | 国产精品久久久电影 | 国产又粗又猛又黄视频 | 超碰在线97国产 | 91爱爱免费观看 | 日韩成人精品一区二区三区 | 国产精品久久久久久久久岛 | 一区 二区电影免费在线观看 | 97在线影院 | 久久精品9| 91av在线国产 | 成年人在线看视频 | 久草在线视频精品 | 久久综合久久鬼 | 婷婷五月在线视频 | 伊人久操 | 午夜精品一区二区三区可下载 | 亚洲成色 | 人人澡人摸人人添学生av | 国产91粉嫩白浆在线观看 | 丁香视频全集免费观看 | 久久久久久美女 | 五月天天在线 | 欧美色操 | 美女视频网 | 91丨九色丨高潮丰满 | 国产色综合 | 91av在线视频播放 | 在线免费观看亚洲视频 | 成人免费xxx在线观看 | 91免费视频国产 | 日韩国产精品久久 | 91视频 - 88av| 免费视频 你懂的 | 国内成人综合 | 黄色a在线观看 | 免费的黄色的网站 | 粉嫩av一区二区三区入口 | 亚洲精品9 | 色鬼综合网 | 久久久久久久久久电影 | 婷婷色站| 夜又临在线观看 | 狠狠色狠狠色综合系列 | 国产精品日韩欧美 | 成人免费视频播放 | 成 人 免费 黄 色 视频 | 亚洲精品视频第一页 | 久久污视频 | 黄色av影视| 在线观看成人网 | 黄色精品久久 | 欧美成人69av | 国产成免费视频 | 精品久久久久久久 | 中文字幕乱码在线播放 | 天天骚夜夜操 | 一区二区精品在线观看 | 久久公开免费视频 | 精品视频不卡 | 国产色视频123区 | 亚洲小视频在线 | 美女网站视频免费都是黄 | 久久精品视频网址 | 国产精品电影一区 | 久久免费视频5 | 亚洲国产精品一区二区久久,亚洲午夜 | 狠狠色丁香婷婷综合久小说久 | 手机在线看片日韩 | 亚洲永久精品国产 | 成人午夜黄色 | 日韩精品久久久久久久电影99爱 | 国产成人一区二区三区在线观看 | 夜色在线资源 | 最新av中文字幕 | 国产亚洲观看 | 日韩av在线网站 | 久久热亚洲 | 国产男女无遮挡猛进猛出在线观看 | 99视频精品| 人人插人人射 | 在线视频欧美日韩 | 日日操天天爽 | 9ⅰ精品久久久久久久久中文字幕 | 国产视频一二区 | 婷婷色站 | 亚洲黄色小说网址 | 成片视频在线观看 | 美女福利视频在线 | 国产色秀视频 | 奇米网在线观看 | 国产成视频在线观看 | www看片网站 | 婷婷综合 | 综合视频在线 | 免费亚洲婷婷 | 婷婷精品 | 超碰最新网址 | 久久99热这里只有精品 | 91在线观看视频网站 | 亚洲精品综合在线观看 | 特级xxxxx欧美| 夜夜躁狠狠躁日日躁视频黑人 | 91中文字幕 | 免费av在 | 欧美日韩视频精品 | 99高清视频有精品视频 | 久久久久色 | 久99视频| 激情中文字幕 | 国产中文字幕av | 菠萝菠萝蜜在线播放 | 久久亚洲综合色 | 日韩一区二区三区高清在线观看 | 9在线观看免费高清完整版 玖玖爱免费视频 | 久久久亚洲麻豆日韩精品一区三区 | 午夜电影久久久 | 久久精品激情 | 丝袜美腿亚洲综合 | 韩国在线视频一区 | 精品视频9999 | 在线观看91网站 | 午夜av免费观看 | 午夜视频久久久 | 国产精品中文字幕在线观看 | 成人在线观看av | 日韩精品资源 | 国产 日韩 欧美 自拍 | 午夜久久久久久久久久影院 | 欧美日韩高清一区二区 国产亚洲免费看 | 99精品热 | 久久9精品| 欧美性生活大片 | 欧美一级艳片视频免费观看 | 在线观看一级 | 国产精品人人做人人爽人人添 | 久久精品视频免费播放 | aaa毛片视频| 人人干人人干人人干 | 欧美日韩在线视频观看 | 狠狠操操网 | 在线观看国产永久免费视频 | 最新中文字幕在线资源 | 日本精品久久久一区二区三区 | 亚洲国产成人精品在线 | 日韩一级黄色av | 亚洲综合色婷婷 | 中文字幕日韩电影 | 天天操狠狠操 | 天天激情天天干 | 国产自产高清不卡 | 日韩高清av | 成人国产精品一区 | 国产精品视频内 | 欧美另类高清 | 国产一区二区三区在线免费观看 | 五月天堂网 | 精品久久久一区二区 | 玖操| 国产视频久久久 | 午夜视频免费 | 中文字幕888 | 久久久久久久久久久久久9999 | 日日综合 | 91在线影院 | 精品久久久久一区二区国产 | 欧美精品国产综合久久 | 久久久久亚洲精品国产 | 亚洲清纯国产 | 91九色丨porny丨丰满6 | 在线观看一级片 | 国产电影一区二区三区四区 | 天天躁日日躁狠狠躁av中文 | 看片黄网站 | 96精品在线| 日韩黄色在线 | 日本二区三区在线 | 国产成人免费在线观看 | 午夜影院一区 | 国产区精品在线 | 一本色道久久综合亚洲二区三区 | 日本免费久久高清视频 | 欧美一级高清片 | 日韩免费av在线 | 日韩免费在线观看视频 | 久久视频精品 | 日本激情视频中文字幕 | 99久久99精品| 久久精品91视频 | h动漫中文字幕 | 狠狠色伊人亚洲综合网站野外 | 国产精品99久久久精品免费观看 | 亚洲夜夜网 | 天天操夜夜操天天射 | 国产成人综合图片 | 91人人在线| 免费看网站在线 | 97人人模人人爽人人喊中文字 | 久热精品国产 | 欧美成年人在线观看 | 999色视频 | 人人插超碰| 欧美a免费 | 婷婷丁香激情 | 激情五月视频 | 在线成人免费电影 | 在线看成人 | 日韩一二区在线 | 伊人天天狠天天添日日拍 | 日日综合 | 久久乱码卡一卡2卡三卡四 五月婷婷久 | 国内精品在线观看视频 | 人人爽人人看 | 349k.cc看片app | 免费在线一区二区 | 五月天丁香综合 | 人人玩人人弄 | 色婷婷视频在线观看 | 97人人模人人爽人人喊网 | 日韩系列在线 | 色狠狠一区二区 | 成人v| 国产精品久久精品 | 亚洲综合小说 | 国产视频亚洲视频 | 伊人永久在线 | 天天射天天搞 | 美女视频是黄的免费观看 | 又黄又刺激又爽的视频 | 又大又硬又黄又爽视频在线观看 | 欧美一区在线看 | 国产精品理论片在线观看 | 亚洲久在线 | 五月婷婷丁香六月 | 成人久久国产 | 国产精品视频地址 | 亚洲精品成人av在线 | 99中文在线 | 久久精品一区二区三区四区 | 超级碰视频 | 黄色一级网 | 亚洲观看黄色网 | 正在播放五月婷婷狠狠干 | 狠狠色丁香久久婷婷综合丁香 | 成人黄色电影在线 | 国产99色| 欧美俄罗斯性视频 | 精品91久久久久 | 欧美午夜激情网 | 国产精品精品国产色婷婷 | 久久深爱网 | 国产99久久久国产精品成人免费 | 免费看一级片 | 中文字幕免费不卡视频 | 色综合久久综合中文综合网 | 超碰在线观看av | 九九热免费在线观看 | a视频在线观看 | 久久精品视频在线观看免费 | 日韩视频免费观看高清 | 在线a人片免费观看视频 | 日p视频| 日韩成人xxxx| 中文字幕在线一二 | 人人干网站 | 成人av片免费看 | 欧美成人xxxxx| 国产午夜在线观看视频 | 精品一区二区三区久久 | 免费观看成人av | 国内精品久久久久影院一蜜桃 | 狠狠操天天射 | av黄免费看 | 波多野结衣电影久久 | 国产麻豆精品一区 | 国产精品九九九九九 | 久草在线一免费新视频 | 日日爱视频 | 日韩黄色免费 | 麻豆观看 | 国产成人精品午夜在线播放 | 成年人免费在线观看 | 国产精品1区2区3区在线观看 | 蜜桃av久久久亚洲精品 | 在线韩国电影免费观影完整版 | 久草在线免费看视频 | 国产一级视频在线免费观看 | 少妇性色午夜淫片aaaze | 亚洲欧洲av | 99久久精品国产亚洲 | 亚洲综合五月天 | 欧美色操 | 99在线视频免费观看 | 色综合天天色 | 国产成人精品不卡 | 久操伊人 | 亚洲精品国偷拍自产在线观看 | 亚洲国产网站 | 狠狠操夜夜| 午夜神马福利 | 在线免费精品视频 | 久久久精品小视频 | 日日夜夜国产 | 91视频在线免费看 | 91香蕉视频好色先生 | 一本一本久久a久久精品综合 | 国产乱码精品一区二区三区介绍 | 久艹视频在线观看 | 五月婷婷操 | 狠狠色伊人亚洲综合网站色 | 久久免费成人网 | 久久久私人影院 | 久久久久免费精品 | 黄色免费在线看 | 国产资源中文字幕 | 国际精品久久 | 国产97视频| 色91在线| 日韩手机在线 | 亚洲天堂网站 | 免费成人黄色片 | 草久久影院 | 久久精品久久久久 | 日韩手机视频 | 狠狠干免费| 午夜精品一区二区三区在线观看 | 91资源在线免费观看 | 亚洲精品综合一区二区 | 成人黄色片在线播放 | 黄色91免费观看 | 日韩欧美国产视频 | 久久网站最新地址 | 久久久国产精品电影 | 91在线影院 | 国产成人av一区二区三区在线观看 | 欧美日韩国产二区三区 | 波多野结衣视频一区 | 五月综合网| 在线免费高清一区二区三区 | 99热这里只有精品1 av中文字幕日韩 | 成人免费观看完整版电影 | 日韩理论电影在线观看 | 亚洲午夜av电影 | 久久精品中文字幕一区二区三区 | 久久狠狠亚洲综合 | 精品国自产在线观看 | 国产资源免费 | 米奇影视7777| 免费看一级特黄a大片 | 九九热视频在线播放 | 一区二区三区在线免费 | 精品国产91亚洲一区二区三区www | 视频精品一区二区三区 | 欧美在线观看禁18 | 国产精品一区在线观看你懂的 | 91人网站 | 国产一区二区在线观看视频 | 日日夜夜精品免费 | 99精品一区二区 | 国产v在线 | 在线观看91久久久久久 | 成人午夜在线观看 | 人人射人人射 | 久久中国精品 | 国产字幕在线播放 | 99视频精品免费视频 | 精品一区二区免费 | 久久伦理电影网 | av免费网站在线观看 | 国产精品中文字幕av | 日本久久久精品视频 | 波多野结衣电影久久 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 免费一级日韩欧美性大片 | 久久99国产精品二区护士 | 亚洲精品欧美精品 | 国产午夜麻豆影院在线观看 | 国产视频精品免费播放 | 天天色欧美 | 国产精品麻豆视频 | 九九电影在线 | 亚洲影音先锋 | 久久99精品国产 | 91天天操 | 五月婷婷色丁香 | 日韩 精品 一区 国产 麻豆 | 福利网址在线观看 | 久久精品精品电影网 | 精品99视频| 成人国产网站 | 91亚·色| 日本巨乳在线 | 亚州性色 | 久久国产免费看 | 亚洲aaa毛片 | 亚洲视频免费 | 久久久久久久综合色一本 | 日韩精品欧美专区 | 亚洲综合在线发布 | 久久高清av | 麻豆影音先锋 | 久久五月婷婷综合 | 在线免费观看视频一区二区三区 | 91精品久久久久久粉嫩 | 久久久亚洲精华液 | 亚洲欧洲一区二区在线观看 | 91色在线观看 | 8090yy亚洲精品久久 | 在线免费看黄色 | 草久久精品 | 国产精品久久久一区二区三区网站 | 成人免费视频网 | 国产午夜精品一区二区三区四区 | 五月天久久久久久 | 日本久久久久 | 国产成人99av超碰超爽 | 婷婷日| 五月婷婷中文网 | 亚洲精品久久激情国产片 | 在线亚洲高清视频 | 精品人妖videos欧美人妖 | 欧美激情精品久久久久久免费 | 久久夜色精品亚洲噜噜国4 午夜视频在线观看欧美 | 九九热在线精品视频 | 亚洲免费在线看 | 国产高清一区二区 | 国产亚洲精品久久久久久久久久久久 | 日韩在线中文字幕视频 | 亚欧洲精品视频在线观看 | 一级片色播影院 | 精品国产一区二区三区久久久久久 | 国产韩国日本高清视频 | 日本高清dvd| 色综合久久久久综合 | 91视频啊啊啊 | 国产韩国日本高清视频 | 免费观看视频的网站 | 国产精品中文字幕在线 | 天天操夜夜操天天射 | 88av网站 | 91视频网址入口 | 国产做爰视频 | 国产精品网在线观看 | 中文字幕在线一区观看 | 亚洲午夜精品久久久久久久久久久久 | 欧美日韩久久一区 | 久久综合九色综合网站 | 久久r精品 | 一区二区电影网 | 免费av的网站 | 一区二区日韩av | 国产免费三级在线观看 | 欧美国产精品一区二区 | 人人澡人 | 狂野欧美激情性xxxx欧美 | 成人黄色在线观看视频 | 日韩免费一二三区 | 日日夜夜精品 | 国产在线专区 | 黄色一级动作片 | 91麻豆产精品久久久久久 | 国产99免费视频 | 精品国产乱码久久久久久1区2匹 | 亚洲乱码在线观看 | 国产精品99久久久久久宅男 | 国产黄色美女 | 久久精品亚洲一区二区三区观看模式 | 亚洲日本精品 | 日本黄色免费播放 | 99色在线观看视频 | 成人久久视频 | 激情五月在线 | 人成在线免费视频 | 久久成人麻豆午夜电影 | 一区二区视频欧美 | 免费91麻豆精品国产自产在线观看 | 中文字幕乱偷在线 | 99热免费在线 | 国产在线欧美日韩 | 黄污网 | 免费看片网址 | zzijzzij亚洲日本少妇熟睡 | 国产在线欧美 | 国产啊v在线观看 | 色搞搞 | 日韩亚洲在线视频 | 免费视频你懂的 | 91毛片视频| av福利免费 | 国内精品久久久久久久97牛牛 | 国产无遮挡又黄又爽在线观看 | 五月婷视频| 国产精品久久免费看 | 色狠狠综合 | 日操干 | 国产精品免费小视频 | 色偷偷av男人天堂 | 丝袜美腿一区 | 国产视频一区在线 | 在线黄色av | 免费a视频在线 | 日本 在线 视频 中文 有码 | 亚洲视频免费 | 四虎影视4hu4虎成人 | 91网址在线看 | 成人毛片久久 | 欧美日韩在线视频免费 | 亚洲视频电影在线 | av在线影片| 亚洲日本va在线观看 | 综合网中文字幕 | 成人av免费看 | 亚洲乱码中文字幕综合 | 日韩一级片网址 | 国产老太婆免费交性大片 | 国产精品久久人 | 九九久久成人 | 日韩欧美国产免费播放 | 热久久这里只有精品 | 国产午夜激情视频 | 欧美一级在线看 | 久草网视频在线观看 | 在线亚洲天堂网 | 69中文字幕 | 亚洲va在线va天堂 | 日韩在线观看视频在线 | 涩五月婷婷 | 99久久精品国产观看 | 欧美日韩国产精品一区二区亚洲 | 亚洲开心色 | 黄色成年网站 | 日日摸日日爽 | 97碰碰精品嫩模在线播放 | 黄色软件视频大全免费下载 | 五月婷婷一区 | 日韩美女高潮 | 国产视频资源在线观看 | 国产精品免费久久久久久久久久中文 | 免费精品国产va自在自线 | 国产一区二区精品久久91 | 在线中文字母电影观看 | 91视频高清完整版 | 国产欧美综合视频 | 日韩欧美精品在线观看 | 99久久国产免费,99久久国产免费大片 | 国产小视频在线观看 | 亚洲成aⅴ人在线观看 | 91欧美视频网站 | 9色在线视频 | 日韩性色| 亚洲综合一区二区精品导航 | 日本久久中文 | 国产九九精品视频 | 天天做夜夜做 | 一区二区三区在线观看免费视频 | 手机av看片 | 欧美性久久久久久 | 精品自拍av | 一本色道久久综合亚洲二区三区 | 天天爽夜夜爽人人爽曰av | 91精品一区在线观看 | 国产精品久久久久久爽爽爽 | 天天爱天天操天天射 | av在线精品 | 精品国产伦一区二区三区观看说明 | 最新av在线网址 | 色天天综合久久久久综合片 | 精品99视频 | 国产成人a亚洲精品 | 国产精品免费一区二区三区 | 国产成人精品久久久久 | 久久图 | 国产免费又粗又猛又爽 | 精品久久久一区二区 | 91麻豆免费看 | 在线视频观看成人 | 综合色在线 | 免费中文字幕在线观看 | 在线免费观看不卡av | 久草在线资源视频 | 日日夜夜操操操操 | 天堂网一区二区 | 日韩欧美在线视频一区二区三区 | 五月色综合 | www91在线观看 | 久久视频在线免费观看 | 欧美另类sm图片 | 亚洲精品一区二区三区高潮 | 亚洲国产日本 | 色免费在线| av成人在线播放 | 久久精品99国产精品酒店日本 | 99爱视频 | 国产网站在线免费观看 | 91免费观看国产 | 娇妻呻吟一区二区三区 | 9在线观看免费高清完整版 玖玖爱免费视频 | 久久婷婷国产色一区二区三区 | 国产韩国精品一区二区三区 | 少妇性色午夜淫片aaaze | av成人在线观看 | 99久久精品国产免费看不卡 | 日韩视频1区 | 99视频精品在线 | 99综合久久 | 综合色婷婷 | 国产亚洲精品久久久久久无几年桃 | 国产精品综合在线 | 91av国产视频 | 久久精品人人做人人综合老师 | 五月开心激情 | avwww在线| 91天天操| 999男人的天堂 | 国产午夜精品一区二区三区嫩草 | 天天操夜夜看 | 久久人人爽人人人人片 | 97精品国产91久久久久久 | 999热线在线观看 | 亚洲精选视频在线 | 欧美色婷 | 成人亚洲欧美 | 久久av高清 | 日韩久久精品一区二区 | 亚州精品在线视频 | 国产91成人在在线播放 | 欧美日韩视频观看 | 国产 视频 高清 免费 | 精品一区二区三区电影 | 激情欧美在线观看 | 狠狠色婷婷丁香六月 | 91av在线免费视频 | 国产黄色片一级三级 | 日韩电影中文字幕在线观看 | 国产成人av| 嫩草91影院 | bayu135国产精品视频 | www久久久久| 中文字幕在线视频一区二区三区 | 99精品国产99久久久久久97 | 精品国产精品久久一区免费式 | 黄网站色成年免费观看 | 男女激情片在线观看 | 波多野结衣视频一区 | 99久久99久久精品国产片果冰 | 日本在线观看视频一区 | 91视频网址入口 | 综合网在线视频 | 中文字幕在线一区二区三区 | 欧美日韩不卡在线视频 | 97视频在线观看播放 | 一区二区视频网站 | 奇米影视8888 | 中文字幕免费观看视频 | 日日爽 | 激情婷婷六月 | a级国产乱理伦片在线播放 久久久久国产精品一区 | 丁香 婷婷 激情 | 欧美另类一二三四区 | 国产午夜亚洲精品 | 日本福利视频在线 | 六月丁香激情综合 | 中文字幕第一页av | 精品视频国产一区 | 99免费视频 | 欧美国产精品一区二区 | 日韩丝袜在线观看 | 91麻豆精品国产91久久久久久久久 | 精品国产激情 | www.888av| 久久夜视频 | 国产a级片免费观看 | 手机看片国产日韩 | 99精品免费在线观看 | 色婷婷中文 | 国产专区在线视频 | 色五月色开心色婷婷色丁香 | 毛片a级片| 精品亚洲免费 | 日韩啪啪小视频 | 片黄色毛片黄色毛片 |