[javascript] JavaScript에는 인터페이스 유형 (예 : Java ‘인터페이스’)이 있습니까?

JavaScript로 OOP를 만드는 방법을 배우고 있습니다. 인터페이스 개념 (예 : Java interface)이 있습니까?

그래서 나는 청취자를 만들 수있을 것입니다 …



답변

“이 클래스에는 이러한 함수가 있어야합니다”라는 개념이 없습니다. 즉, 인터페이스 자체가 없습니다.

  1. JavaScript 상속은 클래스가 아닌 객체를 기반으로합니다. 당신이 깨닫기 전까지는 큰 문제가 아닙니다.
  2. JavaScript는 매우 동적으로 유형이 지정된 언어입니다. 적절한 메소드를 사용하여 객체를 만들어 인터페이스를 준수한 다음이를 준수하는 모든 내용을 정의 할 수 없습니다 . 실수로 타입 시스템을 쉽게 파괴 할 수 있습니다! -타입 시스템을 처음부터 시도해 보는 것은 가치가 없다.

대신, JavaScript는 duck typing 이라는 것을 사용합니다 . (Jacks가 관심을 갖는 한, 오리처럼 걷고 오리처럼 cks 거리면 오리입니다.) 객체에 quack (), walk () 및 fly () 메소드가있는 경우 코드는 예상 한 곳에서 사용할 수 있습니다. “Duckable”인터페이스를 구현할 필요없이 걷거나 qua 고 날 수있는 객체. 인터페이스는 코드에서 사용하는 기능 세트 (및 해당 함수의 반환 값)이며 덕 타이핑을 사용하면 무료로 제공됩니다.

이제 전화를 걸려 고해도 코드가 반쯤 실패하지는 않습니다 some_dog.quack(). TypeError가 발생합니다. 솔직히 말해서 개에게 qua을 지시하면 약간 더 큰 문제가 있습니다. 오리 타자는 모든 오리를 한 줄로 모을 때 가장 잘 작동하며, 말과 함께 일반적인 동물로 취급하지 않는 한 개와 오리가 서로 어울리지 않도록합니다. 다시 말해, 인터페이스가 유동적이지만 여전히 존재합니다. 개를 처음에 pass 고 날아갈 것으로 예상하는 코드로 개를 전달하는 것은 종종 오류입니다.

그러나 당신이 옳은 일을하고 있다고 확신한다면, 그것을 사용하기 전에 특정 방법의 존재를 테스트함으로써 쿼킹 독 문제를 해결할 수 있습니다. 같은 것

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 객체가 전혀 없으며 .definePropertyIE8에서는 호스트 객체 (즉, DOM 요소 등)에서만 작동한다는 것입니다. 호환성이 문제인 경우을 사용할 수 없습니다 .defineProperty. (IE6에 대해서는 언급하지 않을 것입니다. 중국 이외의 지역에서는 더 이상 관련이 없기 때문입니다.)

또 다른 문제는 일부 코딩 스타일은 모든 사람이 잘못된 코드를 작성한다고 가정하고 Object.prototype누군가가 맹목적으로 사용하려는 경우 수정 을 금지 한다는 것 for...in입니다. 관심이 있거나 (IMO broken ) 코드를 사용 하는 경우 약간 다른 버전을 시도하십시오.

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

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


답변

Dustin Diaz 의 ‘ JavaScript 디자인 패턴 ‘ 사본을 선택하십시오 . Duck Typing을 통해 JavaScript 인터페이스를 구현하기위한 장이 몇 가지 있습니다. 잘 읽었습니다. 그러나 아니요, 인터페이스의 언어 기본 구현이 없으므로 Duck Type 해야합니다 .

// 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 버전 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;
}


답변

자바 스크립트 인터페이스 :

자바 스크립트는 않지만 하지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
};

참가자

계명 분석기

resolvePrecept함수는 추상 클래스 내부에서 사용할 유틸리티 및 도우미 함수 입니다. 그 역할은 캡슐화 된 Precepts (data & behavior) 의 맞춤형 구현 처리를 허용하는 것입니다 . 오류를 발생 시키거나 경고 할 수 있으며-그리고-기본값을 Implementor 클래스에 할당합니다.

iAbstractClass

iAbstractClass사용되는 인터페이스를 정의합니다. 그 접근 방식은 Implementor 클래스와의 암묵적 계약을 수반합니다. 이 인터페이스는 각각의 할당 교훈 또는 – – 무엇이든에 똑같은 교훈 네임 스페이스에 대한 교훈 확인자 함수가 반환을. 그러나 암묵적 합의는 맥락 , 즉 Implementor의 조항으로 해석됩니다 .

구현 자

구현 자는 단순히 인터페이스 ( 이 경우 iAbstractClass )와 ‘동의’하고 Constructor-Hijacking :을 사용하여 적용합니다 iAbstractClass.apply(this). 위의 데이터 및 동작을 정의한 다음 인터페이스 생성자 를 하이재킹 하여 구현 자의 컨텍스트를 인터페이스 생성자에 전달하면 구현 자의 재정의가 추가되고 인터페이스가 경고 및 기본값을 설명 할 수 있습니다.

이것은 시간이 지남에 따라 다른 프로젝트를 수행하는 데 매우 귀찮은 접근법입니다. 그러나 몇 가지 단점과 단점이 있습니다.

단점

이는 소프트웨어 전체의 일관성을 상당 부분 구현하는 데 도움이 되지만 실제 인터페이스를 구현하지는 않지만 에뮬레이션합니다. 정의, 기본값, 경고 또는 오류 설명 되어 있지만, 개발자는 JavaScript를 많이 사용하는 것처럼 사용에 대한 예외를 적용하고 주장 합니다.

이것은 “JavaScript의 인터페이스”에 대한 최선의 접근 방법으로 보이지만 다음 사항이 해결 된 것을보고 싶습니다.

  • 반환 유형의 어설 션
  • 서명의 주장
  • delete동작 에서 객체 고정
  • JavaScript 커뮤니티의 특이성에 널리 퍼져 있거나 필요한 것의 주장

즉, 이것이 내 팀과 나만큼 도움이되기를 바랍니다.


답변

정적으로 유형이 지정되고 컴파일 중에 클래스 간 계약을 알아야하므로 Java로 인터페이스가 필요합니다. JavaScript에서는 다릅니다. 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;


답변

트랜스 컴파일러를 사용하려면 TypeScript를 사용해보십시오. 이는 coffeescript 또는 babel과 같은 언어와 유사한 초안 ECMA 기능 (제안서에서 인터페이스를 ” 프로토콜 ” 이라고 함 )을 지원합니다.

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"
}

할 수없는 것 :