JavaScript 재정의 방법


87

아래 코드가 있다고 가정 해 보겠습니다.

function A() {
    function modify() {
       x = 300;
       y = 400;
    }

    var c = new C();
}

function B() {
    function modify(){
       x = 3000;
       y = 4000;
    }

    var c = new C();
}

C = function () {
   var x = 10;
   var y = 20;

   function modify() {
      x = 30;
      y = 40;
   };

   modify();
   alert("The sum is: " + (x+y));
}

나는이 메소드를 오버라이드 (override) 할 수있는 어떤 방법이 있는지 이제 질문은, modify에서 C에있는 방법과 AB. Java에서는 super-keyword를 사용 하지만 JavaScript에서 이와 같은 것을 어떻게 얻을 수 있습니까?


6
modify이러한 두 가지 차이가있다 .. - 방법하지만 중첩 된 함수는 아닌
SIME VIDAS

2
Java에서는 super키워드를 사용하여 수퍼 클래스의 비공개 필드 및 메서드에 액세스 합니다. 이를 재정의하는 데 사용하지 않습니다.
FK82 2011

답변:


138

편집 : 이제 원래 답변이 작성되고 많은 것이 변경된 지 6 년이되었습니다!

  • Babel 과 같은 도구로 컴파일 된 최신 버전의 JavaScript 를 사용하는 경우 실제 클래스를 사용할있습니다 .
  • Angular 또는 React 에서 제공하는 클래스와 유사한 구성 요소 생성자를 사용하는 경우 해당 프레임 워크에 대한 문서를보고 싶을 것입니다.
  • ES5를 사용하고 프로토 타입을 사용하여 손으로 "가짜"클래스를 만드는 경우 아래 답변은 여전히 ​​옳습니다.

행운을 빕니다!


JavaScript 상속은 Java와 약간 다릅니다. 다음은 기본 JavaScript 개체 시스템의 모습입니다.

// Create a class
function Vehicle(color){
  this.color = color;
}

// Add an instance method
Vehicle.prototype.go = function(){
  return "Underway in " + this.color;
}

// Add a second class
function Car(color){
  this.color = color;
}

// And declare it is a subclass of the first
Car.prototype = new Vehicle();

// Override the instance method
Car.prototype.go = function(){
  return Vehicle.prototype.go.call(this) + " car"
}

// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"

var c = new Car("red");
c.go() // "Underway in red car"

불행히도 이것은 약간 못 생기고 "super"에 대한 아주 좋은 방법을 포함하지 않습니다. 호출 할 부모 클래스의 메서드를 수동으로 지정해야합니다. 결과적으로 클래스를 더 멋지게 만들 수있는 다양한 도구가 있습니다. Prototype.js, Backbone.js 또는 js에서 OOP를 수행하기위한 더 좋은 구문을 포함하는 유사한 라이브러리를 살펴보십시오.


2
"클래스 생성을 더 좋게 만들기"도구를 사용하는 대신 클래스를 전혀 만들 수 없습니다. js의 고전적인 OO 에뮬레이션은 항상 지저분합니다.
Raynos 2011

1
(건설적인 의견이 아님) 브라우저 세계에서 "저수준"언어라는 것은 이유없이 매우 추합니다. 아직도 배우고 있습니다. 감사합니다!
dnuske 2012

9
나는 Car.prototype = new Vehicle (); 대신 믿습니다. 이것은 Car.prototype = Object.create (Vehicle.prototype); 아니?
Jordan


왜 Car.prototype = new Vehicle (); 색상을받는 동안 Vehicle ()에 전달할 것이 없기 때문에 올바르지 않습니다.
Tushar 아 로라

62

이것은 Google에서 가장 인기있는 히트작이므로 업데이트 된 답변을 드리고자합니다.

사용 ES6 수업은 훨씬 쉽게 무시 상속 및 방법을합니다 :

'use strict';

class A {
    speak() {
        console.log("I'm A");
    }
}

