国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS高程讀書筆記--第六章原型繼承

EasonTyler / 3503人閱讀

摘要:高程讀書筆記第六章理解對象創建自定義對象的方式有創建一個實例,然后為它添加屬性和方法。創建了自定義的構造函數之后,其原型對象默認只會取得屬性至于其他方法都是從繼承而來的。

JS高程讀書筆記--第六章 理解對象

創建自定義對象的方式有創建一個Object實例,然后為它添加屬性和方法。還可用創建對象字面量的方式

屬性類型

ECMAScript在定義只有內部采用的特性時,描述了屬性的各種特征。
ECMAScript中有兩種屬性:數據屬性訪問器屬性。在JS中不能直接訪問它們。

數據屬性

數據屬性包含一個數據值的位置。在這個位置可以讀取和寫入值。

[[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性。默認值為true

[[Enumerable]]:表示能否通過for-in循環返回屬性。默認值為true

[[Writable]]:表示能否修改屬性的值。默認值為true

[[Value]]:包含這個屬性的數據值。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值保存在這個位置。默認值為undefined

要修改屬性默認的特性,必須使用ES5的Object.defineProperty()方法。這個方法接收三個參數:屬性所在的對象屬性的名字一個描述符對象。在調用這個方法時,如果不指定,configurable、enumerable和writable特性的默認值都是false;

</>復制代碼

  1. 一旦把屬性定義為不可配置的,就不能再把它變回可配置的。

訪問器屬性

訪問器屬性不包含數據值;他們包含一對getter和setter函數(這兩個函數都不是必須的)。在讀取訪問器屬性時,會調用getter函數,這個函數負責返回有效值;在寫入訪問器屬性時,會調用setter函數并傳入新值,這個函數負責決定如何處理數據。

[[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為數據屬性。默認值為true

[[Enumerable]]:表示能否通過for-in循環返回屬性。默認值為true

[[Get]]:在讀取屬性時調用的函數。默認值為undefined;

[[Set]] :在寫入屬性時調用的函數。默認值為undefined

</>復制代碼

  1. 訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義。

不一定非要同時指定getter和setter。只指定getter意味著屬性是不能寫,嘗試寫入屬性會被忽略。在嚴格模式下,嘗試寫入只指定了getter函數的屬性會拋出錯誤。類似的,只指定setter函數的屬性也不能讀,否則在非嚴格模式下會返回undefined,而在嚴格模式下會拋出錯誤。

定義多個屬性

可以利用ES5定義的Object.defineProperties()方法通過描述符一次定義多個屬性。這個方法接收兩個對象參數:第一個對象是要添加和修改其屬性的對象,第二個對象的屬性與第一個對象中要添加或修改的屬性一一對應。

讀取屬性的特性

使用ES5的Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述符。這個方法接收兩個參數:屬性所在對象要讀取其描述符的屬性名稱,返回值是一個對象

創建對象 工廠模式

這種模式抽象了創建具體對象的過程。開發人員發明了一種函數,用函數來封裝以特定接口創建對象的細節。

</>復制代碼

  1. function createPerson(name,age,job){
  2. var o = new Object();
  3. o.name = name;
  4. o.age = age;
  5. o.job = job;
  6. o.sayName = function(){
  7. console.log(this.name);
  8. }
  9. return o;
  10. }
  11. var person1 = createPerson("junyan","25","FE");

工廠模式雖然解決了創建多個相似對象的問題,但卻沒有解決對象識別的問題(即怎樣知道一個對象的類型)

構造函數模式

可以創建自定義的構造函數,從而定義自定義對象類型的屬性和方法。

</>復制代碼

  1. function Person(name,age,job){
  2. this.name = name;
  3. this.age = age;
  4. this.job = job;
  5. this.sayName = function(){
  6. console.log(this.name);
  7. };
  8. }
  9. var person1 = new Person("junyan","25","FE")

這種方式與工廠模式存在以下不同:

沒有顯式的創建對象;

直接將屬性和方法賦給了this對象;

沒有return語句;

要創建Person新實例,必須使用new操作符。以這種方式調用構造函數實際上會經歷以下4個步驟:

創建一個新對象;

將構造函數的作用域賦給新對象(因此this就指向了這個新對象);

執行構造函數中的代碼(為這個新對象添加屬性);

返回新對象;

實例都有一個constructor(構造函數)屬性,該屬性指向Person。對象的這個屬性最初是用來標識對象類型的。但是,提到檢測對象類型,還是instanceof操作符要更可靠一些。

</>復制代碼

  1. 創建自定義的構造函數意味著將來可以將它的實例標識為一種特定的類型

將構造函數當做函數

構造函數與其他函數的唯一區別,就在于調用它們的方式不同。任何函數,只要通過new操作符來調用,那它就可以作為構造函數;

不使用new操作符調用,屬性和方法都被添加給window對象

構造函數的問題

使用構造函數的主要問題就是每個方法都要在每個實例上重新創建一遍。

不同實例上的同名函數是不相等的,可以通過把函數定義轉移到構造函數外部來解決。

原型模式!!

我們創建的每個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法

</>復制代碼

  1. prototype就是通過調用構造函數而創建的那個對象實例的原型對象

使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法。換句話說,不必在構造函數中定義對象實例的信息,而是可以將這些信息直接添加到原型對象中。

</>復制代碼

  1. 構造函、原型和實例的關系:每個構造函數構造函數都有一個原型對象(prototype),原型對象都包含一個指向構造函數的指針(constructor),而實例都包含一個指向原型對象的內部指針(__proto__)

理解原型對象!!!

只要創建了一個新函數,就會根據一組特定的規則為該函數創建一個prototype屬性,這個屬性指向函數的原型對象
所有原型對象都會自動獲得一個constructor(構造函數)屬性,這個屬性包含一個指向prototype屬性所在函數的指針。例:Person.prototype.constructor = Person

創建了自定義的構造函數之后,其原型對象默認只會取得constructor屬性;至于其他方法都是從Object繼承而來的。

</>復制代碼

  1. 原型最初只包含constructor屬性,而該屬性也是共享的,因此可以通過對象實例訪問

當調用構造函數創建一個新實例后,該實例的內部將包含一個指針(內部屬性)ECMA叫[[Prototype]]指向構造函數的原型對象,高級瀏覽器在每個對象上都支持一個屬性__proto__

</>復制代碼

  1. 注:這個連接存在于實例與構造函數的原型對象之間,不存在于實例與構造函數之間。

可以通過isPrototypeOf()方法來確定對象之間是否存在這種關系
Person.prototype.isPrototypeOf(person1); // true;

ES5新增了一個方法,叫Object.getPrototypeOf(),這個方法返回[[Prototype]]的值。
Object.getPrototypeOf(person1) == Person.prototype

使用這個方法可以方便的取得一個對象的原型

當為對象實例添加一個屬性時,這個屬性就會屏蔽原型對象中的同名屬性;換句話說,添加這個屬性只會阻止我們訪問原型中的那個屬性,但不會修改那個屬性。即使將這個屬性設置為null,也只會在實例中設置這個屬性,而不會恢復其指向原型的鏈接。不過,可以通過使用delete操作符則可以完全刪除實例屬性,從而讓我們能夠重新訪問原型中的屬性。

</>復制代碼

  1. 使用hasOwnProperty()方法可以檢測一個屬性是存在于實例中,還是存在于原型中。這個方法(從Object繼承而來)只在給定屬性存在于對象實例中,在返回true

原型與in操作符

多帶帶使用in時,in操作符會在通過對象能夠訪問給定屬性時返回true,無論該屬性存在于實例中還是原型中

同時使用hasOwnProperty()方法和in操作符,就可以確定該屬性到底是存在于對象中,還是存在于原型中

在使用for-in循環時,返回的是所有能夠通過對象訪問的、可枚舉的屬性,其中即包括存在于實例中的屬性,也包括存在于原型中的屬性。屏蔽了原型中不可枚舉屬性的實例屬性也會在for-in循環中返回。

要取得對象上可枚舉的實例屬性,可以使用ES5的Object.keys(),這個方法接收一個對象作為參數,返回一個包含所有可枚舉屬性的字符串數組。

如果想得到所有實例屬性,無論它是否可枚舉,都可以使用Object.getOwnPropertyNames()

更簡單的原型語法

可以用一個包含所有屬性和方法的對象字面量來重寫整個原型對象

</>復制代碼

  1. Person.prototype = {
  2. name:"junyan",
  3. job:"FE"
  4. }

但是這樣constructor屬性就不再指向Person,這種語法實際上完全重寫了默認的prototype對象,因此constructor屬性就變成了新對象的constructor屬性,不再指向Person,而是指向Object。此時instanceof還能返回正確的結果。

如果constructor屬性很重要,可以特意設定將它設置回適當的值,但這種方式重設constructor屬性會導致它的[[Enumerable]]特性被設置為true,因為默認情況下原生的constructor屬性是不可枚舉的。可以使用ES5的Object.defineProperty()

原型的動態性

我們對原型對象所做的任何修改都能夠立即從實例上反映出來,即使是先創建了實例后修改原型也照樣如此,因為實例與原型之間的連接只不過是一個指針,而非一個副本;

但是如果重寫了整個原型對象,就不一樣。調用構造函數時會為實例添加一個指向最初原型的[[Prototye]]指針(__proto__),而把原型修改為另一個對象就等于切斷了構造函數與最初原型之間的聯系

重寫原型對象切斷了現有原型與任何之前已經存在的對象實例之間的聯系,它們引用的仍然是最初的原型

</>復制代碼

  1. 實例中的指針僅指向原型,而不指向構造函數

原生對象的原型

所有原生引用類型(Object、Array、String等)都在其構造函數的原型上定義了方法;

通過原生對象的原型,不僅可以取得所有默認方法的引用,而且也可以定義新方法。可以像修改自定義對象的原型一樣修改原生對象的原型,因此可以隨時添加方法。(不建議);

原型對象的問題

原型中所有屬性被實例共享,對于基本類型值的屬性,通過在實例上添加一個同名屬性,可以隱藏原型中的對應屬性,但對于引用類型值的屬性來說,實例上修改其值,在所有其他實例中都會反映出來,所以基本不多帶帶使用原型模式

組合使用構造函數模式和原型模式

構造函數模式用于定義實例屬性,而原型模式用于定義方法和共享屬性。

</>復制代碼

  1. function Person(name,age,job){
  2. this.name = name;
  3. this.age = age;
  4. this.job = job;
  5. this.friends = ["xiaohua","hanghang"]
  6. }
  7. Person.prototype = {
  8. constructor:Person,
  9. sayName:function(){
  10. console.log(this.name);
  11. }
  12. }
繼承

ECMAScript只支持實現繼承,而且實現繼承主要是依靠原型鏈來實現。

原型鏈

原型鏈作為實現繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。

如果讓原型對象等于另一個類型的實例,此時的原型對象將包含一個指向另一個原型的指針(__proto__)相應地,另一個原型中也包含著一個指向另一個構造函數的指針。若另一個原型又是另一個類型的實例,上述關系依然成立,如此層層遞進,就構成了實例與原型的鏈條。

</>復制代碼

  1. 在找不到屬性或方法的情況下,搜索過程總是要一環一環地前行到原型鏈末端才會停下來

默認的原型

所有引用類型默認都繼承了Object,而這個繼承也是通過原型鏈實現的。所有函數的默認原型都是Object實例,因此默認原型都會包含一個內部指針(__proto__),指向Object.prototype。這也正是所有自定義類型都會繼承toString()valueOf()默認方法的根本原因

確定原型和實例的關系

第一種方式是使用instanceof操作符,只要用這個操作符來測試實例與原型鏈中出現過的構造函數,結果就會返回true。

第二種方式是使用isPrototypeOf()方法。同樣,只要是原型鏈中出現過的原型,都可以說是該原型鏈所派生的實例的原型,因此這個方法也會返回true.

謹慎地定義方法

給原型添加方法一定要放在替換原型的語句之后,重寫的方法會屏蔽原來的那個方法

在通過原型鏈實現繼承時,不能使用對象字面量創建原型方法。因為這樣做就會重寫原型鏈。

原型鏈的問題

實踐中很少會多帶帶使用原型鏈

在通過原型來實現繼承時,原型實際上會變成另一個類型的實例,原先的實例屬性也就順理成章的變成了現在的原型屬性

在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。應該說是沒有辦法在不影響所有對象實例的情況下,給超類型的構造函數傳遞參數。

借用構造函數

在子類型構造函數的內部調用超類型構造函數,可以通過使用apply()call()方法在新創建的對象上執行構造函數。

</>復制代碼

  1. function SubType(){
  2. SuperType.call(this);
  3. }

這一年就會在新的Subtype對象上執行SuperType()函數中定義的所有對象初始化代碼。

可以在子類型構造函數中向超類型構造函數傳遞參數

</>復制代碼

  1. function SubType(){
  2. SuperType.call(this,"junyan");
  3. }

如果僅僅是借用構造函數,那么也將無法避免構造函數模式存在的問題——方法都在構造函數中定義,因此函數復用就無從談起,而且在超類型的原型中定義的方法,對子類型而言也是不可見的,結果所有類型都只能使用構造函數模式。

組合繼承

有時也叫作偽經典繼承,使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承。這樣既通過在原型上定義方法實現了函數復用,又能夠保證每個實例都有它自己的屬性。

</>復制代碼

  1. instanceofisPrototypeof()也能夠用于識別基于組合繼承創建的對象

組合繼承最大的問題就是無論什么情況下,都會調用兩次超類型構造函數:一次是在創建子類原型的時候,另一次是在子類型構造函數內部

原型式繼承

這個方法沒有使用嚴格意義上的構造函數,是基于已有的對象創建新對象,同時還不必因此創建自定義類型。

</>復制代碼

  1. function object(o){
  2. function F(){}
  3. F.prototype = o;
  4. return new F();
  5. }

</>復制代碼

  1. 嚴格上講,object()對傳入其中的對象執行了一次淺復制

ES5通過新增Object.create()方法規范了原型式繼承。這個方法接收兩個參數:一個用作新對象原型的對象和(可選的)一個為新對象定義額外屬性的對象。在傳入一個參數的情況下,Object.create()object()方法的行為相同。
只想讓一個對象與另一個對象保持類似的情況下,原型式繼承是完全可以勝任的,不要忘了,包含引用類型值的屬性始終都會共享相應的值,就像使用原型模式一樣。

寄生式繼承

創建一個僅用于封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最后再像真地是它做了所有工作一樣返回對象。

</>復制代碼

  1. function createAnother(original){
  2. var clone = object(original);
  3. clone.sayHi = function(){
  4. console.log("Hi");
  5. };
  6. return clone;
  7. }

在主要考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式。任何能夠返回新對象的函數都適用于這個模式

寄生式組合繼承

所謂寄生組合式繼承,即通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。其背后的基本思路是:不必為了指定子類型的原型而調用超類型的構造函數,我們所需要的無非就是超類型原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,然后再將結果指定給子類型的原型

</>復制代碼

  1. function inheritPrototype(subType,superType){
  2. var prototype = Object(superType.prototype);
  3. prototype.constructor = subType;
  4. subType.prototype = prototype;
  5. }

第一步是創建超類型原型的一個副本

第二部是為創建的副本添加constructor屬性,從而彌補因重寫原型而失去的默認的constructor屬性。

將新創建的對象(即副本)賦值給子類型的原型

</>復制代碼

  1. 這種繼承的高效率體現在它只調用了一次超類型構造函數,并且因此避免了在子類型.prototype上面創建不必要的、多余的屬性。于此同事,原型鏈還能保持不變;因此還能正常使用instanceof()isPrototypeOf()

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86446.html

相關文章

  • 高程讀書筆記 六章 面向對象程序設計

    摘要:創建一個新對象將構造函數的作用域賦給新對象因此就指向了這個新對象執行構造函數中的代碼為這個新對象添加屬性返回新對象。 本章內容 理解對象屬性 理解并創建對象 理解繼承 ECMA-262把對象定義為:無序屬性的集合,其屬性可以包含基本值、對象或者函數 理解對象 創建對象 創建自定義對象的最簡單方式就是創建一個Object的實例,再為它添加屬性和方法。 var person = new...

    468122151 評論0 收藏0
  • 《javascript高級程序設計》六章 讀書筆記 之 javascript繼承的6種方法

    摘要:繼承的是超類型中構造函數中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結果是子類型實例中有兩組超類型的構造函數中定義的屬性,一組在子類型的實例中,一組在子類型實例的原型中。 ECMAScript只支持實現繼承,主要依靠原型鏈來實現。與實現繼承對應的是接口繼承,由于script中函數沒有簽名,所以無法實現接口繼承。 一、原型鏈 基本思想:利用原型讓一個引用類型繼承另一個引用...

    孫吉亮 評論0 收藏0
  • JavaScript高程六章:繼承-理解與實踐

    摘要:高程第六章繼承理解與實踐昨日細細的讀了一遍高程現在寫篇文章來鞏固下認知吧讀首先是從中讀到了什么我自己也在讀書的時候用筆記下了各個部分的點現在等于閱讀筆記回憶下書本理解基礎第五版中規定了兩種屬性數據屬性訪問器屬性數據屬性包含一個數據值的位 JavaScript高程第六章:繼承-理解與實踐昨日細細的讀了一遍JavaScript高程,現在寫篇文章來鞏固下認知吧. 讀 首先是從中讀到了什么,我...

    mozillazg 評論0 收藏0
  • 《javascript高級程序設計》六章 讀書筆記 之 javascript對象的幾種創建方式

    摘要:三種使用構造函數創建對象的方法和的作用都是在某個特殊對象的作用域中調用函數。這種方式還支持向構造函數傳遞參數。叫法上把函數叫做構造函數,其他無區別適用情境可以在特殊的情況下用來為對象創建構造函數。 一、工廠模式 工廠模式:使用字面量和object構造函數會有很多重復代碼,在此基礎上改進showImg(https://segmentfault.com/img/bVbmKxb?w=456&...

    xiaotianyi 評論0 收藏0
  • 《java 8 實戰》讀書筆記 -六章 用流收集數據

    摘要:分區函數返回一個布爾值,這意味著得到的分組的鍵類型是,于是它最多可以分為兩組是一組,是一組。當遍歷到流中第個元素時,這個函數執行時會有兩個參數保存歸約結果的累加器已收集了流中的前個項目,還有第個元素本身。 一、收集器簡介 把列表中的交易按貨幣分組: Map transactionsByCurrencies = transactions.stream().collect(groupi...

    Airy 評論0 收藏0

發表評論

0條評論

EasonTyler

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<