摘要:函數(shù)用于指定對(duì)象的行為。關(guān)于屬性只在構(gòu)造器函數(shù)的原型上才有的屬性并指向該構(gòu)造器,改寫了的原型對(duì)象默認(rèn)是沒(méi)有屬性的。函數(shù)化工廠模式在偽類模式里,構(gòu)造器函數(shù)不得不重復(fù)構(gòu)造器已經(jīng)完成的工作。
1.自定義類型--構(gòu)造函數(shù)模式(偽類模式)1.對(duì)象適合于收集和管理數(shù)據(jù),容易形成樹(shù)型結(jié)構(gòu)。
Javascript包括一個(gè)原型鏈特性,允許對(duì)象繼承另一對(duì)象的屬性。正確的使用它能減少對(duì)象的初始化時(shí)間和內(nèi)存消耗。
2.函數(shù)它們是javascript的基礎(chǔ)模塊單元,用于代碼復(fù)用、信息隱藏和組合調(diào)用。函數(shù)用于指定對(duì)象的行為。一般來(lái)說(shuō),編程就是將一組需求分解成一組函數(shù)和數(shù)據(jù)結(jié)構(gòu)的技能。
3.模塊我們可以使用函數(shù)和閉包來(lái)構(gòu)造模塊。模塊是一個(gè)提供接口卻隱藏實(shí)現(xiàn)狀態(tài)和實(shí)現(xiàn)的函數(shù)或?qū)ο蟆?/p>
在基于類的系統(tǒng)中,對(duì)象是這樣定義的:使用類來(lái)描述它是什么樣的。假如建筑是基于類的系統(tǒng),則建筑師會(huì)先畫出房子的藍(lán)圖,然后房子都按照該藍(lán)圖來(lái)建造。
在使用自定義類型模式實(shí)現(xiàn)繼承的時(shí)候,我們只需要將參數(shù)傳遞給構(gòu)造函數(shù),然后將參數(shù)掛載在實(shí)例對(duì)象上。其他關(guān)于實(shí)例對(duì)象的方法都不用傳遞參數(shù),因?yàn)橥ㄟ^(guò) 實(shí)例對(duì)象調(diào)用的方法內(nèi)部的this都可以訪問(wèn)到該參數(shù)。掛載在實(shí)例this對(duì)象上的變量稱為實(shí)例變量。
組合--繼承function Person (name, age, job) { // 實(shí)例變量 this.name = name; this.age = age; this.job = job; } Person.prototype.sayName = function () { alert(this.name); } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
function SuperType (name) { this.name = name; this.colors = ["red","blue", "green"]; } SuperType.prototype.sayName = function () { console.log(this.name); } function SubType (name, age) { // 繼承屬性 SuperType.call(this,name); this.age = age; } // 繼承方法 SubType.prototype = new SuperType(); SubType.prototype.sayAge = function () { console.log(this.age) } var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black") console.log(instance1.colors); instance1.sayName(); instance1.sayAge(); var instance2 = new SubType("Greg", 27) console.log(instance2.colors); instance2.sayName(); instance2.sayAge();
在繼承屬性和繼承方法上,我們一共調(diào)用了兩次超類構(gòu)造函數(shù),當(dāng)通過(guò)new調(diào)用超類構(gòu)造函數(shù)創(chuàng)建子類構(gòu)造函數(shù)的原型時(shí),有一個(gè)問(wèn)題,子類構(gòu)造函數(shù)的原型對(duì)象現(xiàn)在便是超類構(gòu)造函數(shù)的實(shí)例,因此也會(huì)有在超類構(gòu)造函數(shù)為實(shí)例對(duì)象this添加的屬性,只是值為undefined而已,也就是說(shuō)通過(guò)new調(diào)用超類構(gòu)造器函數(shù)來(lái)更改子類改造器的原型時(shí),那么在子類構(gòu)造器的原型上便會(huì)有多余的屬性。這便造成了浪費(fèi)。而我們需要的其實(shí)只是,子類構(gòu)造器的原型能夠繼承超類構(gòu)造器原型的方法而已。因此我們需要的,1.創(chuàng)建一個(gè)子類構(gòu)造器原型對(duì)象。2.此子類構(gòu)造器原型繼承自超類構(gòu)造器的原型。3.因?yàn)槲覀冊(cè)?中改寫了子類構(gòu)造器的原型對(duì)象,也就是重新創(chuàng)建了原型對(duì)象,因此我們需要在新創(chuàng)建的原型對(duì)象上添加constructor屬性并將其賦值為子類構(gòu)造器函數(shù)。
將上面的代碼改寫一些,如下所示。
關(guān)于constructor屬性:只在構(gòu)造器函數(shù)的原型上才有的屬性并指向該構(gòu)造器,改寫了的原型對(duì)象默認(rèn)是沒(méi)有constructor屬性的。
寄生組合式--繼承function inheritPrototype (subType,superType) { var prototype = Object.create(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; }; function SuperType (name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function () { console.log(this.name); } function SubType(name, age) { //繼承屬性 SuperType.call(this,name); this.age = age; } //繼承方法 inheritPrototype(SubType,SuperType); SubType.prototype.sayAge = function () { console.log(this.age); } var instance = new SubType();
通過(guò)隱藏那些所謂的prototype操作細(xì)節(jié),現(xiàn)在看起來(lái)沒(méi)那么怪異了。但是否真的有所發(fā)現(xiàn):
沒(méi)有私有環(huán)境,所有屬性都是公開(kāi)的。無(wú)法訪問(wèn)父類的方法。難以調(diào)試
在一個(gè)純粹的原型模式中,我們會(huì)擯棄類,轉(zhuǎn)而專注對(duì)象?;谠偷睦^承相比基于類的繼承在概念上更簡(jiǎn)單:一個(gè)新對(duì)象可以繼承一個(gè)舊對(duì)象的屬性。你通過(guò)構(gòu)造有用的對(duì)象開(kāi)始,接著可以構(gòu)造更多和那個(gè)對(duì)象類似的對(duì)象。這就可以完全避免把一個(gè)應(yīng)用拆解成一系列嵌套抽象類的分類過(guò)程
在基于原型的系統(tǒng)中,我們創(chuàng)建的對(duì)象,看起來(lái)要像我們想要的所有這種類型的對(duì)象那樣,然后告訴javascript引擎,我們想要更多像這樣的對(duì)象。如果建筑是基于原型的,建筑師會(huì)先建一所房子,然后將房子都建成像這種模樣的。
方法Object.creat()作為new操作符的替代方案,使用它來(lái)創(chuàng)建javascript對(duì)象時(shí),能增添一種更像是基于原型的感覺(jué)。
function myMammal = { name : "Herb the Mammal", get_name : function () { return this.name; }, says : function () { return this.saying || ""; } } var myCat = Object.create(myMammal); myCat.name = "Henrietta"; myCat.saying = "meow"; myCat.purr = function (n) { var i, s = ""; for (i = 0;i < n; i += 1) { if(s) { s += "-" } s += "r"; } return s; } myCat.get_name = function () { return this.says + " " + this.name + this.says; }
這是一種"差異化繼承"。通過(guò)定制一個(gè)新的對(duì)象,我們指明它與所基于的基本對(duì)象的區(qū)別。
有時(shí)候,它對(duì)某些數(shù)據(jù)結(jié)構(gòu)繼承于其他數(shù)據(jù)結(jié)構(gòu)的情形非常有用。
在偽類模式里,構(gòu)造器函數(shù)Cat不得不重復(fù)構(gòu)造器Mammal已經(jīng)完成的工作。在函數(shù)化模式中那不再需要了,因?yàn)闃?gòu)造器Cat將會(huì)調(diào)用構(gòu)造器Mammal,讓Mammal去做對(duì)象創(chuàng)建中的大部分工作,所有Cat只關(guān)注自身的差異即可。
函數(shù)化模式有很大的靈活性。它相比偽類模式不僅帶來(lái)的工作更少,還讓我們得到更好的封裝和信息隱藏,以及訪問(wèn)父類方法的能力。
如果我們用函數(shù)化得樣式去創(chuàng)建對(duì)象,并且該對(duì)象的所有方法都不用this或that,那么該對(duì)象就是持久性的。一個(gè)持久性的對(duì)象就是一個(gè)簡(jiǎn)單功能函數(shù)的集合。
私有變量:任何在函數(shù)中定義的變量,都可以認(rèn)為是私有變量,因?yàn)椴荒茉诤瘮?shù)外部訪問(wèn)這些變量。
閉包
閉包是阻止垃圾回收器將變量從內(nèi)存中移除的方法,使的在創(chuàng)建變量的執(zhí)行環(huán)境的外面能夠訪問(wèn)到該變量。
請(qǐng)記住:閉包由函數(shù)創(chuàng)建。每次調(diào)用函數(shù)會(huì)創(chuàng)建一個(gè)唯一的執(zhí)行環(huán)境對(duì)象。函數(shù)執(zhí)行完后,執(zhí)行對(duì)象就會(huì)被丟棄,除非調(diào)用者引用了它。當(dāng)然,如果函數(shù)返回的是數(shù)字,就不能引用函數(shù)的執(zhí)行環(huán)境對(duì)象。但是如果函數(shù)返回的是一個(gè)更復(fù)雜的結(jié)構(gòu),像是函數(shù)、對(duì)象或者數(shù)組,將返回值保存到一個(gè)變量上,就創(chuàng)建了一個(gè)對(duì)執(zhí)行環(huán)境的引用。
Function.prototype.method = function (name,func) { this.prototype[name] = func; return this; } // 工廠mammal函數(shù) var mammal = function (spec) { var that = {}; that.get_name = function () { return spec.name; } that.says = function (spec) { return spec.saying || ""; } return that; } // 工廠cat函數(shù)(基于mammal的函數(shù)) var cat = function (spec) { spec.saying = spec.saying || "meow"; var that = mammal(spec); that.purr = function (n) { var i, s = ""; for (i = 0; i < n; i += 1) { if(s) { s += "-"; } s += "r"; } } that.get_name = function () { return that.says() + " " + spec.name + " " + that.says(); } return that; } // 創(chuàng)建myCat對(duì)象 var myCat = cat({name: "Henrietta"}); Object.method("superior",function (name) { var that = this, method = that[name]; return function () { return method.apply(that, arguments) } }) // 工廠coolcat函數(shù)(基于cat函數(shù)) var coolcat = function (spec) { var that = cat(spec), super_get_name = that.superior("get_name"); that.get_name = function (n) { return "like " + super_get_name() + " baby"; } return that; } var myCoolCat = coolcat({name : "Bix"}); var name = myCoolCat.get_name();
函數(shù)化模塊模式有很大的靈活性。它相比構(gòu)造函數(shù)模式不僅帶來(lái)的工作更少,還讓我們得到更好的封裝休息和隱藏,以及訪問(wèn)父類方法的能力。如果對(duì)象的所有狀態(tài)都是私有的,那么該對(duì)象就成為一個(gè)"防偽(tamper-proof)"對(duì)象。該對(duì)象的屬性是可以被替換或者刪除,當(dāng)該對(duì)象的完整性不會(huì)受到損壞。我們用函數(shù)式的樣式創(chuàng)建一個(gè)對(duì)象,并且該對(duì)象的所有方法都不使用this或者that,那么該對(duì)象就是持久性對(duì)象。一個(gè)持久性對(duì)象,就是一個(gè)簡(jiǎn)單的函數(shù)功能的集合。
一個(gè)持久性的對(duì)象不會(huì)被入侵。訪問(wèn)一個(gè)持久性的對(duì)象時(shí),除非有方法授權(quán),否則攻擊者不會(huì)訪問(wèn)對(duì)象的內(nèi)部狀態(tài)。
前面的模式是用于 自定義類型創(chuàng)建私有變量和特權(quán)方法的。而道格拉斯所說(shuō)的模塊模式則是為 單例創(chuàng)建私有變量和特權(quán)方法。所謂單例指的就是只有一個(gè)實(shí)例的對(duì)象。(就是用對(duì)象字面量表示法創(chuàng)建的對(duì)象)
var singleton = function () { // 私有變量和函數(shù) var privateVariable = 10; function privateFunction () { return false; } //特權(quán)/公有方法和屬性 return { publicProvperty: true; publicMethod: function () { privateVariable++; return privateFunction(); } } }
從本質(zhì)上講,這個(gè)對(duì)象字面量定義的是單例的公共接口。這種模式在需要對(duì)單例進(jìn)行某些初始化,同時(shí)又需要維護(hù)其私有變量時(shí)非常有用。簡(jiǎn)言之,如果必須創(chuàng)建一個(gè)對(duì)象并以某些數(shù)據(jù)對(duì)其進(jìn)行初始化,同時(shí)還要公開(kāi)一些能夠訪問(wèn)這些私有數(shù)據(jù)的方法。
增強(qiáng)的模塊模式這種增強(qiáng)的模塊模式適合那些單例必須是某種類型的實(shí)例,同時(shí)還必須添加某些屬性和方法對(duì)其加以增強(qiáng)的例子。
var singleton = function () { // 私有變量和函數(shù) var privateVariable = 10; function privateFunction () { return false } // 創(chuàng)建對(duì)象 var object = new CustomType(); // 添加特權(quán)/公有屬性和方法 object.publicProperty = true; object.publicMethod = function () { privateVariable++; return privateFunction(); } return object; }()
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/78647.html
摘要:二正文中與的區(qū)別接口只聲明成員方法,不做實(shí)現(xiàn)。在中,我們可以采用全新的基于類繼承的模式設(shè)計(jì)更優(yōu)雅的語(yǔ)義化接口,這是因?yàn)橹械目梢岳^承動(dòng)態(tài)構(gòu)造的類,這一點(diǎn)和其他的靜態(tài)聲明類的編程語(yǔ)言不同。 一 前言 1.在typescript上遇到過(guò)實(shí)例化對(duì)象的兩種寫法:implement和extends。extends很明顯就是ES6里面的類繼承,那么implement又是做什么的呢?它和extends...
摘要:在類內(nèi)部的方法中使用時(shí)。類的私有方法兩個(gè)下劃線開(kāi)頭,聲明該方法為私有方法,不能在類地外部調(diào)用。先在本類中查找調(diào)用的方法,找不到才去基類中找。如果在繼承元組中列了一個(gè)以上的類,那么它就被稱作多重繼承。 類定義 類對(duì)象:創(chuàng)建一個(gè)類之后,可以通過(guò)類名訪問(wèn)、改變其屬性、方法 實(shí)例對(duì)象:類實(shí)例化后,可以使用其屬性,可以動(dòng)態(tài)的為實(shí)例對(duì)象添加屬性(類似javascript)而不影響類對(duì)象。 類...
摘要:類的方法相當(dāng)于之前我們定義在構(gòu)造函數(shù)的原型上。的構(gòu)造函數(shù)中調(diào)用其目的就是調(diào)用父類的構(gòu)造函數(shù)。是先創(chuàng)建子類的實(shí)例,然后在子類實(shí)例的基礎(chǔ)上創(chuàng)建父類的屬性。 前言 首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒(méi)法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì)。 許久已經(jīng)沒(méi)有寫東西了,因?yàn)殡s七雜八的原因最近一直沒(méi)有抽出時(shí)間來(lái)把寫作堅(jiān)持下來(lái),感覺(jué)和跑步一...
摘要:從原型對(duì)象指向構(gòu)造函數(shù)畫一條帶箭頭的線。線上標(biāo)注,表示該原型對(duì)象的構(gòu)造函數(shù)等于。但除此之外,若構(gòu)造函數(shù)所指的顯示原型對(duì)象存在于的原型鏈上,結(jié)果也都會(huì)為。執(zhí)行構(gòu)造函數(shù),并將指針綁定到新創(chuàng)建的對(duì)象上。 做前端開(kāi)發(fā)有段時(shí)間了,遇到過(guò)很多坎,若是要排出個(gè)先后順序,那么JavaScript的原型與對(duì)象絕對(duì)逃不出TOP3。 如果說(shuō)前端是海,JavaScript就是海里的水 一直以來(lái)都想寫篇文章梳理...
摘要:的類與繼承的類與一般的面向?qū)ο笳Z(yǔ)言有很大的不同,類的標(biāo)識(shí)是它的構(gòu)造函數(shù),下面先定義一個(gè)類顯然我們可以看出這兩個(gè)函數(shù)是不同的,雖然它們實(shí)現(xiàn)了相同的功能。利用構(gòu)造函數(shù)來(lái)繼承上面的方法子類顯然無(wú)法繼承父類的原型函數(shù),這樣不符合我們使用繼承的目的。 javascript的類與繼承 javascript的類與一般的面向?qū)ο笳Z(yǔ)言有很大的不同,類的標(biāo)識(shí)是它的構(gòu)造函數(shù),下面先定義一個(gè)類 var ...
閱讀 1497·2021-11-25 09:43
閱讀 3828·2021-11-10 11:48
閱讀 5573·2021-09-23 11:21
閱讀 1684·2019-08-30 15:55
閱讀 3601·2019-08-30 13:53
閱讀 1348·2019-08-30 10:51
閱讀 954·2019-08-29 14:20
閱讀 2057·2019-08-29 13:11