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

資訊專欄INFORMATION COLUMN

JS中的繼承(上)

Fundebug / 3546人閱讀

摘要:中的繼承上學過或者之類語言的同學應該會對的繼承感到很困惑不要問我怎么知道的的繼承主要是基于原型的對的原型感興趣的同學可以了解一下我之前寫的中的原型對象相信很多同學也跟我一樣剛開始接觸的面向對象編程的時候都抱著一種排斥的心態為什么這么

JS中的繼承(上)
學過java或者c#之類語言的同學,應該會對js的繼承感到很困惑--不要問我怎么知道的,js的繼承主要是基于原型(prototype)的,對js的原型感興趣的同學,
可以了解一下我之前寫的JS中的原型對象

相信很多同學也跟我一樣,剛開始接觸js的面向對象編程的時候,都抱著一種排斥的心態--為什么js這么麻煩?
其實了解完原型鏈后,再來看js的繼承,你會發現js的繼承其實比其他OOP語言更簡單,更靈活,我們來看一個基于原型鏈的繼承

// 父類
function Person() {}

// 子類
function Student(){}

// 繼承
Student.prototype = new Person()

我們只要把子類的prototype設置為父類的實例,就完成了繼承,怎么樣? 是不是超級簡單? 有沒有比Java,C#的清晰?
事實上,以上就是js里面的原型鏈繼承

當然,通過以上代碼,我們的Student只是繼承了一個空殼的Person,這樣視乎是毫無意義的,我們使用繼承的目的,
就是要通過繼承獲取父類的內容,那我們先給父類加上一點點簡單的內容(新增的地方標記 "http:// 新增的代碼"):

// 父類
function Person(name,age) {
  this.name = name || "unknow"     // 新增的代碼
  this.age = age || 0              // 新增的代碼
}

// 子類
function Student(name){
  this.name = name                 // 新增的代碼
  this.score = 80                  // 新增的代碼
}

// 繼承
Student.prototype = new Person()

使用

var stu = new Student("lucy")

console.log(stu.name)  // lucy    --子類覆蓋父類的屬性
console.log(stu.age)   // 0       --父類的屬性
console.log(stu.score) // 80      --子類自己的屬性

這里為了降低復雜度,我們只演示了普通屬性的繼承,沒有演示方法的繼承,事實上,方法的繼承也很簡單,
我們再來稍微修改一下代碼,基于上面的代碼,給父類和子類分別加一個方法(新增的地方標記 "http:// 新增的代碼")

// 父類
function Person(name,age) {
  this.name = name || "unknow"
  this.age = age || 0
}

// 為父類新曾一個方法
Person.prototype.say = function() {         // 新增的代碼
    console.log("I am a person")
}

// 子類
function Student(name){
  this.name = name
  this.score = 80
}

// 繼承 注意,繼承必須要寫在子類方法定義的前面
Student.prototype = new Person()

// 為子類新增一個方法(在繼承之后,否則會被覆蓋)
Student.prototype.study = function () {     // 新增的代碼
    console.log("I am studing")
}

使用

var stu = new Student("lucy")

console.log(stu.name)  // lucy               --子類覆蓋父類的屬性
console.log(stu.age)   // 0                  --父類的屬性
console.log(stu.score) // 80                 --子類自己的屬性
stu.say()              // I am a person      --繼承自父類的方法
stu.study()            // I am studing       --子類自己的方法

這樣,看起來我們好像已經完成了一個完整的繼承了,這個就是原型鏈繼承,怎么樣,是不是很好理解?
但是,原型鏈繼承有一個缺點,就是屬性如果是引用類型的話,會共享引用類型,請看以下代碼

// 父類
function Person() {
  this.hobbies = ["music","reading"]
}

// 子類
function Student(){}

// 繼承
Student.prototype = new Person()

使用

var stu1 = new Student()
var stu2 = new Student()

stu1.hobbies.push("basketball")

console.log(stu1.hobbies)   // music,reading,basketball
console.log(stu2.hobbies)   // music,reading,basketball

