JavaScript로 OOP를 만드는 방법을 배우고 있습니다. 인터페이스 개념 (예 : Java interface
)이 있습니까?
그래서 나는 청취자를 만들 수있을 것입니다 …
답변
“이 클래스에는 이러한 함수가 있어야합니다”라는 개념이 없습니다. 즉, 인터페이스 자체가 없습니다.
- JavaScript 상속은 클래스가 아닌 객체를 기반으로합니다. 당신이 깨닫기 전까지는 큰 문제가 아닙니다.
- 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 객체가 전혀 없으며 .defineProperty
IE8에서는 호스트 객체 (즉, 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"
}
할 수없는 것 :
- 유형 값에 대한 RegExp 패턴 정의
- 문자열 길이와 같은 유효성 검사 정의
- 숫자 범위
- 기타