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