JavaScript 유형 타입 시스템은 고전적인 클래스 시스템을 모방하는 것 이상으로 무엇을 할 수 있습니까?
어떤 종류의 시스템은 기존 클래스 시스템보다 훨씬 유연 해 보이지만 사람들은 어떤 종류의 시스템을 모방 한 소는 "모범"에 만족하는 것 같다.
function foo() {
// define instance properties here
}
foo.prototype.method = //define instance method here
new foo()
타입 타입 시스템이 모든 유연성으로 할 수있는 다른 일이 있어야합니다.
모방 클래스 외부의 범용 시스템에 대한 용도가 있습니까? 클래스가 할 수없는 일련의 타입은 어떤 일을 할 수 있습니까?
-type 시스템은 프로토 표준 object-를 통해 상속을 구현함으로써 매혹적인 메타 프로그래밍 모델을 제공 합니다. 물론 이것은 인스턴스 클래스의 표현되고 단순한 개념을 표현하는 데 주로 사용되는 클래스를 생성하기 위해 특정 구문이 필요한 언어 수준의 불변 구조로 클래스가 없습니다. 일반 객체를 사용하여 객체에 대해 할 수있는 모든 작업 (모든 작업을 수행 할 수 있음)을 이제 "클래스"에서 수행 할 수 있습니다. 이것이 바로 유연성입니다.
이 유연성은 JavaScript의 주어진 객체 변형 기능만을 사용하여 프로그래밍 방식으로 많이 사용됩니다.
- 다중 상속을위한 믹스 인 및 특성
- 유형 유형은 상속 된 객체가 인스턴스화 된 후에 수정 될 수 있습니다.
- 고차 함수 생성 및 방법 데코레이터는 쉽게 사용할 수 있습니다.
물론 구축 형 모델 자체는 클래스를 구현하는 것보다 더 강력합니다. 클래스 개념이 매우 유용하고 널리 퍼져 있기 때문에 거의 사용 가능합니다. (JS 엔진에서 생산되지 않는 제품 :-/).
- 기존의 기존 아이템을 전환하면 동작을 극적으로 사용할 수 있습니다. ( ES6
Reflect.setPrototypeOf
와 함께 제공되는 전체 지원 ) 몇 가지 소프트웨어 엔지니어링 패턴을 직접 구현할 수 있습니다. 예는 속성 이있는 플라이 웨이트 패턴 , 동적 체인을 포함하는 책임 체인, 오, 다양한 종류 패턴 입니다.
마지막 항목의 좋은 예는 주소가있는 옵션 개체입니다. 모두가 사용하여 만듭니다.
var myOptions = extend({}, defaultOptions, optionArgument);
그러나 더 역동적 인 접근 방식은
var myOptions = extend(Object.create(defaultOptions), optionArgument);
2013 년 6 월에 저는 클래식보다 기존 의 이점 에 대한 질문에 답 했습니다 . 그 이후로 저는 한정과 클래식 모두 상속에 대해 고민하는 데 많은 시간을 보냈고 체계적인 클래스 동형에 대해 많은 종류의 비용이 있습니다.
예, 상속 상속의 주요 용도는 클래스를 시뮬레이션하는 것입니다. 그러나 클래스를 시뮬레이션하는 것 이상으로 사용할 수 있습니다. 예를 들어 포괄적 인 체인은 범위 체인과 매우 유사합니다.
타입 타입 범위 동형도
JavaScript의 상품 유형과 범위는 많은 점이 있습니다. JavaScript에는 세 가지 일반적인 유형의 체인이 있습니다.
타입 타입 체인.
var foo = {}; var bar = Object.create(foo); var baz = Object.create(bar); // chain: baz -> bar -> foo -> Object.prototype -> null
범위 체인.
function foo() { function bar() { function baz() { // chain: baz -> bar -> foo -> global } } }
메소드 체인.
var chain = { foo: function () { return this; }, bar: function () { return this; }, baz: function () { return this; } }; chain.foo().bar().baz();
세 가지 중 하나 타입 체인과 스코프 체인이 가장 유사합니다. 악명 높은 문장을 사용하여 대부분의 체인을 범위 체인에 사용할 수 있습니다 .with
function foo() {
var bar = {};
var baz = Object.create(bar);
with (baz) {
// chain: baz -> bar -> Object.prototype -> foo -> global
}
}
사용은 무엇입니까? 한 가지 용도는 범용 체인을 사용하여 범위 체인을 모델링하는 것입니다. 이것이 바로 제가 자바 펼쳐보기로 구현 한 제 프로그래밍 언어 인 Bianca를 위해 한 일입니다.
먼저 Bianca의 전역 범위를 정의하여 다음과 같이 이해하게 global.js 라는 파일에 유용한 수학 함수를 채웠습니다 .
var global = module.exports = Object.create(null);
global.abs = new Native(Math.abs);
global.acos = new Native(Math.acos);
global.asin = new Native(Math.asin);
global.atan = new Native(Math.atan);
global.ceil = new Native(Math.ceil);
global.cos = new Native(Math.cos);
global.exp = new Native(Math.exp);
global.floor = new Native(Math.floor);
global.log = new Native(Math.log);
global.max = new Native(Math.max);
global.min = new Native(Math.min);
global.pow = new Native(Math.pow);
global.round = new Native(Math.round);
global.sin = new Native(Math.sin);
global.sqrt = new Native(Math.sqrt);
global.tan = new Native(Math.tan);
global.max.rest = { type: "number" };
global.min.rest = { type: "number" };
global.sizeof = {
result: { type: "number" },
type: "function",
funct: sizeof,
params: [{
type: "array",
dimensions: []
}]
};
function Native(funct) {
this.funct = funct;
this.type = "function";
var length = funct.length;
var params = this.params = [];
this.result = { type: "number" };
while (length--) params.push({ type: "number" });
}
function sizeof(array) {
return array.length;
}
을 사용하여 전역 범위를 만들었습니다 Object.create(null)
. 전역 범위에 부모 범위가 없기 때문에 이렇게했습니다.
그 후 각 프로그램에 대해 소개하는 프로그램의 최상위 정의를 보유하는 별도의 프로그램 범위를 만들었습니다. 코드는 하나의 답변에 맞기에는 너무 큰 analyzer.js 라는 파일에 저장 됩니다. 다음은 파일의 처음 세 줄입니다.
var parse = require("./ast");
var global = require("./global");
var program = Object.create(global);
보시다시피 전역 범위는 프로그램 범위의 상위입니다. 상속에서 program
상속 global
하여 범위 변수 조회를 객체 속성처럼 간단하게 만듭니다. 이 언어의 실행을 훨씬 더 간단하게 만듭니다.
프로그램 범위에는 프로그램의 최상위 수준 정의가 포함됩니다. 예를 들어, matrix.bianca 파일에 많은 다음 곱셈 프로그램을 고려 합니다.
col(a[3][3], b[3][3], i, j)
if (j >= 3) a
a[i][j] += b[i][j]
col(a, b, i, j + 1)
row(a[3][3], b[3][3], i)
if (i >= 3) a
a = col(a, b, i, 0)
row(a, b, i + 1)
add(a[3][3], b[3][3])
row(a, b, 0)
최상위 수준 정의는 col
, row
및 add
입니다. 상속되는 자체 함수 범위도 있습니다. 이에 대한 코드 는 analyzer.js의 67 행 에서 사용할 수 있습니다 .
scope = Object.create(program);
를 들어의 예 함수 범위 add
에는 행렬 a
및에 , 대한 정의가 b
있습니다.
유사 클래스 유형 외에도 함수 범위를 모델링하는 데 유용합니다.
대수 데이터 유형 모델링을위한 준비 유형
클래스는 사용 가능한 유일한 추상화 유형이 아닙니다. 프로그래밍 언어에서 함수형 데이터는 대수 데이터 유형을 사용하여 모델링 됩니다 .
대수 데이터 유형의 가장 좋은 예는 목록입니다.
data List a = Nil | Cons a (List a)
이 데이터 정의는 a의 목록이 빈 목록 (예 :) Nil
이거나 a의 목록에 삽입 된 "a"유형의 값 (예 :) 일 수 Cons a (List a)
있음을 의미합니다. 예를 들어 다음은 모두 목록입니다.
Nil :: List a
Cons 1 Nil :: List Number
Cons 1 (Cons 2 Nil) :: List Number
Cons 1 (Cons 2 (Cons 3 Nil)) :: List Number
a
데이터 정의 의 유형 변수 는 다음 변수 다형성을 활성화합니다 (즉, 목록이 모든 유형의 값을 보유 할 수 있도록 허용). 예를 들어, Nil
이 유형이 있기 때문에 숫자의 목록 또는 논리 값의 목록에 전문 수 아무것도 될 수 있습니다.List a
a
이를 통해 length
다음 과 같은 파라 프로그램 함수를 만들 수 있습니다 .
length :: List a -> Number
length Nil = 0
length (Cons _ l) = 1 + length l
length
기능에 관계없이 포함 된 값의 유형의 목록의 길이를 찾는 데 사용할 수있는 length
기능은 목록의 값에 상관하지 않습니다.
대부분의 함수형 프로그래밍 언어에는 임시 다형성이 있습니다. 임시 다형성에서 함수의 특정 구현은 다형성 변수의 유형에 따라 선택됩니다.
예를 들어, +
JavaScript 의 연산자는 인수 유형에 따라 더하기 및 사용됩니다. 이것은 임시 다형성의 한 형태입니다.
대부분의 함수형 프로그래밍 언어에서 map
함수는 일반적으로 오버로드됩니다. 예를 들어, map
목록의 다른 구현, 집합에 대한 다른 구현 등 이있을 수 있습니다 . 유형 클래스는 임시 다형성을 구현하는 한 가지 방법입니다. 예를 들어, 유형 클래스는 다음 함수를 제공합니다 .Functor
map
class Functor f where
map :: (a -> b) -> f a -> f b
그런 다음 Functor
다양한 데이터 유형 에 대한 특정 인스턴스를 만듭니다 .
instance Functor List where
map :: (a -> b) -> List a -> List b
map _ Nil = Nil
map f (Cons a l) = Cons (f a) (map f l)
JavaScript의 유형을 사용하면 대수 데이터 유형과 임시 다형성을 모두 모델링 할 수 있습니다. 예를 들어 위의 코드는 다음과 같이 JavaScript로 일대일로 번역 될 수 있습니다.
var list = Cons(1, Cons(2, Cons(3, Nil)));
alert("length: " + length(list));
function square(n) {
return n * n;
}
var result = list.map(square);
alert(JSON.stringify(result, null, 4));
<script>
// data List a = Nil | Cons a (List a)
function List(constructor) {
Object.defineProperty(this, "constructor", {
value: constructor || this
});
}
var Nil = new List;
function Cons(head, tail) {
var cons = new List(Cons);
cons.head = head;
cons.tail = tail;
return cons;
}
// parametric polymorphism
function length(a) {
switch (a.constructor) {
case Nil: return 0;
case Cons: return 1 + length(a.tail);
}
}
// ad-hoc polymorphism
List.prototype.map = function (f) {
switch (this.constructor) {
case Nil: return Nil;
case Cons: return Cons(f(this.head), this.tail.map(f));
}
};
</script>
클래스를 사용하여 임시 다형성을 모델링 할 수있는 모든 오버로드 된 함수를 한곳에서 정의해야합니다. 타입 타입을 사용하면 원하는 위치에 정의 할 수 있습니다.
결론
보시다시피 종류는 다양합니다. 예, 주로 클래스를 모델링하는 데 사용됩니다. 그러나 많은 이들이 많은 것들에 있습니다.
타입 타입을 사용할 수있는 다른 것들 :
구조적 공유로 지속적인 데이터 구조 생성 .
구조적 공유의 기본 개념은 개체를 수정하는 대신 원래 개체에서 상속 된 새 개체를 만들고 원하는대로 수정하는 것입니다. 프로토 타입 상속은 그 점에서 탁월합니다.
다른 사람들이 언급했듯이 프로토 타입은 동적입니다. 따라서 새 프로토 타입 메서드를 소급하여 추가 할 수 있으며 프로토 타입의 모든 인스턴스에서 자동으로 사용할 수 있습니다.
도움이 되었기를 바랍니다.
프로토 타입 상속 시스템은 메서드 / 속성의 훨씬 더 동적 인 추가를 허용한다고 생각합니다.
다른 사람들이 작성한 클래스를 쉽게 확장 할 수 있습니다. 예를 들어 모든 jQuery 플러그인이 여기에 있습니다. 네이티브 클래스에 쉽게 추가하고 문자열, 배열 등에 유틸리티 함수를 추가 할 수도 있습니다.
예:
// I can just add whatever I want to anything I want, whenever I want
String.prototype.first = function(){ return this[0]; };
'Hello'.first() // == 'H'
다른 클래스에서 메서드를 복사 할 수도 있습니다.
function myString(){
this[0] = '42';
}
myString.prototype = String.prototype;
foo = new myString();
foo.first() // == '42'
또한 개체가 상속 된 후 프로토 타입 을 확장 할 수 있지만 변경 사항이 적용됩니다.
그리고 개인적으로 프로토 타입이 정말 편리하고 간단하다는 것을 알게되었습니다. 객체 내에 메서드를 배치하는 것이 정말 매력적입니다.)
JavaScript에는 Class라는 개념이 없습니다. 여기 모든 것이 객체입니다. 그리고 JavaScript의 모든 객체는 Object 에서 속인 것 입니다. 프로토 타입 속성은 객체 지향 방식으로 애플리케이션을 개발할 때 상속에 도움이됩니다. 프로토 타입에는 전통적인 객체 지향 구조의 클래스보다 더 많은 기능이 있습니다.
프로토 타입에서는 다른 사람이 작성한 함수에 속성을 추가 할 수 있습니다.
예를 들어.
Array.prototype.print=function(){
console.log(this);
}
상속에 사용 :
프로토 타입 속성을 사용하여 상속을 사용할 수 있습니다. 다음 은 JavaScript에서 상속을 사용하는 방법입니다.
기존의 클래스 시스템에서는 클래스가 정의 된 후에는 수정할 수 없습니다. 하지만 당신은 프로토 타입 시스템으로 자바 스크립트로 할 수 있습니다.
'ProgramingTip' 카테고리의 다른 글
가상 할당 연산자 C ++ (0) | 2020.11.18 |
---|---|
“geom_histogram”을 사용할 때“unit (tic_pos.c,”mm“) : 'x'및 'units'의 길이가 0보다 커야합니다. (0) | 2020.11.18 |
리포지토리 패턴-이를 이해하는 방법과 "복잡한"엔터티와 어떻게 작동합니까? (0) | 2020.11.18 |
Eclipse 프로젝트에서 사용 된 미사용 항아리 찾기 (0) | 2020.11.18 |
HTML 속성 이름에 허용되는 문자는 무엇입니까? (0) | 2020.11.18 |