我們可以看到,當我們改變stu1的引用類型的屬性時,stu2對應的屬性,也會跟著更改,這就是原型鏈繼承缺點 --引用屬性會被所有實例共享,
那我們如何解決這個問題呢? 就是下面我們要提到的借用構造函數繼承,我們來看一下使用構造函數繼承的最簡單例子:

// 父類
function Person() {
  this.hobbies = ["music","reading"]
}

// 子類
function Student(){
    Person.call(this)              // 新增的代碼
}

使用

var stu1 = new Student()
var stu2 = new Student()

stu1.hobbies.push("basketball")
console.log(stu1.hobbies)   // music,reading,basketball
console.log(stu2.hobbies)   // music,reading

這樣,我們就解決了引用類型被所有實例共享的問題了

注意,這里跟 原型鏈繼承 有個比較明顯的區別是并沒有使用prototype繼承,而是在子類里面執行父類的構造函數,
相當于把父類的代碼復制到子類里面執行一遍,這樣做的另一個好處就是可以給父類傳參
// 父類
function Person(name) {
  this.name = name              // 新增的代碼
}

// 子類
function Student(name){
    Person.call(this,name)      // 改動的代碼
}

使用

var stu1 = new Student("lucy")
var stu2 = new Student("lili")
console.log(stu1.name)   // lucy
console.log(stu2.name)   // lili

看起來已經很有Java,C#的味道了有沒有?

但是,構造函數解決了引用類型被所有實例共享的問題,但正是因為解決了這個問題,導致一個很矛盾的問題出現了,--函數也是引用類型,
也沒辦法共享了.也就是說,每個實例里面的函數,雖然功能一樣,但是卻不是同一個函數,就相當于我們每實例化一個子類,就復制了一遍的函數代碼

// 父類
function Person(name) {
  this.say = function() {}    // 改動的代碼
}

// 子類
function Student(name){
    Person.call(this,name)
}

使用

var stu1 = new Student("lucy")
var stu2 = new Student("lili")
console.log(stu1.say === stu2.say)   // false

以上代碼可以證明,父類的函數,在子類的實例下是不共享的

總結
繼承方式 繼承核心代碼 優缺點
原型鏈繼承 Student.prototype = new Person() 實例的引用類型共享
構造函數繼承 在子類(Student)里執行 Person.call(this) 實例的引用類型不共享

從上表我們可以看出 原型鏈繼承構造函數繼承 這兩種繼承方式的優缺點剛好是互相矛盾的,那么我們有沒有辦法魚和熊掌兼得呢?
沒有的話,我就不會說出來了,^_^,接下來請允許我隆重介紹 組合繼承

組合繼承,就是各取上面2種繼承的長處,普通屬性 使用 構造函數繼承,函數 使用 原型鏈繼承,
這個代碼稍微復雜一點,不過相信有了上面的基礎后,看起來也是很輕松

// 父類
function Person() {
  this.hobbies = ["music","reading"]
}

// 父類函數
Person.prototype.say = function() {console.log("I am a person")}

// 子類
function Student(){
    Person.call(this)             // 構造函數繼承(繼承屬性)
}
// 繼承
Student.prototype = new Person()  // 原型鏈繼承(繼承方法)

使用

// 實例化
var stu1 = new Student()
var stu2 = new Student()

stu1.hobbies.push("basketball")
console.log(stu1.hobbies)           // music,reading,basketball
console.log(stu2.hobbies)           // music,reading

console.log(stu1.say == stu2.say)   // true

這樣,我們就既能實現屬性的獨立,又能做到函數的共享,是不是很完美呢?

組合繼承據說是JavaScript中最常用的繼承方式(具體無法考證哈).

至此,我們就把js里面的常用繼承了解完了,其實也沒有那么難嘛!不過,我們總結一下3種繼承

原型鏈繼承,會共享引用屬性

構造函數繼承,會獨享所有屬性,包括引用屬性(重點是函數)

