有没有办法在 ES6/Node4中创建接口?

ES6在节点4中完全可用。我想知道它是否像 MyClass implements MyInterface那样包含了定义方法契约的接口概念。

我在谷歌上找不到太多,但也许有一个不错的技巧或变通方法。

124412 次浏览

接口不是 ES6的一部分,但类是。

如果你真的需要他们,你应该看看 打字机哪个 support them

Debiasej 在评论中写道,下面提到的文章解释了更多关于设计模式(基于接口、类)的内容:

Http://loredanacirstea.github.io/es6-design-patterns/

用 javascript 编写的设计模式书也许对你有用:

Http://addyosmani.com/resources/essentialjsdesignpatterns/book/

设计模式 = 类 + 接口或多重继承

ES6 JS 中的工厂模式示例(要运行: node example.JS) :

"use strict";


// Types.js - Constructors used behind the scenes


// A constructor for defining new cars
class Car {
constructor(options){
console.log("Creating Car...\n");
// some defaults
this.doors = options.doors || 4;
this.state = options.state || "brand new";
this.color = options.color || "silver";
}
}


// A constructor for defining new trucks
class Truck {
constructor(options){
console.log("Creating Truck...\n");
this.state = options.state || "used";
this.wheelSize = options.wheelSize || "large";
this.color = options.color || "blue";
}
}




// FactoryExample.js


// Define a skeleton vehicle factory
class VehicleFactory {}


// Define the prototypes and utilities for this factory


// Our default vehicleClass is Car
VehicleFactory.prototype.vehicleClass = Car;


// Our Factory method for creating new Vehicle instances
VehicleFactory.prototype.createVehicle = function ( options ) {


switch(options.vehicleType){
case "car":
this.vehicleClass = Car;
break;
case "truck":
this.vehicleClass = Truck;
break;
//defaults to VehicleFactory.prototype.vehicleClass (Car)
}


return new this.vehicleClass( options );


};


// Create an instance of our factory that makes cars
var carFactory = new VehicleFactory();
var car = carFactory.createVehicle( {
vehicleType: "car",
color: "yellow",
doors: 6 } );


// Test to confirm our car was created using the vehicleClass/prototype Car


// Outputs: true
console.log( car instanceof Car );


// Outputs: Car object of color "yellow", doors: 6 in a "brand new" state
console.log( car );


var movingTruck = carFactory.createVehicle( {
vehicleType: "truck",
state: "like new",
color: "red",
wheelSize: "small" } );


// Test to confirm our truck was created with the vehicleClass/prototype Truck


// Outputs: true
console.log( movingTruck instanceof Truck );


// Outputs: Truck object of color "red", a "like new" state
// and a "small" wheelSize
console.log( movingTruck );

有一些包可以模拟接口。

你可以使用 Es6-接口

这是我对这个问题的解决方案。你可以通过用一个接口覆盖另一个接口来“实现”多个接口。

class MyInterface {
// Declare your JS doc in the Interface to make it acceable while writing the Class and for later inheritance
/**
* Gives the sum of the given Numbers
* @param {Number} a The first Number
* @param {Number} b The second Number
* @return {Number} The sum of the Numbers
*/
sum(a, b) {
this._WARNING('sum(a, b)');
}




// delcare a warning generator to notice if a method of the interface is not overridden
// Needs the function name of the Interface method or any String that gives you a hint ;)
_WARNING(fName = 'unknown method') {
console.warn('WARNING! Function "' + fName + '" is not overridden in ' + this.constructor.name);
}
}


class MultipleInterfaces extends MyInterface {
// this is used for "implement" multiple Interfaces at once
/**
* Gives the square of the given Number
* @param {Number} a The Number
* @return {Number} The square of the Numbers
*/
square(a) {
this._WARNING('square(a)');
}
}


class MyCorrectUsedClass extends MyInterface {
// You can easy use the JS doc declared in the interface
/** @inheritdoc */
sum(a, b) {
return a + b;
}
}
class MyIncorrectUsedClass extends MyInterface {
// not overriding the method sum(a, b)
}


class MyMultipleInterfacesClass extends MultipleInterfaces {
// nothing overriden to show, that it still works
}




let working = new MyCorrectUsedClass();


let notWorking = new MyIncorrectUsedClass();


let multipleInterfacesInstance = new MyMultipleInterfacesClass();


// TEST IT


console.log('working.sum(1, 2) =', working.sum(1, 2));
// output: 'working.sum(1, 2) = 3'


console.log('notWorking.sum(1, 2) =', notWorking.sum(1, 2));
// output: 'notWorking.sum(1, 2) = undefined'
// but also sends a warn to the console with 'WARNING! Function "sum(a, b)" is not overridden in MyIncorrectUsedClass'


