Kotlin 擴(kuò)展函數(shù) 與 JS 的 prototype

Kotlin 擴(kuò)展函數(shù) 與 JS 的 prototype

Kotlin 擴(kuò)展函數(shù)

Kotlin的擴(kuò)展函數(shù)功能使得我們可以為現(xiàn)有的類(lèi)添加新的函數(shù),實(shí)現(xiàn)某一具體功能 暑中。
擴(kuò)展函數(shù)是靜態(tài)解析的挖胃,并未對(duì)原類(lèi)添加函數(shù)或?qū)傩粤删纾瑢?duì)類(lèi)本身沒(méi)有任何影響族淮。
擴(kuò)展屬性允許定義在類(lèi)或者kotlin文件中椭迎,不允許定義在函數(shù)中彰阴。

lambda是要作為參數(shù)被傳入某方法或賦值給某變量的匿名方法的簡(jiǎn)化表現(xiàn)形式瘾敢。

fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT){
    Toast.makeText(this, message, duration).show()
}

this指接收者對(duì)象(receiver object)(也就是調(diào)用擴(kuò)展函數(shù)時(shí), 在"."號(hào)之前指定的對(duì)象實(shí)例).

fun Any?.toString():String{
    if(this == null)
        return "null"
    else{
        return toString()
    }
}

1.擴(kuò)展(extensions)

在不修改原類(lèi)的情況下,
Kotlin能給一個(gè)類(lèi)擴(kuò)展新功能,無(wú)需繼承該類(lèi),也不用任何設(shè)計(jì)模式(如裝飾模式等),
Kotlin支持?jǐn)U展函數(shù)和擴(kuò)展屬性!

為什么要使用擴(kuò)展(動(dòng)機(jī)):
在Java中,有很多工具類(lèi)如java.util.Collections,使用很繁瑣:

// Java
Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list))

靜態(tài)導(dǎo)入Collections類(lèi),簡(jiǎn)化寫(xiě)法:

// Java
swap(list, binarySearch(list, max(otherList)), max(list))

靜態(tài)導(dǎo)入使用依然很麻煩,如果能給list類(lèi)添加擴(kuò)展函數(shù)就好了:

list.swap(list.binarySearch(otherList.max()), list.max())

2.類(lèi)-擴(kuò)展函數(shù)

1.定義

為MutableList類(lèi)擴(kuò)展一個(gè)swap函數(shù):

    fun MutableList<Int>.swap(index1: Int, index2: Int) {
        val tmp = this[index1]  //this: 當(dāng)前MutableList對(duì)象 
        this[index1] = this[index2]
        this[index2] = tmp
    }    

對(duì)MutableList對(duì)象調(diào)用swap函數(shù):

val list = mutableListOf(1, 2, 3)
list.swap(0, 2)

MutableList泛化類(lèi)型:

    //為在表達(dá)式中使用泛型,要在函數(shù)名前添加泛型參數(shù)!
    fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
        val tmp = this[index1]
        this[index1] = this[index2]
        this[index2] = tmp
    }

2.靜態(tài)解析(沒(méi)有多態(tài))

擴(kuò)展不能真正修改類(lèi),即沒(méi)有在一個(gè)類(lèi)中插入新成員!
擴(kuò)展函數(shù)是靜態(tài)解析分發(fā)的,不是虛函數(shù)(即沒(méi)有多態(tài)),調(diào)用只取決于對(duì)象的聲明類(lèi)型!
1.調(diào)用是由對(duì)象聲明類(lèi)型決定,而不是由對(duì)象實(shí)際類(lèi)型決定!

    open class C
    class D: C()
    fun C.foo() = "c"
    fun D.foo() = "d"
    fun printFoo(c: C) {
        println(c.foo()) //擴(kuò)展函數(shù)是靜態(tài)解析的,不是虛函數(shù)(即沒(méi)有多態(tài))
    }
    fun main(args: Array<String>) {
        printFoo(D()) //輸出"c",擴(kuò)展函數(shù)調(diào)用只取決于參數(shù)c的聲明類(lèi)型 
    }

2.類(lèi)的成員函數(shù)和擴(kuò)展函數(shù)-同名同參數(shù):

    class C {
        fun foo() { println("member") }
    }
    fun C.foo() {
        println("extension") 
    }
    fun main(args: Array<String>) {
        val c = C()
        println(c.foo()) //輸出“member”
    }

3.類(lèi)的成員函數(shù)和擴(kuò)展函數(shù)-同名不同參數(shù):

    class C {
        fun foo() { println("member") }
    }
    fun C.foo(i: Int) {
        println("extension")
    }
    fun main(args: Array<String>) {
        val c = C()
        println(c.foo(2)) //輸出"extension"
    }

3.可空接收者

可null的類(lèi)型定義擴(kuò)展,即使對(duì)象為null,也可在對(duì)象上調(diào)用!

 fun Any?.toString(): String {
        if (this == null) return "null"
        return toString()
    }

2.類(lèi)-擴(kuò)展屬性

和擴(kuò)展函數(shù)類(lèi)似,Kotlin也支持?jǐn)U展屬性:

    val <T> List<T>.lastIndex: Int // 不能初始化
        get() = size - 1 // 只能由getters/setters顯式提供

    val Foo.bar = 1 // 錯(cuò)誤:擴(kuò)展屬性不能有初始化器
        get() = 1

