Javascript의 다형성이란 무엇입니까?


91

나는 인터넷에서 다형성 에 관한 기사를 읽을 수 있었다 . 하지만 그 의미와 그 중요성을 잘 이해하지 못했다고 생각합니다. 대부분의 기사에서는 이것이 왜 중요한지, 그리고 OOP (물론 JavaScript에서)에서 다형성 동작을 어떻게 달성 할 수 있는지에 대해 설명하지 않습니다.

구현 방법에 대한 아이디어가 없기 때문에 코드 예제를 제공 할 수 없으므로 내 질문은 다음과 같습니다.

  1. 뭔데?
  2. 왜 필요합니까?
  3. 어떻게 작동합니까?
  4. 자바 스크립트에서이 다형성 동작을 어떻게 얻을 수 있습니까?

이 예가 있습니다. 그러나이 코드의 결과가 무엇인지 쉽게 이해할 수 있습니다. 다형성 자체에 대한 명확한 아이디어를 제공하지 않습니다.

function Person(age, weight) {
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo.";
    }
}
function Employee(age, weight, salary) {
    this.salary = salary;
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo " +
        "and earns " + this.salary + " dollar.";
    }
}

Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
  // The argument, 'obj', can be of any kind
  // which method, getInfo(), to be executed depend on the object
  // that 'obj' refer to.

function showInfo(obj) {
    document.write(obj.getInfo() + "<br>");
}

var person = new Person(50,90);
var employee = new Employee(43,80,50000);
showInfo(person);
showInfo(employee);

이 질문은 아마도 너무 광범위하여 StackOverflow에서 잘 작동하지 않을 것입니다. 우리가 할 수있는 최선의 방법은 여러분을 다른 다형성 설명에 연결하는 것입니다. StackOverflow는 "소스가 다형성이 XYZ라고 말했지만 Y는 무엇을 의미합니까?"와 같이 특정 문제에 대한 특정 질문이나 설명에 가장 적합합니다.
Vitruvius 2014

2
당신은 그것을 필요로하지 않습니다. 조금도. JS에서 클래스도 필요하지 않으며 실제로 앱 구축을위한 다른 많은 패러다임이 있습니다. 적용 / 호출 / 바인딩은 균질성에 대한 필요성을 제거하고 소프트 오브젝트를 사용하면 미리 장식하거나 특별한 경우를 상속하지 않고도 필요에 맞게 모든 것을 수정할 수 있습니다.
dandavis 2014

1
다형성은 OO와 관련된 것이 아니라 많은 의미를 가지고 있습니다. Is Polymorphism Possible without Inheritance 질문에서이 다른 답변을 읽을 수 있습니다 .
Edwin Dalorzo 2014

상속은 일반적으로 JavaScript에서 잘못 수행됩니다. Child의 프로토 타입으로 사용할 Parent의 인스턴스를 생성하려면 생성자 함수와 프로토 타입이 객체를 정의하고 생성하는 역할에 대한 이해 부족을 보여줍니다. 자세한 내용은 다음 답변에서 확인할 수 있습니다. stackoverflow.com/a/16063711/1641941
HMR

답변:


99

다형성은 객체 지향 프로그래밍 (OOP)의 신조 중 하나입니다. 동작을 공유하고 특정 동작으로 공유 동작을 재정의 할 수 있도록 객체를 디자인하는 관행입니다. 다형성은이를 실현하기 위해 상속을 이용합니다.

OOP에서는 모든 것이 객체로 모델링되는 것으로 간주됩니다. 이 추상화는 자동차의 너트와 볼트까지, 또는 1 년, 제조사, 모델이있는 단순한 자동차 유형만큼 광범위하게 적용 할 수 있습니다.

다형성 자동차 시나리오를 가지려면 기본 자동차 유형이 있고 자동차에서 상속하고 자동차가 갖는 기본 동작 위에 자체 동작을 제공하는 하위 클래스가 있습니다. 예를 들어, 하위 클래스는 TowTruck이 될 수 있으며, 이는 여전히 연도 제조업체와 모델을 보유 할 수 있지만 IsTowing에 대한 플래그만큼 기본이 될 수있는 몇 가지 추가 동작 및 속성을 리프트의 세부 사항만큼 복잡 할 수 있습니다.