console.log('multipleInterfacesInstance.sum(1, 2) =', multipleInterfacesInstance.sum(1, 2));
// output: 'multipleInterfacesInstance.sum(1, 2) = undefined'
// console warn: 'WARNING! Function "sum(a, b)" is not overridden in MyMultipleInterfacesClass'


console.log('multipleInterfacesInstance.square(2) =', multipleInterfacesInstance.square(2));
// output: 'multipleInterfacesInstance.square(2) = undefined'
// console warn: 'WARNING! Function "square(a)" is not overridden in MyMultipleInterfacesClass'

EDIT:

I improved the code so you now can simply use implement(baseClass, interface1, interface2, ...) in the extends.

/**
* Implements any number of interfaces to a given class.
* @param cls The class you want to use
* @param interfaces Any amount of interfaces separated by comma
* @return The class cls exteded with all methods of all implemented interfaces
*/
function implement(cls, ...interfaces) {
let clsPrototype = Object.getPrototypeOf(cls).prototype;
for (let i = 0; i < interfaces.length; i++) {
let proto = interfaces[i].prototype;
for (let methodName of Object.getOwnPropertyNames(proto)) {
if (methodName !== 'constructor')
if (typeof proto[methodName] === 'function')
if (!clsPrototype[methodName]) {
console.warn('WARNING! "' + methodName + '" of Interface "' + interfaces[i].name + '" is not declared in class "' + cls.name + '"');
clsPrototype[methodName] = proto[methodName];
}
}
}
return cls;
}


// Basic Interface to warn, whenever an not overridden method is used
class MyBaseInterface {
// declare a warning generator to notice if a method of the interface is not overridden
// Needs the function name of the Interface method or any String that gives you a hint ;)
_WARNING(fName = 'unknown method') {
console.warn('WARNING! Function "' + fName + '" is not overridden in ' + this.constructor.name);
}
}




// create a custom class
/* This is the simplest example but you could also use
*
*  class MyCustomClass1 extends implement(MyBaseInterface) {
*      foo() {return 66;}
*  }
*
*/
class MyCustomClass1 extends MyBaseInterface {
foo() {
return 66;
}
}


// create a custom interface
class MyCustomInterface1 {
// Declare your JS doc in the Interface to make it acceable while writing the Class and for later inheritance


/**
* Gives the sum of the given Numbers
* @param {Number} a The first Number
* @param {Number} b The second Number
* @return {Number} The sum of the Numbers
*/
sum(a, b) {
this._WARNING('sum(a, b)');
}
}


// and another custom interface
class MyCustomInterface2 {
/**
* Gives the square of the given Number
* @param {Number} a The Number
* @return {Number} The square of the Numbers
*/
square(a) {
this._WARNING('square(a)');
}
}


// Extend your custom class even more and implement the custom interfaces
class AllInterfacesImplemented extends implement(MyCustomClass1, MyCustomInterface1, MyCustomInterface2) {
/**
* @inheritdoc
*/
sum(a, b) {
return a + b;
}


/**
* Multiplies two Numbers
* @param {Number} a The first Number
* @param {Number} b The second Number
* @return {Number}
*/
multiply(a, b) {
return a * b;
}
}




// TEST IT


let x = new AllInterfacesImplemented();


console.log("x.foo() =", x.foo());
//output: 'x.foo() = 66'


console.log("x.square(2) =", x.square(2));
// output: 'x.square(2) = undefined
// console warn: 'WARNING! Function "square(a)" is not overridden in AllInterfacesImplemented'


console.log("x.sum(1, 2) =", x.sum(1, 2));
// output: 'x.sum(1, 2) = 3'


console.log("x.multiply(4, 5) =", x.multiply(4, 5));
// output: 'x.multiply(4, 5) = 20'

鉴于 ECMA 是一种“无类”的语言,在我看来,实现经典作曲并没有多大意义。这样做的危险在于,你实际上是在尝试重新设计语言(如果你对此有强烈的感觉,那么有很好的整体解决方案,比如前面提到的 TypeScript,可以缓解重造轮子)

现在,这并不是说构图是不可能的,然而在普通的旧 JS。前段时间我仔细研究过这个问题。在对象原型范例中,我所见过的处理组合最有力的候选者是 Stampit,我现在在许多项目中使用它。而且,重要的是,它遵循一个明确的规范。

more information on stamps 给你

Flow 支持 接口规范接口规范,无需将整个代码库转换为 TypeScript。

接口是 打破依赖关系的方法,同时在现有代码中谨慎步骤。