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

資訊專欄INFORMATION COLUMN

我來重新學習 javascript 的面向對象(part 2)

silvertheo / 652人閱讀

摘要:先來說其實構造函數也有,原型對象有,實例有也有,或者更加籠統的說,所有對象都是有的。構造函數的原型對象上的會指向構造函數。由于屬性是可以變更的,所以未必真的指向對象的構造函數,只是一個提示。

續上一集內容,通過構造函數的方式,成功地更新了生產技術,老板笑呵呵,工人少奔波,只是問題總比辦法多,又遇到一個新問題,就是會造成一些資源的重復和浪費,那么經過工程師們的智慧交流,他們產生了一個新技術,原型模式

一、使用原型模式
function Food() {}

Food.prototype.name = "蘋果";
Food.prototype.sayName = function() {
  console.log("我是" + this.name);
};

var food1 = new Food();
food1.sayName();

var food2 = new Food();
food2.sayName();
// 創建無限多的 food 。。。。。。

console.log(food1.sayName == food2.sayName); // 返回 true

將所有屬性和方法,包括sayName 方法都放到原型Food的原型上去

跟之前構造函數創建新對象的方式一樣,使用new來創建

這樣就完成了原型模式的使用了,能夠將函數進行共享,不用每次都重復創建不同的函數實例了,而且所有的屬性共享,也能夠很方便節省代碼和簡化結構,其他人也可以很方便地進行使用。

但是比較懵逼,為什么這樣就可以了呢?原型是個什么東西?怎么起作用的呢?

1.1 理解什么是原型

在《javascript 高級程序設計》里面是這樣說的,我們創建的每個函數都有一個 prototype,這個屬性是一個內存指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。

換句大白話來說:

原型就是根,所有東西都有根,是來自于哪里,是被誰創造出來的,并且能夠通過這個根去追溯父輩祖輩的信息。

全部東西都會由原型創造,所以都會帶有一個原型屬性,只是不同的原型創造出來的東西帶有不同的原型屬性。

例如圖1,可以粗獷地理解為蛋是雞生的,所以蛋的原型是雞。

圖片引用來自:https://hackernoon.com/unders...

或者用親屬關系來理解,原型就是你的父輩祖輩。

圖片引用自http://china.findlaw.cn/info/...

例如圖2,這是一個類樹狀結構的組織:

圖片引用自:http://rohitnsit08.blogspot.c...

這里的global object 的意思在后面有解釋。

從這個圖可以看到,各種不同過的對象,都會有不同的原型,string 的原型就是 string.prototypefunction 的原型就是 string.prototype 等等,而這些原型的原型就是Object.prototype了,所以就有那么一句話,在 javascript 里面,所有的東西都是對象

在 javascript 里面,global object 有4種:

在瀏覽器里面,windows 被稱作是 global object

在 nodejs 里面,nodejs 的運行本身也是一個 global objec

在 Worker 線程下, WorkerGlobalScope 也叫 global object

在一般 javascript 運行過程中,在所有對象被創建之前,會預先創建一個 global object,里面包含了所有這個 javascript 引擎里面擁有的屬性和方法,這個也叫做 global object,并且 javascript 的對象系統都是基于這個 global object 建立的。

1.2 理解什么是 constructor 和構造函數的 prototype 和 [[prototype]]

其實原型是很好理解的東西,就是原來的形態,例如string 的原型就是 string.prototype,字符串的原來的形態就是字符串原型,但是還有一些比較影響理解和學習的東西,例如constructor prototype [[prototype]] 這些。

① 先來說constructor

其實構造函數也有constructor,原型對象有constructor,實例有constructor 也有,或者更加籠統的說,所有對象都是有constructor的。

// 構造函數的constructor,默認構造函數的原型對象是Function對象
function Food() {}
console.log(Food.constructor); // 返回[Function: Function]

// 實例的constructor是Food
var food1 = new Food("蘋果");
console.log(food1.constructor); // 返回 [Function: Food]