사람과 직원의 예를 다시 살펴보면 모든 직원은 사람이지만 모든 사람은 직원이 아닙니다. 즉, 사람들은 수퍼 클래스가되고 직원은 하위 클래스가 될 것입니다. 사람들은 나이와 몸무게가있을 수 있지만 급여는 없습니다. 직원은 사람이므로 본질적으로 나이와 몸무게가 있지만 직원이기 때문에 급여를받습니다.

따라서이를 용이하게하기 위해 먼저 수퍼 클래스 (Person)를 작성합니다.

function Person(age,weight){
 this.age = age;
 this.weight = weight;
}

그리고 우리는 Person에게 그들의 정보를 공유 할 수있는 능력을 줄 것입니다.

Person.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo.";
};

다음으로 Person, Employee의 하위 클래스를 갖고 싶습니다.

function Employee(age,weight,salary){
 this.age = age;
 this.weight = weight;
 this.salary = salary;
}
Employee.prototype = new Person();

그리고 Employee에 더 적합한 것을 정의하여 getInfo의 동작을 재정의합니다.

Employee.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo " +
    "and earns " + this.salary + " dollar.";  
};

원래 코드 사용과 유사하게 사용할 수 있습니다.

var person = new Person(50,90);
var employee = new Employee(43,80,50000);

console.log(person.getInfo());
console.log(employee.getInfo());

그러나 Employee의 생성자가 사람의 생성자와 매우 유사하고 프로토 타입의 유일한 기능이 재정의되기 때문에 여기서 상속을 사용하여 얻을 수있는 것은 많지 않습니다. 다형성 디자인의 힘은 행동을 공유하는 것입니다.


2
@ user3138436-맞습니다. 프로토 타입 체인은 getInfoPerson보다 체인에서 더 높기 때문에 Employee의 첫 번째 발생에 대해 검사 됩니다. 그것이 내가 "무시하다"고 말했을 때의 의미였습니다.
Travis J

17
생성자 (Person.call (this, arg))를 다시 사용하지 않고 Employee 프로토 타입을 Person 인스턴스로 설정하지 않습니다. 프로토 타입은 공유 멤버가가는 곳이고 생성자 함수는 인스턴스 특정 멤버가 생성되는 곳입니다. 샘플은 복사 붙여 넣기 코드를 사용하여 생성자 함수를 다시 사용하고 프로토 타입 부분을 잘못 상속합니다 (Person에는 특히 변경 가능한 멤버가있는 경우 Employee.prototype에 비즈니스가없는 인스턴스 특정 멤버가 있음). 생성자 함수 및 프로토 타입을 사용한 상속에 대한 자세한 정보는 다음을 참조하십시오. stackoverflow.com/a/16063711/1641941
HMR

3
Employee가 사람의 getinfo를 재사용하고 확장하려면 return Person.prototype.getInfo.call(this) + + "and earns " + this.salary + " dollar.";복사 붙여 넣기 코드를 재사용하는 대신 간단하게 할 수 있습니다.
HMR 2014

3
여기서 다형성이 적용된 곳은?
알버트 Jegani

2
@rpeg 다형성의 요점은 OPs 예제에서 더 잘 볼 수 있습니다. 함수 showInfo (); 일반 객체를받습니다. 다형성은 이제 객체 유형에 따라 다르게 반응하는 능력입니다. 나는이 대답이 모든 특정 객체에 대해 getInfo ()를 호출하기 때문에 이것을 충분히 명확하게하지 않는다고 생각합니다.
Stefan

26

이 다른 답변 에서 설명했듯이 다형성은 다른 해석을 가지고 있습니다.

내가 읽은 주제에 대한 가장 좋은 설명 은 유명한 유형 이론가 인 Luca Cardelli 의 기사 입니다. 이 기사의 이름은 On Understanding Types, Data Abstraction 및 Polymorphism 입니다.

그것은 무엇입니까?

