Имеет ли JavaScript тип интерфейса (например, "интерфейс" Java)?
учусь Как сделать ООП с JavaScript. Имеет ли он концепцию интерфейса (например, Java interface)?
Так что я мог бы создать слушателя...
10 ответов:
нет понятия "этот класс должен иметь эти функции" (то есть, нет интерфейса как такового), потому что:
- наследование JavaScript основано на объектах, а не на классах. Это не имеет большого значения, пока вы не поймете:
- JavaScript-это очень динамически типизированный язык -- вы можете создать объект с помощью соответствующих методов, которые сделают его соответствующим интерфейсу,а затем определить все вещи, которые сделали это соответствовать. Было бы так легко разрушить систему типов-даже случайно! -- что не стоит пытаться сделать систему типов в первую очередь.
вместо этого JavaScript использует то, что называется утиной типизацией. (Если он ходит, как утка, и крякает, как утка, насколько JS заботится, это утка.) Если ваш объект имеет методы quack(), walk () и fly (), код может использовать его везде, где он ожидает объект, который может ходить, крякать и летать, не требуя реализация некоторого" Уткабельного " интерфейса. Интерфейс-это именно тот набор функций, которые использует код (и возвращаемые значения из этих функций), и с помощью duck typing вы получаете это бесплатно.
теперь, это не значит, что ваш код не провалится на полпути, если вы попытаетесь позвонить
some_dog.quack(); вы получите TypeError. Честно говоря, если вы говорите собакам крякать, у вас есть немного большие проблемы; утка набрав работает лучше всего, когда вы держите все ваши утки в ряд, так сказать, и не позволяйте собакам и уткам смешиваться вместе, если вы не относитесь к ним как к родовым животным. Другими словами, несмотря на то, что интерфейс является текучим, он все еще существует; часто бывает ошибкой передавать собаку в код, который ожидает, что она будет крякать и летать в первую очередь.но если вы уверены, что поступаете правильно, вы можете обойти проблему крякающей собаки, проверив наличие определенного метода, прежде чем пытаться его использовать. Что-то вроде
if (typeof(someObject.quack) == "function") { // This thing can quack }так вы можете проверить все способы вы можете использовать, прежде чем использовать их. Синтаксис-это хоть какая-то уродливая,. Есть немного более красивый способ:
Object.prototype.can = function(methodName) { return ((typeof this[methodName]) == "function"); }; if (someObject.can("quack")) { someObject.quack(); }это стандартный JavaScript, поэтому он должен работать в любом интерпретаторе JS, который стоит использовать. Он имеет дополнительное преимущество чтения, как английский.
для современных браузеров (то есть, почти любой браузер, кроме IE 6-8), есть даже способ сохранить свойство от отображения в
for...in:Object.defineProperty(Object.prototype, 'can', { enumerable: false, value: function(method) { return (typeof this[method] === 'function'); } }в проблема в том, что объекты IE7 не имеют
.definePropertyвообще, и в IE8, он якобы работает только на объектах хоста (то есть, элементы DOM и такие). Если совместимость является проблемой, вы не можете использовать.defineProperty. (Я даже не буду упоминать IE6, потому что это довольно неуместно за пределами Китая.)другая проблема заключается в том, что некоторые стили кодирования любят предполагать, что все пишут плохой код, и запрещают изменение
Object.prototypeв случае, если кто-то хочет слепо использоватьfor...in. Если вы заботитесь об этом, или использование (IMO сломанные) код, который делает, попробуйте немного другую версию:function can(obj, methodName) { return ((typeof obj[methodName]) == "function"); } if (can(someObject, "quack")) { someObject.quack(); }
возьмите копию ' шаблоны проектирования JavaScript на Дастин Диаз. Есть несколько глав, посвященных реализации интерфейсов JavaScript с помощью Duck Typing. Это приятно читать. Но нет, нет языка родной реализации интерфейса, вы должны Тип Утка.
// example duck typing method var hasMethods = function(obj /*, method list as strings */){ var i = 1, methodName; while((methodName = arguments[i++])){ if(typeof obj[methodName] != 'function') { return false; } } return true; } // in your code if(hasMethods(obj, 'quak', 'flapWings','waggle')) { // IT'S A DUCK, do your duck thang }
JavaScript (ECMAScript edition 3) имеет
implementsзарезервированное слово накопленные для дальнейшего использования. Я думаю, что это предназначено именно для этой цели, однако, в спешке, чтобы получить спецификацию за дверью, у них не было времени, чтобы определить, что с ней делать, поэтому в настоящее время браузеры ничего не делают, кроме как позволяют ему сидеть там и иногда жалуются, если вы пытаетесь использовать его для чего-то.возможно и действительно достаточно легко создать свой собственный
Object.implement(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.prototypeС которым у некоторых людей могут быть проблемы, но я считаю, что это прекрасно работает.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:
хотя JavaScript делает не есть
interfaceтипа, это иногда необходимо. По причинам, связанным с динамическим характером JavaScript и использованием Прототипического наследования, трудно обеспечить согласованные интерфейсы между классами-однако это возможно сделать; и часто эмулируется.на данный момент существует множество конкретных способов эмуляции интерфейсов в JavaScript; дисперсия на подходах обычно удовлетворяет одни потребности, в то время как другие остаются без внимания. Часто самый надежный подход является чрезмерно громоздким и блокирует разработчика (разработчика).
вот подход к интерфейсам / абстрактным классам, который не очень громоздок, является экспликативным, сводит реализации внутри абстракций к минимуму и оставляет достаточно места для динамических или пользовательских методологий:
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 };участники
заповедь Решатель
The
resolvePreceptфункция-это утилита и вспомогательная функция для использования внутри вашего Абстрактный Класс. Его работа заключается в том, чтобы обеспечить индивидуальную реализацию-обработку инкапсулированных заповеди (данные и поведение). Он может выдавать ошибки или предупреждать -- и -- присваивать значение по умолчанию классу реализации.iAbstractClass
The
iAbstractClassопределяет интерфейс, который будет использоваться. Свой подход подразумевает молчаливое согласие с его классом-исполнителем. Этот интерфейс присваивает каждому предписание к тому же самому точному пространству имен заповедей -- или -- к чему угодно Сельсин Предписание возвращает функция. Однако молчаливое соглашение разрешает контекст -- положение исполнителя.конструктор
конструктор просто соглашается с интерфейсом (iAbstractClass in этот случай) и применяет его с помощью Конструктора-Угон:
iAbstractClass.apply(this). Определив данные и поведение выше, а затем захват конструктор интерфейса -- передача контекста реализации конструктору интерфейса -- мы можем гарантировать, что переопределения реализации будут добавлены, и этот интерфейс будет объяснять предупреждения и значения по умолчанию.это очень не громоздкий подход, который служил моей команде и я очень хорошо с течением времени и разные проекты. Однако у него есть некоторые недостатки и недоработки.
недостатки
хотя это помогает реализовать согласованность во всем вашем программном обеспечении в значительной степени, это не реализует истинные интерфейсы -- но подражает им. Хотя определения, значения по умолчанию и предупреждения или ошибки are эксплицируется, экспликация использование принудительно и утверждено разработчиком (как с большая часть разработки на JavaScript).
это, казалось бы, лучший подход к "интерфейсы на JavaScript", однако, я хотел бы видеть следующее решение:
- утверждения возвращаемых типов
- утверждения подписей
- замораживание объектов из
deleteдействия- утверждения чего-либо еще распространенного или необходимого в специфике JavaScript сообщество
тем не менее, я надеюсь, что это поможет вам так же, как и моя команда и я.
надеюсь, что всем, кто все еще ищет ответ, найдет его полезным.
вы можете попробовать использовать прокси (это стандарт с 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;
вам нужны интерфейсы в Java, так как он статически типизирован и контракт между классами должен быть известен во время компиляции. В JavaScript все по-другому. JavaScript является динамически типизированным; это означает, что когда вы получаете объект, вы можете просто проверить, имеет ли он определенный метод и вызвать его.
Я знаю, что это старый, но я недавно обнаружил, что мне нужно все больше и больше иметь удобный API для проверки объектов на интерфейсы. Поэтому я написал следующее:https://github.com/tomhicks/methodical
Он также доступен через NPM:
npm install methodicalон в основном делает все, что предложено выше, с некоторыми вариантами для того, чтобы быть немного более строгим, и все это без необходимости делать нагрузки
if (typeof x.method === 'function')шаблонный.надеюсь, кто-то находит полезный.
Javascript не имеет интерфейсов. Но это может быть утка типа, пример можно найти здесь:
http://reinsbrain.blogspot.com/2008/10/interface-in-javascript.html
Если вы хотите использовать транскомпилятор, то вы можете дать TypeScript попробовать. Он поддерживает функции проекта ECMA, похожие на то, что делают такие языки, как coffeescript или babel.
в TypeScript ваш интерфейс может выглядеть так:
interface IMyInterface { id: number; // TypeScript types are lowercase name: string; callback: (key: string; value: any; array: string[]) => void; type: "test" | "notATest"; // so called "union type" }что вы не можете сделать:
- определите Шаблоны регулярных выражений для типа value
- определяют проверку как длина строки
- диапазоны номеров
- etc.
Comments