由于擴(kuò)展沒(méi)有在類(lèi)中插入新成員,因此擴(kuò)展屬性無(wú)法使用幕后字段,
這就是為什么擴(kuò)展屬性不能有初始化器,只能由getters/setters顯式提供!
3.伴生對(duì)象-擴(kuò)展函數(shù)和屬性

可為伴生對(duì)象定義擴(kuò)展函數(shù)和屬性:

    class MyClass {
        companion object { }  //伴生對(duì)象
    }

    fun MyClass.Companion.foo() {
        // ……
    }

    MyClass.foo() //用類(lèi)名調(diào)用

4.作用域

1.擴(kuò)展直接在包中

在頂層定義擴(kuò)展(即直接在包中):

    package foo.bar
    fun Baz.goo() {
        ...            
    }

在其它包調(diào)用:

    package com.example.usage
    import foo.bar.goo //導(dǎo)入所有名為“goo”的擴(kuò)展
    // 或者 import foo.bar.*
    fun usage(baz: Baz) {
        baz.goo()
    }

2.擴(kuò)展作為類(lèi)成員

在一個(gè)類(lèi)內(nèi)部可為另一個(gè)類(lèi)聲明擴(kuò)展,
擴(kuò)展聲明所在的類(lèi)稱(chēng)為分發(fā)接收者(dispatch receiver),
擴(kuò)展函數(shù)調(diào)用所在類(lèi)稱(chēng)為擴(kuò)展接收者(extension receiver)

1.定義

    class D { //擴(kuò)展接收者(extension receiver)
        fun f() { …… }
    }

    class C { //分發(fā)接收者(dispatch receiver)
        fun f() { …… }

        fun D.foo() {
           this@C.f() //分發(fā)接收者 C.f()
           f()        //擴(kuò)展接收者 D.f()
        }

        fun call(d: D) {
            d.foo()   //調(diào)用擴(kuò)展函數(shù)
        }
    }

2.繼承-覆蓋
成員擴(kuò)展可聲明為open,并在子類(lèi)中被覆蓋,
對(duì)分發(fā)接收者是虛擬的(多態(tài)),但對(duì)擴(kuò)展接收者是靜態(tài)的!

    open class D {
    }
    class D1 : D() {
    }

    open class C {
        open fun D.foo() {
            println("D.foo in C")
        }
        open fun D1.foo() {
            println("D1.foo in C")
        }
        fun call(d: D) {
            d.foo()   // 調(diào)用擴(kuò)展函數(shù)
        }
    }
    class C1 : C() {
        override fun D.foo() {
            println("D.foo in C1")
        }
        override fun D1.foo() {
            println("D1.foo in C1")
        }
    }
    C().call(D())   // 輸出 "D.foo in C"
    C().call(D1())  // 輸出 "D.foo in C", 擴(kuò)展接收者靜態(tài)解析(非多態(tài))
    C1().call(D())  // 輸出 "D.foo in C1",分發(fā)接收者虛擬解析(多態(tài))


JS 的 prototype

JavaScript prototype 屬性

定義和用法

prototype 屬性使您有能力向?qū)ο筇砑訉傩院头椒ā?br> prototype就是“一個(gè)給類(lèi)的對(duì)象添加方法的方法”,使用prototype屬性硝枉,可以給類(lèi)動(dòng)態(tài)地添加方法

語(yǔ)法

object.prototype.name=value

實(shí)例

在本例中廉丽,我們將展示如何使用 prototype 屬性來(lái)向?qū)ο筇砑訉傩裕?/p>

function employee(name,job,born){
  this.name=name;
  this.job=job;
  this.born=born;
}
var bill=new employee("Bill Gates","Engineer",1985);
employee.prototype.salary=null;
bill.salary=20000;
console.log(bill.salary);

輸出:

20000

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市妻味,隨后出現(xiàn)的幾起案子正压,更是在濱河造成了極大的恐慌,老刑警劉巖责球,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焦履,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雏逾,警方通過(guò)查閱死者的電腦和手機(jī)嘉裤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)栖博,“玉大人屑宠,你說(shuō)我怎么就攤上這事〕鹑茫” “怎么了典奉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)丧叽。 經(jīng)常有香客問(wèn)我卫玖,道長(zhǎng),這世上最難降的妖魔是什么踊淳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任假瞬,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脱茉。我一直安慰自己剪芥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布芦劣。 她就那樣靜靜地躺著粗俱,像睡著了一般说榆。 火紅的嫁衣襯著肌膚如雪虚吟。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天签财,我揣著相機(jī)與錄音串慰,去河邊找鬼。 笑死唱蒸,一個(gè)胖子當(dāng)著我的面吹牛邦鲫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播神汹,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼庆捺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了屁魏?” 一聲冷哼從身側(cè)響起滔以,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎氓拼,沒(méi)想到半個(gè)月后你画,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桃漾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年坏匪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撬统。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡适滓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恋追,到底是詐尸還是另有隱情凭迹,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布几于,位于F島的核電站蕊苗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏沿彭。R本人自食惡果不足惜朽砰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瞧柔,春花似錦漆弄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至哥蔚,卻和暖如春倒谷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糙箍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工渤愁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人深夯。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓抖格,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親咕晋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雹拄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容