Cardelli는이 기사에서 여러 유형의 다형성을 정의합니다.

  • 만능인
    • 파라 메트릭
    • 포함
  • 애드 혹
    • oveloading
    • 강제

아마도 JavaScript에서는 다형성의 효과를보기가 조금 더 어려울 수 있습니다. 왜냐하면보다 고전적인 유형의 다형성이 정적 유형 시스템에서 더 분명해지기 때문에 JavaScript에는 동적 유형 시스템이 있기 때문입니다.

예를 들어 JavaScript에서는 컴파일 타임에 메서드 나 함수 오버로딩이나 자동 유형 강제 변환이 없습니다. 동적 언어에서 우리는 이러한 대부분을 당연한 것으로 간주합니다. 언어의 동적 특성으로 인해 JavaScript에서 매개 변수 다형성과 같은 것이 필요하지 않습니다.

그럼에도 불구하고 JavaScript는 Java 또는 C #과 같은 다른 객체 지향 프로그래밍 언어에서 일반적으로 수행하는 것과 유사한 방식으로 하위 유형 다형성 (위의 Cardelli에 의해 포함 다형성으로 분류 됨)의 동일한 아이디어를 에뮬레이트하는 유형 상속의 한 형태를 가지고 있습니다. 위에서 공유 한 또 다른 답변).

동적 언어에서 매우 일반적인 또 다른 형태의 다형성은 덕 타이핑 이라고 합니다.

다형성이 객체 지향 프로그래밍에만 관련되어 있다고 믿는 것은 실수입니다. 다른 프로그래밍 모델 (기능적, 절차 적, 논리 등)은 유형 시스템에서 다른 형태의 다형성을 제공합니다. 아마도 OOP에만 사용되는 방식에는 약간 익숙하지 않을 것입니다.

왜 필요한가?

다형성은 소프트웨어에서 많은 좋은 속성을 조성하며, 무엇보다도 모듈 성과 재사용 성을 촉진하고 유형 시스템을보다 유연하고 유연하게 만듭니다. 그것 없이는 유형에 대해 추론하기가 정말 어려울 것입니다. 다형성은 한 유형이 공용 인터페이스를 충족하는 경우 다른 호환 가능한 유형으로 대체 될 수 있도록하므로 정보 숨기기 및 모듈화도 촉진됩니다.

어떻게 작동합니까?

이것은 대답하기 쉽지 않습니다. 언어마다 구현 방법이 다릅니다. JavaScript의 경우 위에서 언급했듯이 프로토 타입 상속을 사용하여 유형 계층의 형태로 구체화되는 것을 볼 수 있으며 덕 타이핑을 사용하여 활용할 수도 있습니다.

주제는 약간 광범위하며 단일 게시물에서 두 개의 많은 질문을 열었습니다. Cardelli의 논문을 읽고 언어 나 프로그래밍 패러다임에 관계없이 다형성을 이해하려고 시도하는 것이 가장 좋을 것입니다. 그러면 이론적 개념과 JavaScript와 같은 특정 언어가 이러한 아이디어를 구현하기 위해 제공해야하는 것 사이에 연관성을 만들기 시작할 것입니다.


14

다형성의 목적은 무엇입니까?

다형성은 유형 동등성에 대한 조건을 완화하여 정적 유형 안전성을 잃지 않고 정적 유형 시스템을보다 유연하게 만듭니다. 프로그램은 유형 오류가없는 경우에만 실행된다는 증거가 있습니다.

다형성 함수 또는 데이터 유형은 더 넓은 범위의 시나리오에서 사용할 수 있기 때문에 단일형 함수보다 더 일반적입니다. 이러한 의미에서 다형성은 엄격하게 형식화 된 언어의 일반화 개념을 나타냅니다.

이것이 Javascript에 어떻게 적용됩니까?

Javascript에는 약하고 동적 유형 시스템이 있습니다. 이러한 유형 시스템은 하나의 유형 만 포함하는 엄격한 유형 시스템과 동일합니다. 이러한 유형을 거대한 공용체 유형 (의사 구문)으로 생각할 수 있습니다.

type T =
 | Undefined
 | Null
 | Number
 | String
 | Boolean
 | Symbol
 | Object
 | Array
 | Map
 | ...