// 構造函數的原型對象Food.prototype 也有constructor,指向構造函數
console.log(Food.prototype.constructor); // 返回 [Function: Food]

構造函數也是函數,他的 constructor默認會指向[Function: Function],也就是函數原型對象是他的原型對象。

當使用 new 來實例化對象的時候,實例的constructor會默認指向構造函數,證明是哪一個來自于哪一個構造函數,但是僅此而已,只是一個標識,所以是 Food

構造函數 的原型對象 Food Prototype上的constructor會指向構造函數 Food

可以看出,通過 constructor 可以看到他們之間的關系,但是通過constructor連接的關系是很脆弱的(容易變化,不可靠),也因為 javascript 在設計當初并沒有太多考慮這個情況,所以constructor比較雞肋。

另外雖然有這么多constructor,但是我們一般討論的比較多的是,原型對象的constructor,他會默認指向構造函數的 prototype 屬性,僅此而已,如果他沒有被改變的話,也可以充當一種標志,代表通過這個構造函數生成的實例是來自哪個原型的,從而判斷對象的類型是哪一種(但不可靠)

舉例說明:

function Food() {}
console.log(Food.constructor); // 返回[Function: Function]

// 當重寫原型的時候,實例的constructor 就變成了[Function: Object]
Food.prototype = {
  name: "蘋果"
};
var food2 = new Food("蘋果");
console.log(food2.constructor); // 返回 [Function: Object]

這里實例的constructor就被改變了,所以一般我們可以看到重寫原型的時候(原型鏈被切斷,會默認指向默認的原型對象),會手動加入一個 constructor 屬性來指定它的值,以方便識別。

function Food() {}
console.log(Food.constructor); // 返回[Function: Function]
// 我們需要主動標記 constructor屬性
Food.prototype = {
  constructor: Food,
  name: "蘋果"
};
var food2 = new Food("蘋果");
console.log(food2.constructor); // 返回 [Function: Food]
constructor其實沒有什么用處,他是JavaScript語言設計的歷史遺留物。由于constructor屬性是可以變更的,所以未必真的指向對象的構造函數,只是一個提示。不過,從編程習慣上,我們應該盡量讓對象的constructor指向其構造函數,以維持這個慣例。--by 賀師俊

② 再來說prototype

在 javascript 里面,只要是函數,都會有這樣一個屬性prototype,這個屬性指向函數的原型對象,在默認情況下,所有原型對象都會自動獲得一個 constructor 屬性,指向prototype 所在的函數。

function Food() {}
console.log(Food.prototype) // 返回Food {}

var food1 = new Food("蘋果");

console.log(food1.prototype) // 返回 undefined

構造函數 Food 的prototype屬性是一個內存指針,最終是指向 Food 的原型對象 Food Prototype 的,這里需要注意我的寫法,是 Food Prototype ,這里雖然很相似,但其實不是。

實例對象上的 prototype 屬性沒辦法直接查看,所以返回 undefined,需要用別的方法來查看。

③ 最后說說[[prototype]]__proto__

這是存在于實例身上的 prototype 屬性,但是沒辦法直接查看,只能通過某些方式來獲取和判斷。不同的瀏覽器有不同的叫法,的屬性名字也可能是[[prototype]] 或者_proto_

// Object.getPrototypeOf會返回原型對象,但看起來跟普通構造函數沒區別
console.log(Object.getPrototypeOf(food1)); // 返回 Food {}

// 所以一般會使用這個方式來判斷原型對象是否一致
console.log(Object.getPrototypeOf(food1) === Food.prototype); // 返回 true
// 或者這個方式,isPrototypeOf會直接判斷
console.log(Food.prototype.isPrototypeOf(food1)) // 返回 true
1.3 為什么能夠通過原型模式來解決問題呢?

原型的作用主流程:

在 javascript 里面,創建一個新函數(對象),都會在創建過程里面增加一個prototype屬性,也就是原型屬性,這個屬性指向構造函數的原型對象,例如food1prototype屬性指向Food的原型對象Food prototype

