乐趣区

关于javascript:JavaScript中的类有什么问题呢

并不是说 JS 的类有问题,然而如果你应用该语言已有一段时间,特地是应用过 ES5,那么你可能就晓得了从原型继承到以后类模型的演变。

原型链会有什么问题?

以我的高见,这个问题的答案是:没有。然而社区花了很多年的工夫才将类的概念强加到不同的构造和库中,因而 ECMA 技术委员会决定无论如何都要增加它。

你会问,这有什么问题吗? 这就是他们真正做的,在咱们曾经领有的原型继承之上增加了一些形成,并决定将其称为类,这反过来又让开发人员认为他们正在解决一种面向对象的语言,而实际上它们并不是。

类只不过是语法糖
jS 没有齐全的 OOP 反对,它素来没有,这是因为它素来都不须要它。

外表上,以后版本的类显示 OOP 范例,因为:

咱们能够创立根本的类定义,用十分经典的语法将状态和行为分组在一起。
咱们能够从一个类继承到另一个类。
咱们能够在私有和公有之间定义属性和办法的可见性 (只管公有字段依然是一个实验性的个性)。
咱们能够为属性定义 getter 和 setter。
咱们能够实例化类。
那么为什么我说类是语法糖呢? 因为只管在表面上,它们看起来是十分面向对象的,然而如果咱们试图做一些超出它们可能的事件,比方定义一个类扩大两个类(目前不可能的事件),咱们须要应用上面的代码

// 辅助函数
function applyMixins(derivedCtor, baseCtors) {
    baseCtors.forEach(baseCtor => {Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {let descriptor = Object.getOwnPropertyDescriptor(baseCtor.prototype, name)
            Object.defineProperty(derivedCtor.prototype, name, descriptor);
        });
    });
}

class A {methodA () {console.log('A')
  }
}

class B {methodB () {console.log('B')
  }
}

class C {

}

// 应用 mixins

咱们须要这样做,因为在 JS 中咱们无奈编写:

class A {methodA(){console.log("A")
    }
}

class B {methodB(){console.log("B")
    }
}

class C extends A, B {}

在下面的示例中,要害局部应该是 applyMixins 函数。如果,你没有齐全了解它试图做什么,但能够分明地看到它正在拜访所有类的原型属性来复制和重新分配办法和属性。这就是咱们须要看到假相的中央: 类只不过是在通过验证的原型继承模型之上的语法糖。

这是否意味着咱们应该停止使用类?当然不是,重要的是要了解它,而且如果咱们想做些冲破类的限度,那么咱们就必须用原型来解决。

JS 的 OOP 模型缺失了什么呢?
如果咱们以后的 OOP 模型是如此之薄,仅是原型继承的形象层,那么咱们到底短少什么呢?是什么让 JS 真正成为 OOP?

看这个问题的一个好办法就是看看 TypeScript 在做什么。该语言背地的团队通过创立一些能够翻译成 JS 的货色,无疑将 JS 推向了极限。这反过来也限度了它们的能力。

目前 JS 中缺失的一些 OOP 结构具备外在的类型查看性能,在动静类型语言中没有真正的意义,这可能是它们还没有被增加的起因。
接口
接口可帮忙定义类应遵循的 API。接口的次要益处之一是,咱们能够定义实现雷同接口的任何类的变量,而后平安地调用其任何办法。

interface Animal {speak()
}

class Dog implements Animal{speak() {console.log("Woof!")
  }
}

class Cat implements Animal{speak() {console.log("Meau!")
  }
}

class Human implements Animal{speak() {console.log("Hey dude, what's up?")
  }
}

// 如果咱们在 JS 中有接口,咱们能够释怀地做:let objects = [new Dog(), new Cat(), new Human()]
objects.forEach(o => o.speak())

当然,咱们能够通过定义 speak 办法并笼罩它的类来实现同样的目标,但接口更加清晰和优雅。

抽象类
每当我尝试对我的代码进行残缺的 OOP 操作时,我必定会错过 JS 中的抽象类。抽象类是定义和实现办法的类,但永远不会实例化。这是一种能够扩大但从未间接应用的常见行为的分组形式。这是一个很好的资源,并且相对能够在以后 JS 畛域内实现而不会破费太多精力。

动态多态
动态多态性使咱们能够在雷同的类中屡次定义雷同的办法,然而具备不同的签名。换句话说,反复该名称,但要确保其接管不同的参数。当初咱们有了 JS 的 rest 参数,这使咱们能够领有一个任意数字,然而,这也意味着咱们必须在办法中增加额定的代码来解决这种动态性。相同,咱们能够更分明地区分办法签名,则能够将雷同行为的不同含意间接封装到不同办法中。

clipboard.png

右边的版本不是无效的 JS,但它提供了一个更洁净的代码,因而,浏览和了解起来比拟容易。左边的版本是齐全无效的,它浏览起来绝对艰难些,还要懂得一些 ES6 的语法。

多态性通常是通过查看办法中接管到的参数的类型来实现的。然而,因为 JS 的工作原理,咱们晓得这是不可能的。

受爱护的属性和办法
咱们曾经有了公开的可见性,而且咱们很快就失去了办法和属性的公有可见性(通过 #前缀)。我认为下一步应该是增加受爱护的可见性,然而,当初还没有,我认为如果你想要有一个适合的 OOP 体验,这三个都是必要的。受爱护的属性和办法只能从类外部或它的一个子类中拜访(与公有可见性相同,公有可见性将拜访限度为只能拜访父类)。

明天就跟大家分享到这里了,我是小智,咱们下期再见。

代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

退出移动版