모든 값은 런타임에 이러한 대체 유형 중 하나에 연결됩니다. 그리고 Javascript는 약한 유형이기 때문에 모든 값은 여러 번 유형을 변경할 수 있습니다.

유형 이론적 관점을 취하고 하나의 유형 만 있다고 생각하면 Javascript의 유형 시스템에는 다형성 개념이 없음을 확실하게 말할 수 있습니다. 대신 우리는 덕 타이핑과 암시 적 타입 강제를 가지고 있습니다.

그러나 이것이 우리 프로그램의 유형에 대해 생각하는 것을 막아서는 안됩니다. 자바 스크립트에는 타입이 없기 때문에 코딩 과정에서 유추해야합니다. 우리의 마음은 빠진 컴파일러에 대해 서 있어야합니다. 즉, 프로그램을 보자 마자 알고리즘뿐만 아니라 기본 (다형성) 유형도 인식해야합니다. 이러한 유형은보다 안정적이고 강력한 프로그램을 구축하는 데 도움이됩니다.

이 작업을 제대로 수행하기 위해 가장 일반적인 다형성 현상에 대한 개요를 제공하겠습니다.

파라 메트릭 다형성 (일명 제네릭)

Parametric polymorphism은 유형이 전혀 중요하지 않기 때문에 서로 다른 유형이 상호 교환 가능하다고 말합니다. 매개 변수 다형성 유형의 하나 이상의 매개 변수를 정의하는 함수는 해당 인수에 대해 아무것도 알지 못하지만 모든 유형에 채택 할 수 있으므로 모두 동일하게 처리해야합니다. 이러한 함수는 데이터의 일부가 아닌 인수의 속성으로 만 작동 할 수 있기 때문에 이것은 매우 제한적입니다.

// parametric polymorphic functions

const id = x => x;

id(1); // 1
id("foo"); // "foo"

const k = x => y => x;
const k_ = x => y => y;

k(1) ("foo"); // 1
k_(1) ("foo"); // "foo"

const append = x => xs => xs.concat([x]);

append(3) ([1, 2]); // [1, 2, 3]
append("c") (["a", "b"]); // ["a", "b", "c"]

임시 다형성 (일명 오버로딩)

임시 다형성은 서로 다른 유형이 특정 목적에 대해서만 동등하다고 말합니다. 이러한 의미에서 동등 해지려면 유형은 해당 목적에 특정한 함수 세트를 구현해야합니다. 임시 다형성 유형의 매개 변수를 하나 이상 정의하는 함수는 각 인수에 연결된 함수 집합을 알아야합니다.

임시 다형성은 함수가 더 큰 유형의 도메인과 호환되도록합니다. 다음 예제는 "맵 오버"목적과 유형이이 제약 조건을 구현하는 방법을 보여줍니다. 함수 집합 대신 "맵핑 가능"제약 조건에는 단일 map함수 만 포함 됩니다.

// Option type
class Option {
  cata(pattern, option) {
    return pattern[option.constructor.name](option.x);
  }
  
  map(f, opt) {
    return this.cata({Some: x => new Some(f(x)), None: () => this}, opt);
  }
};

class Some extends Option {
  constructor(x) {
    super(x);
    this.x = x;
  }
};

class None extends Option {
  constructor() {
    super();
  }
};


// ad-hoc polymorphic function
const map = f => t => t.map(f, t);

// helper/data

const sqr = x => x * x;

const xs = [1, 2, 3];
const x = new Some(5);
const y = new None();

// application

console.log(
  map(sqr) (xs) // [1, 4, 9]
);

console.log(
  map(sqr) (x) // Some {x: 25}
);

console.log(
  map(sqr) (y) // None {}
);

하위 유형 다형성

다른 답변은 이미 하위 유형 다형성을 다루기 때문에 건너 뜁니다.

구조적 다형성 (일명 구조적 하위 유형 지정)

