因爲函數也是值,因此能夠做爲對象的屬性。把函數放在對象內部有兩個主要理由,第一個理由是把許多相關函數放在一組。把許多函數組合到單個對象中,有助於組織和理解大型程序。
人類不但願去嘗試理解一個擁有數百個甚至數千個函數的系統,若是一個系統只有數十個軟件組成部分,那咱們理解起來會容易不少。例如,在一個遊戲程序中,咱們會很天然地爲玩家、地貌、物理屬性、消息傳遞、裝備、圖像等分別建立出子系統,每一個都是一個很大的對象。編程
將函數做爲屬性的第二個理由是讓程序從面向過程轉向面向對象。例如,咱們不必定要將函數看做對形狀執行操做,將函數存儲爲形狀的屬性。將函數放在對象的內部,可讓人們專一於這些函數,讓函數扮演對象行爲的角色。
數組
var firstGirlfriend = { // 屬性 sex:"woman", behaviorA:function () {return ("漂亮")}, behaviorB:function () {return ("前凸後翹")}, skill:{first:"作家務",second:"按摩",thirdly:"PAPAPA"} // 方法 behaviorC:function () { return ("我會:"+this.skill.first+" | "+this.skill.second+" | ") }, test:function () {return this;} }; alert(firstGirlfriend.behaviorC()) // "我會:作家務 | 按摩 | " alert(firstGirlfriend.test()===firstGirlfriend) // true
this
我會另開一篇文章談個人理解:this
引用的是全局對象。this
引用根據函數調用方式不一樣而有所不一樣。接收方對象:
經過點運算符或中括號運算符調用對象的方法時,在運算符左側所指定的對象。var obj = { x:3, doit:function () {alert("method is called."+this.x);} }; obj.doit(); // 對象obj時接收方對象。doit是方法 obj["doit"](); // 同上
回到我們的"妹子"那兒,我想知道妹子有有什麼技能,因此我用一個方法(behaviorC()
)讓她本身說出來,這時誰是接收方呢?沒錯,是妹子firstGirlfriend
,妹子本身說本身會什麼嘛,固然是她本身了,test()
也證實了函數
方法中,this.skill.first
,先肯定this
引用的對象,而後讀取屬性值,最後成爲全局函數alert的傳入值,被彈出。學習
好了大概知道this是什麼咱們就要繼續了。this
們
:var GirlfriendPlant = function (s) { return { sex:s, behaviorA:function () {return ("漂亮")}, behaviorB:function () {return ("前凸後翹")}, skill:{first:"作家務",second:"按摩",thirdly:"PAPAPA"}, // 方法 behaviorC:function () { return ("我會:"+this.skill.first+" | "+this.skill.second+" | ") }, test:function () {return this;} }; }; var girl_a = GirlfriendPlant("woman"); var girl_b = GirlfriendPlant("man"); alert(girl_a.behaviorB()); // "前凸後翹" alert(girl_b.sex+" | "+girl_b.behaviorC("man | 我會:作家務 | 按摩 | ")); // :)
瞧,是否是不用一個一個的寫啦?並且我還高度定製了一些"功能",好比......咳咳,我是異性戀,可是男生力氣大作家務也快不是?
可是!仍是有不足的地方,每一個妹子出生就自帶這些技能和屬性了,但是有些妹子是不肯學習某些技能的,好比一些方法,一些屬性也不想表露出來,怎麼辦?spa
這段代碼看上去沒問題,卻有一個嚴重缺陷,每次建立一個對象,都另行建立了額外的屬性、方法。在建立多個對象時,會浪費大量的內存來保存這些函數方法的冗餘副本,這是很糟糕的事情,由於內存資源是有限的。當腳本耗盡內存就會崩潰。可是,咱們還有一個方法來解決它們!
// 工廠設置製造車間,protoMGP對象表明一個技能屬性坑齊全可是未命名未定製的妹子 var protoMGP = { sex:undefined, behaviorA:function () {return ("漂亮")}, behaviorB:function () {return ("前凸後翹")}, skill:{first:undefined,second:undefined,thirdly:undefined}, // 方法 behaviorC:function () { alert("我會:"+this.skill.first+" | "+this.skill.second+" | "+this.skill.thirdly); } }; // 工廠參數輸入車間 var middleGirlPlant = function (sex,f,s,t) { // 得到車間製造的妹子(對象),注意得到的只是粗胚,爲設置參數,但已經留好坑了 var girlObj = Object.create(protoMGP); // 開始定製妹子 girlObj.sex = sex; girlObj.skill.first = f; girlObj.skill.second = s; girlObj.skill.thirdly = t; // 返回定製好的妹子(對象) return girlObj; }; //如今開始製造妹子 var gA = middleGirlPlant("woman","洗衣","作飯","LOL"); console.log(gA.skill.first+" | "+gA.skill.second+" | "+gA.skill.thirdly); // "洗衣 | 作飯 | LOL" var gB = middleGirlPlant("man","Java","C","JavaScript"); console.log(gB.skill.first+" | "+gB.skill.second+" | "+gB.skill.thirdly); // "Java | C | JavaScript"
看,咱們的妹子不但知足自定義屬性方法,而且這些屬性方法並不保存在每一個妹子對象上,而是在她們的工廠中,只要須要隨時能夠調用它們。(好吧這裏實在抽象不起來了)prototype
middleGirlPlant
建立的對象都有本身的sex
、skill
、behaviorA()
、behaviorB()
、behaviorC()
屬性,方法,這些屬性方法是由每一個對象裏的prototype
引用的對象提供的,每一個對象的隱藏連接都指向惟一共享原型,其中包含了上面所述的那些屬性方法。不過還有一個小小缺陷。咱們使用了兩個全局變量middleGirlPlant
、protoMGP
。若是有一個就更好了,這樣咱們的原型做爲函數的一個屬性(對象)。接下來,就是引出new
這個構造器了。JavaScript中的每一個函數對象都自動包含一個
prototype
屬性,prototype
是函數兩個預約義屬性中的第二個,第一個length
。只要函數一經定義,它的prototype
屬性就會被初始化爲一個全新對象。(這個全新對象有本身的一個屬性,叫作constructor
)。
// 建立構造函數highGirlfactory function highGirlfactory(s) { this.sex = s; var test = "哇哈哈,我有女友啦!!!!"; return test; }; // 構造函數的prototype(原型) highGirlfactory.prototype.behaviorA = function (a,b,c) { this.first = a; this.second = b; this.thirdly = c; }; // 構造函數的prototype(原型) highGirlfactory.prototype.behaviorB = function () { console.log("我會:"+this.first+this.second+this.thirdly); }; // GirlA對象 var GirlA = new highGirlfactory("woman"); GirlA.behaviorA("Ax","Ay","Az"); GirlA.behaviorB(); // "我會:AxAyAz" // GirlB對象 var GirlB = new highGirlfactory("woman"); GirlB.sex = "SEX"; console.log(GirlB.sex) // "SEX" // --- var Test = highGirlfactory(); alert(Test); // "哇哈哈,我有女友啦!!!!" // 原型鏈 alert(highGirlfactory.prototype.constructor===highGirlfactory) // true alert(GirlA.__proto__===highGirlfactory.prototype) // true
就不廢話了.....當你使用new操做符,就無需明確連接(Object.create
)原型,也無需返回新建立的對象。當你在函數調用以前加上了new
時,會發生什麼?引自《JavaScript程序設計》《JavaScript編程全解》設計
new
表達式的值是(被生成的)對象的引用。經過new
表達式調用的構造函數內的this
引用,引用了(被新生成的)對象。new
表達式後,會隱式生成一個新對象,可是對象不是賦值的,是引用的,因此說完就是生成了一個新對象的引用,代碼中就是var GirlA = new highGirlfactory("woman")
將這個引用賦值給了變量GirlA
。而後!構造函數裏的(this引用)引用了新對象,嗯這樣斷句應該沒錯@_@
,這裏要提到一個以前沒說清楚的知識,this
這個功能全稱叫this
引用,咱們爲了形象點說指向。意思就是this
指向的是新對象,接收方對象就是那個新生成的對象。so.......1.
全部的函數(對象)都具備名爲prototype
的屬性(這個屬性引用的對象成爲prototype
對象)。 2.
全部的對象都含有一個(隱藏的)連接,用以指向在對象生成過程當中所使用的構造函數(Function
對象)的prototype
對象。 Object.prototype
對象。GirlB.sex = "SEX"
;這裏從新建立一個鍵值對,在console.log(GirlB.sex)
時,因爲自身屬性就存在這個鍵值對,不會在搜索到原型裏的sex屬性。關於Object.prototype
我理解不是很深,到時也會在研究一下。code
_proto_
)這個玩意兒,他就是那個神祕的隱式連接,在new
生成的新對象中,裏面的_proto_
引用的對象就是原型對象。GirlA.__proto__===highGirlfactory.prototype對象
prototype
引用的對象裏還有一個constructor
屬性,這個東東引用的是構造函數,沒錯就是本身找本身。書中是這麼寫的:highGirlfactory.prototype.constructor===highGirlfactory
能夠經過使用對象的
constructor
屬性來從對象處獲取其構造函數。若是能獲知對象的構造函數,也就可以知道該對象的原型繼承狀況了,因而即可以瞭解這個對象的一部分操做。
constructor
屬性不是對象的以前屬性,而是經過原型鏈查找到的屬性。嗯,不懂~,先暫時理解爲獲取構造函數吧(弄懂回來補充)