JS로 몇 가지 확장 메서드를 작성해야합니다. C #에서이 작업을 수행하는 방법을 알고 있습니다. 예:
public static string SayHi(this Object name)
{
return "Hi " + name + "!";
}
다음에 의해 호출됩니다.
string firstName = "Bob";
string hi = firstName.SayHi();
JavaScript에서 이와 같은 작업을 어떻게 수행합니까?
답변
자바 스크립트는 C #의 확장 메서드에 대한 정확한 아날로그가 없습니다. JavaScript와 C #은 완전히 다른 언어입니다.
가장 유사한 방법은 모든 문자열 객체의 프로토 타입 객체를 수정하는 것입니다 : String.prototype
. 일반적으로, 가장 좋은 방법은 없습니다 당신이 통제하지 않는 다른 코드와 결합을 의미 라이브러리 코드의 개체 내장의 프로토 타입을 수정할 수 있습니다. (애플리케이션에 포함 된 다른 코드를 제어하는 애플리케이션에서 수행하는 것은 괜찮습니다.)
당신이 경우에 할 수 는 A 내장이있는 만들기 위해 (지금까지) 최선의 프로토 타입 수정 비 열거 사용하여 속성을 Object.defineProperty
(이전 그러니까 기본적으로, ES5 +를 현대의 자바 스크립트 환경, 그리고 IE8¹ 이상). 다른 문자열 메서드의 열거 가능성, 쓰기 가능성 및 구성 가능성을 일치 시키려면 다음과 같습니다.
Object.defineProperty(String.prototype, "SayHi", {
value: function SayHi() {
return "Hi " + this + "!";
},
writable: true,
configurable: true
});
(기본값은 enumerable
입니다 false
.)
더 이상 사용되지 않는 환경을 지원해야하는 경우 String.prototype
특히에 대해 열거 가능한 속성을 만들 수 있습니다.
// Don't do this if you can use `Object.defineProperty`
String.prototype.SayHi = function SayHi() {
return "Hi " + this + "!";
};
그것은 좋은 생각이 아니지만 당신은 그것을 피할 수 있습니다. 절대로 으로 그렇게하지 Array.prototype
나Object.prototype
. 여기에 열거 가능한 속성을 만드는 것은 Bad Thing ™입니다.
세부:
JavaScript는 프로토 타입 언어입니다. 이는 모든 객체가 프로토 타입 객체에 의해 뒷받침된다는 것을 의미 합니다 . JavaScript에서 해당 프로토 타입은 다음 네 가지 방법 중 하나로 지정됩니다.
- 바이 생성자 함수 오브젝트 (예를 들면,
new Foo
포함 된 객체를 생성Foo.prototype
의 프로토 타입) - 바이
Object.create
ES5에서 추가 기능 (2009) - 에 의해
__proto__
접근 자 속성 (ES2015 +, 전용 웹 브라우저에서,이 표준화되기 전에 일부 환경에 존재) 또는Object.setPrototypeOf
(ES2015 +) - 메소드를 호출하기 때문에 원시 객체를 생성 할 때 JavaScript 엔진에 의해 ( “프로모션”이라고도 함)
따라서 귀하의 예제에서는 firstName
문자열 프리미티브이므로 String
메서드를 호출 할 때마다 인스턴스로 승격 되며 해당 String
인스턴스의 프로토 타입은 String.prototype
. 따라서 함수 String.prototype
를 참조 하는 속성을 추가 SayHi
하면 해당 함수를 모든 String
인스턴스에서 사용할 수 있습니다 (그리고 승격되기 때문에 문자열 프리미티브에서도 효과적으로 사용할 수 있음 ).
예:
이 확장 메서드와 C # 확장 메서드 사이에는 몇 가지 주요 차이점이 있습니다.
-
( DougR 이 주석에서 지적했듯이) C #의 확장 메서드 는
null
reference에서 호출 될 수 있습니다 .string
확장 메서드 가있는 경우이 코드 :string s = null; s.YourExtensionMethod();
공장. JavaScript에서는 그렇지 않습니다.
null
자체 유형이며의 모든 속성 참조null
는 오류를 발생시킵니다. (그렇지 않은 경우에도 Null 유형에 대해 확장 할 프로토 타입이 없습니다.) -
( ChrisW 가 주석에서 지적했듯이) C #의 확장 메서드는 전역 적이 지 않습니다. 확장 메서드를 사용하는 코드에서 정의 된 네임 스페이스를 사용하는 경우에만 액세스 할 수 있습니다. (정적 호출에 대한 구문 설탕이므로에서 작동합니다
null
.) JavaScript에서는 사실이 아닙니다. 내장 된 프로토 타입을 변경하면 해당 변경 사항이 전체 영역의 모든 코드에 표시됩니다. (영역은 전역 환경 및 관련 내장 객체 등)에서 수행하십시오. 따라서 웹 페이지에서이 작업을 수행하면 해당 페이지에서로드하는 모든 코드에 변경 사항이 적용됩니다. 당신은 Node.js를 모듈에서이 작업을 수행 할 경우, 모든 해당 모듈과 동일한 영역에로드 된 코드는 변경 사항을 볼 수 있습니다. 두 경우 모두 라이브러리 코드에서이 작업을 수행하지 않는 이유입니다. (그들은 메인 스레드가 아닌 다른 지구 환경과 다른 내장 함수를 가지고 있도록 웹 노동자와 Node.js를 작업자 스레드가 자신의 영역에서로드됩니다.하지만 그 영역은 아직 어떤 모듈을 공유 그들은 로드합니다.)
¹ IE8에는가 Object.defineProperty
있지만 JavaScript 객체가 아닌 DOM 객체에서만 작동합니다. String.prototype
JavaScript 객체입니다.
답변
전역 증가 사용
declare global {
interface DOMRect {
contains(x:number,y:number): boolean;
}
}
/* Adds contain method to class DOMRect */
DOMRect.prototype.contains = function (x:number, y:number) {
if (x >= this.left && x <= this.right &&
y >= this.top && y <= this.bottom) {
return true
}
return false
};