구조적 다형성은 서로 다른 유형이 동일한 방식으로 동일한 구조를 포함하면 한 유형이 다른 유형의 모든 속성을 갖지만 추가 속성을 포함 할 수 있다고 말합니다. 즉, 구조적 다형성은 컴파일 타임에 덕 타이핑이며 확실히 추가적인 타입 안전성을 제공합니다. 그러나 두 값이 일부 속성을 공유하기 때문에 동일한 유형이라고 주장함으로써 값의 의미 수준을 완전히 무시합니다.

const weight = {value: 90, foo: true};
const speed =  {value: 90, foo: false, bar: [1, 2, 3]};

불행히도 speed는의 하위 유형으로 간주 weight되며 value속성을 비교하자마자 사과와 오렌지를 가상으로 비교합니다.


1
이것은 여러 측면에서 더 정확하지만 에서 허용 된 답변보다 (확실히 더 철저 함), 동일한 접근성을 갖지 않습니다.이 답변은 질문자가 이미 질문을 처리하기에는 너무 똑똑하다고 가정합니다. :)
Jared Smith

@JaredSmith 저는 이해하기 쉬운 단락으로 주제를 요약하려고했습니다. 하지만 더 깊게 드릴수록 더 복잡해집니다. 나는 유형이 지정되지 않은 언어에서 다형성에 대한 좋은 소스를 찾지 못했기 때문에이 대답은 그럼에도 불구하고 가치 있다고 생각합니다.

편집은 접근성을 크게 향상시킵니다. 동적 언어에서 다형성의 유용성에 관해서는 많은 것이 있지만 JS에서 좋은 예를 생각하기 위해 고군분투하고 있습니다. 더 좋은 예는 사용자 정의 유형이 .NET과 같은 다형성 함수와 함께 작동하도록 허용하는 Python의 매직 메서드입니다 len. 또는 conjclojure에서.
자레드 스미스

8

뭐야?

Poly = many, morphism = form 또는 행동 변화.

왜 우리가 그것을 필요로합니까?

프로그래밍에서 함수 (함수 X)의 인터페이스가 다른 유형이나 매개 변수 수를 수용 할 수있을만큼 유연하기를 원할 때 사용됩니다. 또한 매개 변수 유형 또는 숫자 변경에 따라 함수 X가 다르게 동작하기를 원할 수 있습니다 (모피 즘).

어떻게 작동합니까?

각 구현이 서로 다른 매개 변수 유형 또는 매개 변수 수를 허용하는 X 함수의 여러 구현을 작성합니다. 매개 변수의 유형 또는 수에 따라 컴파일러 (런타임시)는 X가 일부 코드에서 호출 될 때 실행되어야하는 X 구현을 결정합니다.

자바 스크립트 에서이 다형성 동작을 어떻게 얻을 수 있습니까?

JS는 형식화 된 언어가 아니므로 실제로 다형성과 같은 OOP 개념을 사용하는 것은 아닙니다. 그러나 최신 버전의 JS에는 이제 클래스가 포함되어 있으며 JS에서도 다대 시즘이 이해되기 시작할 가능성이 있습니다. 다른 답변은 몇 가지 흥미로운 해결 방법을 제공합니다.


4

다형성이란 서로 다른 객체에 대해 동일한 메서드를 호출하고 각 객체가 서로 다른 방식으로 반응하는 능력을 POLYMORPHISM 이라고 합니다 .

    function Animal(sound){
    this.sound=sound;
    this.speak=function(){
    			return this.sound;
    	}
    }
//one method 
    function showInfo(obj){
    		console.log(obj.speak());
    }
//different objects
    var dog = new Animal("woof");
    var cat = new Animal("meow");
    var cow = new Animal("humbow");
//responds different ways
    showInfo(dog);
    showInfo(cat);
    showInfo(cow);


2

JavaScript는 컴파일 된 언어가 아니라 해석 된 언어입니다.

컴파일 시간 다형성 (또는 정적 다형성) 컴파일 시간 다형성은 Java, C ++에서 메소드 오버로딩에 불과합니다.

따라서 자바 스크립트에서는 메서드 오버로딩이 불가능합니다.

그러나 동적 (런타임) 다형성은 런타임에 존재하는 다형성이므로 자바 스크립트에서 메서드 재정의가 가능합니다.

또 다른 예는 PHP입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.