这并不是一个反模式。在js中,它是一种反模式,因为js是动态的,因此更改原型会在运行时更改代码的工作方式,这使得它成为一个反模式。基于in操作符的工作方式以及您可以重写everything的事实,这也极其危险,因此更改原型可能会影响页面上某个地方的代码:
Number.prototype.toString = function(){
return "bullshit";
};
alert(""+12);
function replaceSpaces($receiver) {
return replace($receiver, 32, 95);
}
function foo(str) {
var formatted = replaceSpaces(str);
}
完全没有猴子补丁!扩展函数只是Kotlin中的一种语法糖。这只是将第一个参数传递给静态函数的另一种方式。
Main.kt
和Library1.kt
中有以下代码:import library1.*
import library2.*
fun main() {
listOf(99, 101, 103, 104).printOddVals()
}
package library1
fun List<Int>.printOddVals() {
for (x in this) {
if (x % 2 != 0) {
println(x)
}
}
}
package library2
fun List<Int>.printOddVals() {
for ((i, x) in this.withIndex()) {
if (i % 2 != 0) {
println(x)
}
}
}
Main.kt:5:31: error: overload resolution ambiguity:
public fun List<Int>.printOddVals(): Unit defined in library1 in file Library1.kt
public fun List<Int>.printOddVals(): Unit defined in library2 in file Library2.kt
listOf(99, 101, 103, 104).printOddVals()
^
import library1.*
import library2.*
import library2.printOddVals as printOddVals1
fun main() {
listOf(99, 101, 103, 104).printOddVals1()
}
package library1
class Cow {
fun chewCud() {}
}
import library1.*
fun Cow.moo() {
println("MOOOOOOO!")
}
fun main() {
val cow = Cow()
cow.moo()
}
Cow.moo
最初是我们编写的扩展方法。但是然后我们更新了library1,新版本有一个moo
成员函数:package library1
class Cow {
fun chewCud() {}
fun moo() { println("moo") }
}
main()
中调用cow.moo()
时,我们的扩展函数不会被使用,而是使用库的新成员函数。这是运行时行为的变化,如果库的新moo()
实现不能充分替代我们之前编写的扩展函数,则可能存在错误。然而,好在这至少产生了一个编译器警告:Main.kt:3:9: warning: extension is shadowed by a member: public final fun moo(): Unit
fun Cow.moo() {
^
import library1.*
fun Animal.talk() {
println("Hello there! I am a " + this::class.simpleName)
}
fun main() {
val cow = Cow()
val sheep = Sheep()
cow.talk()
sheep.talk()
}
package library1
interface Animal
class Cow : Animal
class Sheep : Animal
main()
函数时,我们的扩展函数被用于cow.talk()
和sheep.talk()
。Why hello there. I am a Cow.
Why hello there. I am a Sheep.
但是假设我们给Cow
添加一个talk
成员:
package library1
interface Animal
class Cow : Animal {
fun talk() {
println("moo")
}
}
class Sheep : Animal
moo
Why hello there. I am a Sheep.
当然,你可以自由地形成自己的观点!扩展函数
自由地使用扩展函数。每当您有一个主要作用于对象的函数时,请考虑将其制作为接受该对象作为接收器的扩展函数。为了最小化 API 污染,请尽可能限制扩展函数的可见性。必要时,使用本地扩展函数、成员扩展函数或具有私有可见性的顶级扩展函数。
不,这并不好。Kotlin允许对现有类型进行扩展是非常糟糕的。
使用扩展,就没有任何理由创建类层次结构,甚至也不需要创建新的类定义。
Kotlin的创造者们可能还不如直接使用erlang而不费心地创建扩展。
扩展意味着您不能再依赖于类定义为常量。想象一下人们将花费多少时间来查找开发人员的“创意”扩展,更不用说调试它们了。
str.replaceStrings()
在编译后变成了Foo.replaceStrings(str)
。 - killjoy