組合繼承,利用原型鏈繼承要共享的屬性,利用構造函數繼承要獨享的屬性,實現相對完美的繼承

上面為什么要說相對完美呢? 因為本文的標題叫【JS中的繼承(上)】,那肯定是還有
【JS中的繼承(下)】.md)咯,
目前為止,我們只講了3種最基本的繼承,事實上,JavaScript還有好多繼承方式,為了讓你不至于學習疲勞,所以我打算分開來講,
如果你沒有那個耐性繼續看下去,那么看完這篇對于理解JavaScript的繼承,也是夠用的。但是建議多看兩遍,加深印象,
我學js繼承的時候,那本犀牛書都被我翻爛了,寫這篇文字的時候,我還在一遍翻一邊寫的呢(噓!)

好了,今天就到這里,感謝收看,如果覺得對您有用,請給本文的github加個star,萬分感謝,
另外,github上還有其他一些關于前端的教程和組件,有興趣的童鞋可以看看,你們的支持就是我最大的動力。

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

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

相關文章

  • JS對象繼承與原型鏈

    摘要:此用來定義通過構造器構造出來的對象的原型,構造器內部的代碼用來給對象初始化。 對象繼承 VS 類繼承 在 class-based 的面向對象的世界里,要出現對象,必須先有類。類之間可以繼承,類再使用 new 操作創建出實體,父子對象之間的繼承體現在父類和子類上。你不能說 對象 a 繼承了對象 b,只能說 class A 繼承了 class B,然后他們各自有一個實例a、b。 JS中實現...

    QLQ 評論0 收藏0
  • JS中的類與類的繼承

    摘要:首先捋清楚類和對象的關系類比如人類,指的是一個范圍對象比如某個人,指的是這個范圍中具體的對象中的作為構造函數時,就是一個類,通過操作符,可以返回一個對象。 JS中的類與類的繼承 我們知道,JS中沒有類或接口的概念,即不能直接定義抽象的類,也不能直接實現繼承。不過,為了編程的方便,我們可以在 JS 中模擬類和繼承的行為。首先捋清楚類和對象的關系: 類:比如人類,指的是一個范圍; ...

    Tangpj 評論0 收藏0
  • Javascript 設計模式讀書筆記(三)——繼承

    摘要:的繼承方式屬于原型式繼承,非常靈活。當使用關鍵字執行類的構造函數時,系統首先創建一個新對象,這個對象會繼承自構造函數的原型對象新對象的原型就是構造函數的屬性。也就是說,構造函數用來對生成的新對象進行一些處理,使這個新對象具有某些特定的屬性。 繼承這個東西在Javascript中尤其復雜,我掌握得也不好,找工作面試的時候在這個問題上栽過跟頭。Javascript的繼承方式屬于原型式繼承,...

    cangck_X 評論0 收藏0
  • javascript基礎篇:關于js面向對象的理解

    摘要:關于中面向對象的理解面向對象編程它是一種編程思想我們的編程或者學習其實是按照類實例來完成的學習類的繼承封裝多態封裝把實現一個功能的代碼封裝到一個函數中一個類中以后再想實現這個功能,只需要執行這個函數方法即可,不需要再重復的編寫代碼。 關于js中面向對象的理解 面向對象編程(oop) 它是一種編程思想 (object-oriented programming ), 我們的編程或者學習其...

    roadtogeek 評論0 收藏0
  • javascript基礎篇:關于js面向對象的理解

    摘要:關于中面向對象的理解面向對象編程它是一種編程思想我們的編程或者學習其實是按照類實例來完成的學習類的繼承封裝多態封裝把實現一個功能的代碼封裝到一個函數中一個類中以后再想實現這個功能,只需要執行這個函數方法即可,不需要再重復的編寫代碼。 關于js中面向對象的理解 面向對象編程(oop) 它是一種編程思想 (object-oriented programming ), 我們的編程或者學習其...

    newtrek 評論0 收藏0

發表評論

0條評論

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