我正在学习如何用JavaScript制作面向对象编程。是否有接口概念(如Java的接口)?

这样我就可以创建一个监听器。


当前回答

在Java中需要接口,因为它是静态类型的,并且在编译期间应该知道类之间的契约。在JavaScript中则不同。JavaScript是动态类型的;这意味着当你获得对象时,你可以检查它是否有特定的方法并调用它。

其他回答

JavaScript (ECMAScript edition 3)有一个保留字以备将来使用。我认为这正是为了这个目的而设计的,然而,在匆忙发布规范的过程中,他们没有时间定义如何使用它,所以,目前,浏览器除了让它呆在那里,偶尔会抱怨你试图用它来做什么之外,什么也不做。

创建自己的object. implementation (Interface)方法是可能的,而且非常简单,只要在给定的对象中没有实现特定的属性/函数集,该方法的逻辑就会中断。

我写了一篇关于面向对象的文章,其中使用了我自己的符号如下:

// Create a 'Dog' class that inherits from 'Animal'
// and implements the 'Mammal' interface
var Dog = Object.extend(Animal, {
    constructor: function(name) {
        Dog.superClass.call(this, name);
    },
    bark: function() {
        alert('woof');
    }
}).implement(Mammal);

有很多方法来处理这个特殊的问题,但这是我在自己的接口实现中使用的逻辑。我发现我更喜欢这种方法,而且它易于阅读和使用(如上所述)。这意味着在Function中添加一个“实现”方法。原型,有些人可能有一个问题,但我发现它工作得很漂亮。

Function.prototype.implement = function() {
    // Loop through each interface passed in and then check 
    // that its members are implemented in the context object (this).
    for(var i = 0; i < arguments.length; i++) {
       // .. Check member's logic ..
    }
    // Remember to return the class being tested
    return this;
}

Javascript没有接口。但它可以是鸭子类型的,一个例子可以在这里找到:

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

这是一个老问题,但这个话题一直困扰着我。

由于这里和网络上的许多答案都专注于“强制”界面,我想提出另一种观点:

当我使用行为相似的多个类(即实现一个接口)时,我感到最缺乏接口。

例如,我有一个电子邮件生成器,期望接收电子邮件节工厂,“知道”如何生成节的内容和HTML。因此,它们都需要某种类型的getContent(id)和getHtml(content)方法。

我能想到的最接近接口的模式(尽管它仍然是一种变通方法)是使用一个将获得2个参数的类,它将定义2个接口方法。

这种模式的主要挑战是,方法要么必须是静态的,要么必须获取实例本身作为参数,以便访问其属性。然而,在有些情况下,我发现这种权衡是值得的。

class Filterable { constructor(data, { filter, toString }) { this.data = data; this.filter = filter; this.toString = toString; // You can also enforce here an Iterable interface, for example, // which feels much more natural than having an external check } } const evenNumbersList = new Filterable( [1, 2, 3, 4, 5, 6], { filter: (lst) => { const evenElements = lst.data.filter(x => x % 2 === 0); lst.data = evenElements; }, toString: lst => `< ${lst.data.toString()} >`, } ); console.log('The whole list: ', evenNumbersList.toString(evenNumbersList)); evenNumbersList.filter(evenNumbersList); console.log('The filtered list: ', evenNumbersList.toString(evenNumbersList));

希望任何还在寻找答案的人都能从中找到帮助。

你可以尝试使用代理(这是自ECMAScript 2015以来的标准):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

latLngLiteral = new Proxy({},{
    set: function(obj, prop, val) {
        //only these two properties can be set
        if(['lng','lat'].indexOf(prop) == -1) {
            throw new ReferenceError('Key must be "lat" or "lng"!');
        }

        //the dec format only accepts numbers
        if(typeof val !== 'number') {
            throw new TypeError('Value must be numeric');
        }

        //latitude is in range between 0 and 90
        if(prop == 'lat'  && !(0 < val && val < 90)) {
            throw new RangeError('Position is out of range!');
        }
        //longitude is in range between 0 and 180
        else if(prop == 'lng' && !(0 < val && val < 180)) {
            throw new RangeError('Position is out of range!');
        }

        obj[prop] = val;

        return true;
    }
});

然后你就可以轻松地说:

myMap = {}
myMap.position = latLngLiteral;

如果你想通过instanceof (@Kamaffeather问)检查,你可以像这样把它包装在一个对象中:

class LatLngLiteral {
    constructor(props)
    {
        this.proxy = new Proxy(this, {
            set: function(obj, prop, val) {
                //only these two properties can be set
                if(['lng','lat'].indexOf(prop) == -1) {
                    throw new ReferenceError('Key must be "lat" or "lng"!');
                }

                //the dec format only accepts numbers
                if(typeof val !== 'number') {
                    throw new TypeError('Value must be numeric');
                }

                //latitude is in range between 0 and 90
                if(prop == 'lat'  && !(0 < val && val < 90)) {
                    throw new RangeError('Position is out of range!');
                }
                //longitude is in range between 0 and 180
                else if(prop == 'lng' && !(0 < val && val < 180)) {
                    throw new RangeError('Position is out of range!');
                }

                obj[prop] = val;

                return true;
            }
        })
        return this.proxy
    }
}

这可以在不使用Proxy的情况下完成,而是使用类getter和setter:

class LatLngLiteral {
    #latitude;
    #longitude;

    get lat()
    {
        return this.#latitude;
    }

    get lng()
    {
        return this.#longitude;
    }
    
    set lat(val)
    {
        //the dec format only accepts numbers
        if(typeof val !== 'number') {
            throw new TypeError('Value must be numeric');
        }

        //latitude is in range between 0 and 90
        if(!(0 < val && val < 90)) {
            throw new RangeError('Position is out of range!');
        }
        
        this.#latitude = val
    }
    
    set lng(val)
    {
        //the dec format only accepts numbers
        if(typeof val !== 'number') {
            throw new TypeError('Value must be numeric');
        }

        //longitude is in range between 0 and 180
        if(!(0 < val && val < 180)) {
            throw new RangeError('Position is out of range!');
        }
        
        this.#longitude = val
    }
}

JavaScript中没有本机接口, 有几种方法可以模拟接口。我已经写了一个包来做这件事

你可以看到这里的植入