而這個被指向的原型對象里面也會自動獲得一個constuctor構造函數屬性,這個屬性里面包含了一個指向,指向之前被創建的對象的prototype屬性的所在位置,相當于原型對象是母體,被創建的對象會關聯到母體身上,

javascript 解析器讀取到對象之后,會執行一次搜索,如果在當前對象上沒有搜索到目標屬性的話,就會繼續搜索指針指向的原型對象,會不斷逐級查找(原型對象),直至找到為止。

參考前面所說的原型,constructor 和 prototype 的內容來理解

在《javascript 高級程序設計》第三版里面的有一幅圖:

person1 和 person2 都是實例, Person 是構造函數,Person Prototype 是 Person 構造函數的原型對象。

person1或者 person2 的[[Prototype]]都指向了Person Prototype

問什么這里會有一條線指向了構造函數?

因為Person 構造函數的prototype 指向了Person Prototype,而Person Prototypeconstructor 也指向了Person 構造函數,他們之間通過這樣來互相確認“關聯狀態”,但僅僅互相確認關系而已(因為 constructor 容易被改變)。

類比到我們的 Food 例子里面去,food1和 FoodFood Prototype的關系就跟 person1和 person2和PersonPerson Prototype 的關系是一樣的。
二、 對于原型的一些使用技巧

① 如果需要查找這個實例對象的原型的話,可以使用Object.getPrototypeOf ,他會返回整個原型對象。

function Food() {}

Food.prototype.name = "蘋果";

Food.prototype.sayName = function() {
  console.log("我是" + this.name);
};

var food1 = new Food();
console.log(Object.getPrototypeOf(food1)) // 返回 Food { name: "蘋果", sayName: [Function] }

② 只能通過對象實例訪問保存在原型的值,不能通過對象實例來重寫原型中的值。
③ 對象實例可以重寫從原型對象中“繼承”過來的同名屬性,這時候會切斷對象實例和原型對象的某個同名屬性的聯系,如果想恢復聯系即恢復沒改過的同名屬性的話,可以使用delete刪除對象實例的某個屬性。
hasOwnProperty()方法可以檢測一個屬性是存在于實例中還是存在于原型中。

function Food() {}

Food.prototype.name = "蘋果";

Food.prototype.sayName = function() {
  console.log("我是" + this.name);
};

var food1 = new Food();

console.log(food1.hasOwnProperty("name")); // 返回 false
food1.name = "bilibili"; // 設置 food1的 name 屬性(也就是改寫從原型對象繼承過來的 name 屬性)
console.log(food1.hasOwnProperty("name")); // 返回 true
console.log(food1.name); // 返回 bilibili

⑤ 更簡單的原型寫法

function Food() {}

Food.prototype = {
  constructor: Food, // 這里需要注意
  name: "蘋果",
};

如果不寫constructor的話,Food.prototype constructor就不再指向 Food ,這樣就沒辦法通過constructor來識別得到改對象實例是屬于哪個原型對象了。

以這種方式編寫原型的時候,如果主動設置constructor,對象的[[Enumerable]] 可遍歷屬性就會被設置為 true,代表可以被遍歷。

⑥ 在原型對象上直接編輯修改,會即時反應到實例對象上,所以可以隨時進行修改,很方便。
⑦ 如果重寫原型對象,要注意原型對象的指向問題:

// 原型鏈會被切斷
function Food() {
}
var food1 = new Food("蘋果"); // 繼續指向原來的 Food.prototype(最初的那個原型對象)
// 重寫Food.prototype
Food.prototype = {
  constructor: Food,
  name: "蘋果",
};
console.log(food1.name); // 返回 undefined
// 原型鏈不會被切斷
function Food() {
}
// 先重寫Food.prototype
Food.prototype = {
  constructor: Food,
  name: "蘋果",
};
// 再實例化對象
var food1 = new Food("蘋果"); // 指向新的被重寫后的Food.prototype
console.log(food1.name); // 返回 蘋果

