JavaScript是否具有接口类型(例如Java的“接口”)?

本文翻译自:Does JavaScript have the interface type (such as Java's 'interface')?

I'm learning how to make OOP with JavaScript . 我正在学习如何使用JavaScript制作OOP Does it have the interface concept (such as Java's interface )? 它是否具有接口概念(例如Java的interface )?

So I would be able to create a listener... 所以我可以创建一个监听器......


#1楼

参考:https://stackoom.com/question/FZD9/JavaScript是否具有接口类型-例如Java的-接口


#2楼

JavaScript Interfaces: JavaScript接口:

Though JavaScript does not have the interface type, it is often times needed. 虽然JavaScript 没有interface类型,它往往是需要时间。 For reasons relating to JavaScript's dynamic nature and use of Prototypical-Inheritance, it is difficult to ensure consistent interfaces across classes -- however, it is possible to do so; 由于与JavaScript的动态性质和原型继承的使用相关的原因,很难确保跨类的一致接口 - 但是,有可能这样做; and frequently emulated. 并经常模仿。

At this point, there are handfuls of particular ways to emulate Interfaces in JavaScript; 此时,有一些特定的方法可以在JavaScript中模拟接口; variance on approaches usually satisfies some needs, while others are left unaddressed. 方法的差异通常满足一些需求,而其他方法则没有得到解决。 Often times, the most robust approach is overly cumbersome and stymies the implementor (developer). 通常,最强大的方法过于繁琐并且阻碍了实现者(开发人员)。

Here is an approach to Interfaces / Abstract Classes that is not very cumbersome, is explicative, keeps implementations inside of Abstractions to a minimum, and leaves enough room for dynamic or custom methodologies: 这是一种接口/抽象类的方法,它不是非常麻烦,是解释性的,将抽象内部的实现保持在最低限度,并为动态或自定义方法留下足够的空间:

function resolvePrecept(interfaceName) {
    var interfaceName = interfaceName;
    return function curry(value) {
        /*      throw new Error(interfaceName + ' requires an implementation for ...');     */
        console.warn('%s requires an implementation for ...', interfaceName);
        return value;
    };
}

var iAbstractClass = function AbstractClass() {
    var defaultTo = resolvePrecept('iAbstractClass');

    this.datum1 = this.datum1 || defaultTo(new Number());
    this.datum2 = this.datum2 || defaultTo(new String());

    this.method1 = this.method1 || defaultTo(new Function('return new Boolean();'));
    this.method2 = this.method2 || defaultTo(new Function('return new Object();'));

};

var ConcreteImplementation = function ConcreteImplementation() {

    this.datum1 = 1;
    this.datum2 = 'str';

    this.method1 = function method1() {
        return true;
    };
    this.method2 = function method2() {
        return {};
    };

    //Applies Interface (Implement iAbstractClass Interface)
    iAbstractClass.apply(this);  // .call / .apply after precept definitions
};

Participants 参与者

Precept Resolver 解析器解析器

The resolvePrecept function is a utility & helper function to use inside of your Abstract Class . resolvePrecept函数是一个在Abstract类中使用的实用程序和帮助函数。 Its job is to allow for customized implementation-handling of encapsulated Precepts (data & behavior) . 它的工作是允许对封装的Precepts(数据和行为)进行定制的实现处理。 It can throw errors or warn -- AND -- assign a default value to the Implementor class. 它可以抛出错误或警告 - 并 - 为Implementor类分配一个默认值。

iAbstractClass iAbstractClass

The iAbstractClass defines the interface to be used. iAbstractClass定义了要使用的接口。 Its approach entails a tacit agreement with its Implementor class. 它的方法需要与其Implementor类达成默契。 This interface assigns each precept to the same exact precept namespace -- OR -- to whatever the Precept Resolver function returns. 此接口将每个规则分配给相同的准确命名空间 - 或 - 分配给Precept Resolver函数返回的任何内容。 However, the tacit agreement resolves to a context -- a provision of Implementor. 但是,默契协议解决了上下文 - 实施者的规定。

Implementor 实施者