class B extends A {
    speak() {
        super.speak();

        console.log("I'm B");
    }
}

var a = new A();
a.speak();
// Output:
// I'm A

var b = new B();
b.speak();
// Output:
// I'm A
// I'm B

super키워드 는 상속 클래스에서 사용될 때 부모 클래스를 참조합니다. 또한 부모 클래스의 모든 메서드는 자식의 인스턴스에 바인딩되어 있으므로 작성할 필요가 없습니다.super.method.apply(this); .

호환성에 관해서 : ES6 호환성 표 는 (대부분) 주요 플레이어 지원 클래스의 최신 버전 만 보여줍니다. V8 브라우저는 올해 1 월 (Chrome 및 Opera) 이후로이 기능을 사용했으며 SpiderMonkey JS 엔진을 사용하는 Firefox는 다음 달 공식 Firefox 45 릴리스와 함께 수업을 볼 예정입니다. 모바일 측면에서 Android는 여전히이 기능을 지원하지 않지만 5 개월 전에 출시 된 iOS 9는 부분적으로 지원됩니다.

다행히도 Harmony 코드를 ES5 코드로 재 컴파일하기위한 JS 라이브러리 인 Babel이 있습니다. ES6의 클래스 및 기타 여러 멋진 기능은 Javascript 코드를 훨씬 더 읽기 쉽고 유지 관리 할 수 ​​있도록 만들 수 있습니다.


10
이 답변은 더 많은 신용을받을 가치가 있으며 현재 정답입니다.
Klompenrunner

6

일단 고전적인 OO를 모방하는 것을 피하고 대신 원형 OO를 사용해야합니다. 프로토 타입 OO를위한 멋진 유틸리티 라이브러리는 특성입니다. 입니다.

대신 메서드를 덮어 쓰고 상속 체인을 설정 (항상 개체 상속보다 개체 구성을 선호해야 함)하려면 재사용 가능한 함수를 특성으로 묶고이를 사용하여 개체를 만들어야합니다.

라이브 예

var modifyA = {
    modify: function() {
        this.x = 300;
        this.y = 400;
    }
};

var modifyB = {
    modify: function() {
        this.x = 3000;
        this.y = 4000;
    }
};

C = function(trait) {
    var o = Object.create(Object.prototype, Trait(trait));

    o.modify();
    console.log("sum : " + (o.x + o.y));

    return o;
}

//C(modifyA);
C(modifyB);

10
당신은 질문에 대답하지 않습니다. 이것은 주석이어야합니다.
FK82 2011


3

예제에서 modify ()는 A, B 또는 C 정의 내에서 액세스 할 수없는 개인 함수입니다. 다음과 같이 선언해야합니다.

this.modify = function(){}

C는 C에 전달하지 않는 한 부모에 대한 참조가 없습니다. C가 A 또는 B에서 상속하도록 설정되어 있으면 해당 공용 메서드를 상속합니다 (modify ()가 정의 된 것과 같은 개인 함수가 아님). C가 부모로부터 메서드를 상속하면 상속 된 메서드를 재정의 할 수 있습니다.


수정은 로컬 함수입니다. 자바 스크립트에는 개인이 없습니다
Raynos 2011

로컬 / 프라이빗, 같은 것이 아닌 다른 용어입니까?
Alex Heyd

2

modify()마지막으로 호출 한 메서드 는 재정의 modify()하려면 먼저 A또는 을 상속해야하는 경우 전역 컨텍스트에서 호출됩니다 B.

아마도 당신은 이것을 시도하고있을 것입니다 :

이 경우 C상속A

function A() {
    this.modify = function() {
        alert("in A");
    }
}

function B() {
    this.modify = function() {
        alert("in B");
    }
}

C = function() {
    this.modify = function() {
        alert("in C");
    };

    C.prototype.modify(); // you can call this method where you need to call modify of the parent class
}

C.prototype = new A();

1
C.prototype.modify()잘못된 this값을 가질 것 입니다. 즉 C.prototype, c의 인스턴스 대신. 사용하십시오 .call(this)그러나 당신의 대답은 :) 단지 중복
Raynos