在 new 創建完實例之后,實例的原型對象是構造函數的原型對象,如果在這時候重寫了構造函數的原型對象的話,那么原來實例跟原來構造函數的原型對象的鏈接就會被切斷,就無法使用原型對象上的數據了。

三、文末我們又遇到了新問題了

用了原型模式之后,雖然解決了遇到的一系列問題,但也帶來了一些新的副作用(怎么副作用那么多。。。。。),原型模式的共享特性帶來了方便之余,也造成了一些困擾,如果我們需要一些不想共享的信息,例如 food1 的原產地是巴西,印度,非洲,food2的原產地是巴西,印度,俄羅斯,他們之間有一些區別,不能完全共享,那么怎么辦呢?

會通過組合使用構造函數模式和原型模式或者動態原型模式來解決,下回分解。

參考內容

紅寶書,《javascript 高級程序設計第三版》

版權信息
作者: 慫如鼠
網站: https://www.whynotbetter.com
本作品著作權歸作者所有,商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

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

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

相關文章

  • 我來重新學習 javascript 面向對象part 1)

    摘要:其實在之前的工廠模式里面,也存在這個問題,不過工廠模式更徹底,直接完全創建一個新對象,而構造函數模式的話只是方法會被重新創建。 我來重新學習 javascript 的面向對象(part 1) 很多job 的描述都說要求精通 javascript 面向對象編程,但是根據一般的套路,寫精通其實就是熟練,寫熟練其實就是一般,寫一般其實就是懵逼! showImg(https://segment...

    myshell 評論0 收藏0
  • 我來重新學習 javascript 面向對象part 3)

    摘要:二動態原型模式動態原型模式的特點是,在構造函數里面增加判斷處理是否添加原型對象屬性。他依然有一個嚴重的問題,就是原型對象和實例和構造函數之間沒辦法關聯,這樣不適合在有一定規模復雜度的程序開發中使用。 續上一集內容,有一些數據不需要共享的時候,但是又想實現共享數據處理,魚與熊掌,都要兼得(老板就是這么霸氣),那么經過工程師們的智慧交流,他們發現現實并非那么殘酷,還有一些辦法可取的,也就是...

    Elle 評論0 收藏0
  • 我來重新學習js面向對象part 4)

    摘要:我是的可以改變函數的對象的指向拋出異常,沒有這個因為子類和超類都是構造函數,那么就會有之前說的,構造函數在的時候,里面的方法函數會重復創建實例,導致資源浪費。 我來重新學習js 的面向對象(part 4) 續上一篇,隨著業務越來越大,要考慮一些繼承的玩意了,大千世界,各種東西我們要認識和甄別是需要靠大智慧去分門別類,生物學中把動植物按界、門、綱、目、科、屬、種進行分類的方法可能是最有代...

    MAX_zuo 評論0 收藏0
  • 我來重新學習js 面向對象part 5)

    摘要:無限增殖返回蘋果返回香蕉返回返回使用的新語法方法會創建一個新對象,使用現有的對象來提供新創建的對象的。是新增的,用來規范原型式繼承。這里將返回的新對象放到子類的原型對象里面,這樣子類就擁有了父類的原型對象,也就實現了方法的繼承。 這是最后的最后了,我會順便總結一下各種繼承方式的學習和理解。(老板要求什么的,管他呢) 一、繼承-組合繼承、偽經典繼承 showImg(https://seg...

    BicycleWarrior 評論0 收藏0
  • 2017年 最好javascript 書籍

    摘要:請記住,這些書中的一些可能不是最新的,但概念和基礎仍應適用。是最好的老師之一。的秘密由部分組成。在你完成這些書后,查看書籍和最好的本土書籍。 我看過三本,第1本,第二本,第四本。第一本買的的實體書,其他兩本看的是電子書。第一本是大名鼎鼎老道寫的,書很薄,但是非常經典。javascirpt忍者秘籍是jquery的作者寫的,也是非常經典。you dont kown js系列也是非常好。看了...

    mingzhong 評論0 收藏0

發表評論

0條評論

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