The Implementor simply 'agrees' with an Interface ( iAbstractClass in this case) and applies it by the use of Constructor-Hijacking : iAbstractClass.apply(this) . 实现者只是“同意”接口(在本例中为iAbstractClass )并通过使用Constructor-HijackingiAbstractClass.apply(this) By defining the data & behavior above, and then hijacking the Interface's constructor -- passing Implementor's context to the Interface constructor -- we can ensure that Implementor's overrides will be added, and that Interface will explicate warnings and default values. 通过定义上面的数据和行为,然后劫持 Interface的构造函数 - 将Implementor的上下文传递给Interface构造函数 - 我们可以确保将添加Implementor的覆盖,并且该接口将显示警告和默认值。

This is a very non-cumbersome approach which has served my team & I very well for the course of time and different projects. 这是一个非常麻烦的方法,它为我和我的团队提供了很好的时间和不同的项目。 However, it does have some caveats & drawbacks. 但是,它确实有一些警告和缺点。

Drawbacks 缺点

Though this helps implement consistency throughout your software to a significant degree, it does not implement true interfaces -- but emulates them. 虽然这有助于在很大程度上实现整个软件的一致性,但它并没有实现真正的接口 - 而是模仿它们。 Though definitions, defaults, and warnings or errors are explicated, the explication of use is enforced & asserted by the developer (as with much of JavaScript development). 虽然定义,默认值,警告或错误阐明,使用的解释是强制执行及由开发商断言 (如多JavaScript开发的)。

This is seemingly the best approach to "Interfaces in JavaScript" , however, I would love to see the following resolved: 这似乎是“JavaScript中的接口”的最佳方法,但是,我希望看到以下解决方案:

  • Assertions of return types 断言类型的断言
  • Assertions of signatures 签名的断言
  • Freeze objects from delete actions delete操作中冻结对象
  • Assertions of anything else prevalent or needed in the specificity of the JavaScript community 断言JavaScript社区的特殊性中普遍存在或需要的任何其他内容

That said, I hope this helps you as much as it has my team and I. 也就是说,我希望这对我和我的团队和我一样有帮助。


#3楼

I know this is an old one, but I've recently found myself needing more and more to have a handy API for checking objects against interfaces. 我知道这是一个旧的,但我最近发现自己需要越来越多的方法来获得一个方便的API来检查对象的接口。 So I wrote this: https://github.com/tomhicks/methodical 所以我写了这个: https//github.com/tomhicks/methodical

It's also available via NPM: npm install methodical 它也可以通过NPM获得: npm install methodical

It basically does everything suggested above, with some options for being a bit more strict, and all without having to do loads of if (typeof x.method === 'function') boilerplate. 它基本上完成了上面提到的所有操作,并提供了一些更严格的选项,并且无需加载if (typeof x.method === 'function')样板。

Hopefully someone finds it useful. 希望有人发现它很有用。


#4楼

Javascript does not have interfaces. Javascript没有接口。 But it can be duck-typed, an example can be found here: 但它可以是鸭型,可以在这里找到一个例子:

http://reinsbrain.blogspot.com/2008/10/interface-in-javascript.html http://reinsbrain.blogspot.com/2008/10/interface-in-javascript.html


#5楼

You need interfaces in Java since it is statically typed and the contract between classes should be known during compilation. 您需要Java中的接口,因为它是静态类型的,并且在编译期间应该知道类之间的契约。 In JavaScript it is different. 在JavaScript中它是不同的。 JavaScript is dynamically typed; JavaScript是动态类型的; it means that when you get the object you can just check if it has a specific method and call it. 这意味着当你得到对象时,你可以检查它是否有一个特定的方法并调用它。


#6楼

There's no notion of "this class must have these functions" (that is, no interfaces per se), because: 没有“这个类必须具有这些功能”的概念(即,本身没有接口),因为:

  1. JavaScript inheritance is based on objects, not classes. JavaScript继承基于对象,而不是类。 That's not a big deal until you realize: 直到你意识到这一点并不重要:
  2. JavaScript is an extremely dynamically typed language -- you can create an object with the proper methods, which would make it conform to the interface, and then undefine all the stuff that made it conform . JavaScript是一种极其动态类型的语言 - 您可以使用适当的方法创建一个对象,这将使其符合接口, 然后取消定义使其符合的所有内容 It'd be so easy to subvert the type system -- even accidentally! 破坏类型系统很容易 - 甚至意外! -- that it wouldn't be worth it to try and make a type system in the first place. - 首先尝试制作类型系统是不值得的。