1

모든 변수를 "공개"로 지정하지 않는 한, 즉 Function직접 또는 prototype속성을 통해 해당 변수를 구성원으로 만듭니다 .

var C = function( ) {
    this.x = 10 , this.y = 20 ;
    this.modify = function( ) {
        this.x = 30 , this.y = 40 ;
        console.log("(!) C >> " + (this.x + this.y) ) ;
    } ;
} ;

var A = function( ) {
    this.modify = function( ) {
       this.x = 300 , this.y = 400 ;
       console.log("(!) A >> " + (this.x + this.y) ) ;
    } ;
} ;
    A.prototype = new C ;

var B = function( ) {
    this.modify = function( ) {
       this.x = 3000 , this.y = 4000 ;
       console.log("(!) B >> " + (this.x + this.y) ) ;
    } ;
} ;


new C( ).modify( ) ;
new A( ).modify( ) ;
new B( ).modify( ) ; 

몇 가지 변경 사항을 알 수 있습니다.

가장 중요한 것은 가정 된 "슈퍼 클래스"생성자에 대한 호출이 이제이 줄 내에서 암시 적이라는 것입니다.

<name>.prototype = new C ;

모두 AB지금 가지고있는 것 개별적으로 수정 구성원을 x하고 y있는 우리가 작성한 것인지의 경우되지 않을 것 ... = C대신.

그런 다음 x, y그리고 modify모든 "공공"회원 그래서 다른 할당하는 것을 Function그들에게를

 <name>.prototype.modify = function( ) { /* ... */ }

Function해당 이름으로 원본 을 "무시"합니다 .

마지막으로, "super-class"에 대한 암시 적 호출은 "super-class"를 가정 된 "sub-classes" 의 속성으로 설정할 때 다시 실행될 것이기 때문에 선언 modify에서 호출을 수행 할 수 없습니다 .Functionprototype

하지만 이것은 자바 스크립트에서 이런 종류의 일을하는 방법입니다.

HTH,

FK


아무 문제가 없습니다 <name>.prototype = new C;프로토 타입의 당신의 그림자 모든 구성원 어쨌든
Raynos

@Raynos : 네, 있습니다. 즉, Object를 인스턴스화하지 않으면 모든 상속 Objects이 동일한 멤버를 공유합니다 . 따라서, 변화 에하는 것은 바꿀 것 에 따라서 변경 에 . 분명히 바람직하지 않습니다. CCxAxCxB
FK82 2011

당신은 요점을 놓쳤습니다. 줄을 제거해도 코드는 계속 작동합니다
Raynos

@Raynos : 당신은 당신 자신의 요점을 놓치고 있습니다. ;-) 우리는 원하는 AB상속에서 C. 해당 줄이 누락 된 경우에는 해당되지 않습니다. 실제로이 경우 "그림자" A와 함께 B액세스 할 수 있는 유일한 프로토 타입은 Object.prototype.
FK82 2011

코드를보세요. A와 B는 프로토 타입에서 C 멤버를 사용하지 않습니다. 따라서 C에서 "상속"하는 것은 쓸모가 없습니다. A와 B 재정의하기 때문입니다 x, y그리고 modify및 따라서 모든 그림자 C의 회원. C를 사용하지 않는다면 프로토 타입에 C를 넣는 이유는 무엇입니까? 죽은 코드입니다.
Raynos 2011

0

function A() {
    var c = new C();
	c.modify = function(){
		c.x = 123;
		c.y = 333;
	}
	c.sum();
}

function B() {
    var c = new C();
	c.modify = function(){
		c.x = 999;
		c.y = 333;
	}
	c.sum();
}


C = function () {
   this.x = 10;
   this.y = 20;

   this.modify = function() {
      this.x = 30;
      this.y = 40;
   };
   
   this.sum = function(){
	this.modify();
	console.log("The sum is: " + (this.x+this.y));
   }
}

A();
B();

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