摘要:本質上是摒棄類,不調用構造函數,而是用,直接讓新對象繼承舊對象的屬性。基于類型的繼承基于類型的繼承是通過構造函數依賴于原型的繼承,而非依賴于對象。例如需要通過來訪問基類的構造函數繼承自。
JavaScript作為一門語法比較松散的語言,在ES6之前并沒有像C++/Java等傳統OO語言一樣有class關鍵字,也不能通過private,public等關鍵字來限定權限。本篇就介紹一下JavaScript是如何實現繼承的(js的繼承說白了只是一種思想上的繼承,在代碼級別并沒有像java的天然繼承,在編寫js的時候采用oo思想,能更簡單的優化和擴展代碼)。
JavaScript的繼承可以分為兩類:
? 基于對象的繼承
? 基于類型的繼承
基于對象的繼承
基于對象的繼承也叫原型繼承。我們知道通過JavaScript字面量創建的對象都會連接到Object.prototype,因此我們用Object.prototype來實現繼承。本質上是摒棄類,不調用構造函數,而是用Object.create(),直接讓新對象繼承舊對象的屬性。例如:
var person = { name: "Jack", getName: function () { return this.name; } } var p1 = Object.create(person); console.log(p1.getName()); //Jack
代碼很簡單,person有一個屬性和一個方法。對象p1通過Object.create()來繼承,第一個參數prototype指向person的prototype,這樣對象p1就繼承了person的屬性和方法。
Object.create()還可以指定第二個參數,即數據屬性,將其添加到新對象中。數據屬性可設4個描述符value, writable,enumerable,configurable 。后3個看名字也能猜出意思,不指定的話默認為false。因為和本篇關系不大,就不跑題了,只看看設置value的情況:
var p2 = Object.create(person, { name: { value: "Zhang" } }); console.log(p2.getName()); //Zhang
用Object.create()相當于創建了一個全新的對象,你可以給該對象任意新增,重載它的屬性和方法:
var person = { name: "Jack", getName: function () { return this.name; }, getAge: function() { return this.age; } //注意并沒有age這個成員變量,依賴子類實現 } var p3 = Object.create(person); p3.name = "Rose"; p3.age = 17; p3.location = "上海"; p3.getLocation = function() { return this.location; } console.log(p3.getName()); //Rose console.log(p3.getAge()); //17 console.log(p3.getLocation()); //上海
在person中并沒有age這個屬性,因此你調用person.getAge();將得到undefined。但在對象p3里新定義了age這個屬性,于是就能正確地調用基類的getAge方法。另外子類重載了name的值,且新定義了location屬性和getLocation方法。結果如上所示,不贅述。
基于類型的繼承
基于類型的繼承是通過構造函數依賴于原型的繼承,而非依賴于對象。例如:
function Person(name) { this.name = name; this.getName = function () { return this.name; }; } function Student(name, age) { Person.call(this, name); this.age = age; this.getAge = function () { return this.age; }; } Student.prototype = new Person(); //需要通過new來訪問基類的構造函數 var p = new Person("Cathy"); var s = new Student("Bill", 23); console.log(p.getName()); //Cathy console.log(s.getName()); //Bill console.log(s.getAge()); //23
Student繼承自Person。name雖然是在基類Person里被定義的,但用new調用Person的構造函數后,this將被綁定到子類Student對象上,因此name最終是定義在子類Student對象上的。結果如上所示,不贅述。
保護隱私
之所以定義getName,getAge等方法就是不想讓用戶直接訪問name,age等屬性。可惜上面兩種繼承均無法保護隱私,均可像p.name,p.age這樣直接訪問屬性。如果認為這些屬性的隱私非常重要,希望模擬出OO語言中private屬性的效果,可以用函數模塊化。
所謂函數模塊化,本質上就是在函數內新建一個對象,新對象的方法里使用參數對象的屬性,然后將新對象返回。此時新對象里是沒有參數對象的屬性的,達到了保護隱私的目的。代碼如下:
var person = function(spec) { var that = {}; //新對象 that.getName = function () { return spec.name; }; //使用參數的屬性 that.getAge = function() { return spec.age; }; //使用參數的屬性 return that; //返回新對象 } var p4 = person({name: "Jane", age: 20}); console.log(p4.name); //undefined console.log(p4.age); //undefined console.log(p4.getName()); //Jane console.log(p4.getAge()); //20
因為函數person返回的是新對象that,而that里并沒有name和age屬性,因此直接訪問會得到undefined。只能通過that暴露出的兩個接口來獲取name和age。
進一步實現多層繼承也非常方便,效果如下,不贅述:
var student = function(spec) { var that = person(spec); //新對象繼承自person that.getRole = function() { return "student"; }; //新對象增加方法 that.getInfo = function() { return spec.name + " " + spec.age + " " + that.getRole(); }; return that; //返回新對象 }; var p5 = student({name:"Andy", age:12}); console.log(p5.name); //undefined console.log(p5.getName()); //Andy console.log(p5.getRole()); //student console.log(p5.getInfo()); //Andy 12 student
更多資源上:去轉盤;或者加我的QQ群參與js,css的討論學習(QQ群:512245829)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80159.html
摘要:繼承的是超類型中構造函數中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結果是子類型實例中有兩組超類型的構造函數中定義的屬性,一組在子類型的實例中,一組在子類型實例的原型中。 ECMAScript只支持實現繼承,主要依靠原型鏈來實現。與實現繼承對應的是接口繼承,由于script中函數沒有簽名,所以無法實現接口繼承。 一、原型鏈 基本思想:利用原型讓一個引用類型繼承另一個引用...
摘要:而作為構造函數,需要有個屬性用來作為以該構造函數創造的實例的繼承。 歡迎來我的博客閱讀:「JavaScript 原型中的哲學思想」 記得當年初試前端的時候,學習JavaScript過程中,原型問題一直讓我疑惑許久,那時候捧著那本著名的紅皮書,看到有關原型的講解時,總是心存疑慮。 當在JavaScript世界中走過不少旅程之后,再次萌發起研究這部分知識的欲望,翻閱了不少書籍和資料,才搞懂...
摘要:使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承。總結實現繼承有種方式原型鏈繼承借用構造函數繼承組合繼承原型式繼承寄生式繼承寄生組合式繼承寄生組合式繼承是大家公認的最好的實現引用類型繼承的方法。 簡介 本文不準備深入細節,主要是對《JavaScript高級程序設計中》介紹的JS如何實現繼承做一個總結,畢竟好記性不如爛筆頭。文末會附帶一張神圖,搞清楚這張圖,...
摘要:面向對象中有三大特征,封裝,繼承,多態。這不僅無法做到數據共享,也是極大的資源浪費,那么引入對象實例對象的屬性指向其構造函數,這樣看起來實例對象好像繼承了對象一樣。實例對象的原型指向其構造函數的對象構造器的指向。 前言 為什么說是再談呢,網上講解這個的博客的很多,我開始學習也是看過,敲過就沒了,自以為理解了就結束了,書到用時方恨少啊。實際開發中一用就打磕巴,于是在重新學習了之后分享出來...
摘要:對象重新認識面向對象面向對象從設計模式上看,對象是計算機抽象現實世界的一種方式。除了字面式聲明方式之外,允許通過構造器創建對象。每個構造器實際上是一個函數對象該函數對象含有一個屬性用于實現基于原型的繼承和共享屬性。 title: JS對象(1)重新認識面向對象 date: 2016-10-05 tags: JavaScript 0x00 面向對象 從設計模式上看,對象是...
閱讀 3887·2021-09-27 13:36
閱讀 4592·2021-09-22 15:12
閱讀 3067·2021-09-13 10:29
閱讀 1837·2021-09-10 10:50
閱讀 2365·2021-09-03 10:43
閱讀 526·2019-08-29 17:10
閱讀 449·2019-08-26 13:52
閱讀 3258·2019-08-23 14:37