Instead, JavaScript uses what's called duck typing . 相反,JavaScript使用所谓的duck typing (If it walks like a duck, and quacks like a duck, as far as JS cares, it's a duck.) If your object has quack(), walk(), and fly() methods, code can use it wherever it expects an object that can walk, quack, and fly, without requiring the implementation of some "Duckable" interface. (如果它像鸭子一样走路,像鸭子那样呱呱叫,就JS而言,它就是鸭子。)如果你的对象有quack(),walk()和fly()方法,代码可以在任何预期的地方使用它一个可以行走,嘎嘎叫和飞行的物体,而不需要实现一些“Duckable”接口。 The interface is exactly the set of functions that the code uses (and the return values from those functions), and with duck typing, you get that for free. 接口正是代码使用的函数集(以及这些函数的返回值),并且使用duck typing,您可以免费获得。

Now, that's not to say your code won't fail halfway through, if you try to call some_dog.quack() ; 现在,如果你试图调用some_dog.quack() ,那并不是说你的代码不会中途失败。 you'll get a TypeError. 你会得到一个TypeError。 Frankly, if you're telling dogs to quack, you have slightly bigger problems; 坦率地说,如果你告诉狗嘎嘎叫,你会遇到更大的问题; duck typing works best when you keep all your ducks in a row, so to speak, and aren't letting dogs and ducks mingle together unless you're treating them as generic animals. 当你把所有的鸭子连成一排时,鸭子的打字效果最好,可以这么说,除非你把它们视为一般动物,否则它们不会让狗和鸭子混在一起。 In other words, even though the interface is fluid, it's still there; 换句话说,即使界面是流动的,它仍然存在; it's often an error to pass a dog to code that expects it to quack and fly in the first place. 将狗传递给期望它首先嘎嘎叫并飞行的代码通常是错误的。

But if you're sure you're doing the right thing, you can work around the quacking-dog problem by testing for the existence of a particular method before trying to use it. 但是如果你确定你做的是正确的事情,你可以通过在尝试使用之前测试特定方法的存在来解决这个问题。 Something like 就像是

if (typeof(someObject.quack) == "function")
{
    // This thing can quack
}

So you can check for all the methods you can use before you use them. 因此,您可以在使用之前检查可以使用的所有方法。 The syntax is kind of ugly, though. 不过,语法有点难看。 There's a slightly prettier way: 有一个更漂亮的方式:

Object.prototype.can = function(methodName)
{
     return ((typeof this[methodName]) == "function");
};

if (someObject.can("quack"))
{
    someObject.quack();
}

This is standard JavaScript, so it should work in any JS interpreter worth using. 这是标准的JavaScript,所以它应该适用于任何值得使用的JS解释器。 It has the added benefit of reading like English. 它具有英语阅读的额外好处。

For modern browsers (that is, pretty much any browser other than IE 6-8), there's even a way to keep the property from showing up in for...in : 对于现代浏览器(即几乎任何除IE 6-8之外的浏览器),甚至还有一种方法可以防止该属性出现在for...in

Object.defineProperty(Object.prototype, 'can', {
    enumerable: false,
    value: function(method) {
        return (typeof this[method] === 'function');
    }
}

The problem is that IE7 objects don't have .defineProperty at all, and in IE8, it allegedly only works on host objects (that is, DOM elements and such). 问题是IE7对象根本没有.defineProperty ,而在IE8中,它据称只适用于主机对象(即DOM元素等)。 If compatibility is an issue, you can't use .defineProperty . 如果兼容性是个问题,则不能使用.defineProperty (I won't even mention IE6, because it's rather irrelevant anymore outside of China.) (我甚至不会提到IE6,因为它在中国之外已经相当无关紧要了。)

Another issue is that some coding styles like to assume that everyone writes bad code, and prohibit modifying Object.prototype in case someone wants to blindly use for...in . 另一个问题是,某些编码样式会假设每个人都编写错误的代码,并禁止修改Object.prototype ,以防有人想盲目地使用for...in If you care about that, or are using (IMO broken ) code that does, try a slightly different version: 如果您关心它,或者正在使用(IMO 损坏的 )代码,请尝试稍微不同的版本:

function can(obj, methodName)
{
     return ((typeof obj[methodName]) == "function");
}

if (can(someObject, "quack"))
{
    someObject.quack();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值