자바 스크립트 상속 [닫힘]


80

나는 자바 스크립트에서 상속을 구현하려고합니다. 나는 그것을 지원하기 위해 다음과 같은 최소한의 코드를 생각해 냈습니다.

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

전문가 여러분, 이것이 충분한 지 또는 내가 놓친 다른 중요한 문제가 있는지 알려주십시오. 직면 한 유사한 문제를 바탕으로 다른 변경 사항을 제안하십시오.

다음은 완전한 테스트 스크립트입니다.

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
    this.superalert = function(){
        alert('tst');
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

function Child(){
    Base.extend(this, Base);
    this.width = 20;
    this.height = 15;
    this.a = ['s',''];
    this.alert = function(){
        alert(this.a.length);
        alert(this.height);
    }
}

function Child1(){
    Base.extend(this, Child);
    this.depth = 'depth';
    this.height = 'h';
    this.alert = function(){
        alert(this.height); // display current object height
        alert(this.a.length); // display parents array length
        this.call(this.base.alert); 
          // explicit call to parent alert with current objects value
        this.call(this.base.superalert); 
          // explicit call to grandparent, parent does not have method 
        this.base.alert(); // call parent without overriding values
    }
}

var v = new Child1();
v.alert();
alert(v.height);
alert(v.depth);

상속이 필요한 경우 이미이를 제공하는 많은 라이브러리가 있습니다. 적어도 코드를 읽고 코드가 잘못된 곳을 찾으십시오. 하지만 왜 재발 명할까요? 마음에 와서 두 멋진 자바 스크립트 상속 라이브러리는 KLASSselfish.js가 (. 내가 모두가있는 거 놀라운 사용했습니다)
bejonbee

Klass를 사용했지만 배열 변수를 재정의하는 데 몇 가지 문제가 있습니다. 나는 이기적인 시도를 할 것입니다. 그러나 내 버전은 간단한 4 줄 코드이지만 대부분의 시나리오에서 나를 위해 작동합니다. 나중에이 접근 방식에 갇히게 될지 알고 싶습니다.
hungryMind 2011 년

2
비슷한 질문 에 대한 이 SO 답변 을 검토 할 수 있습니다 . 모든 훌륭한 팁 중에서 저자는 자식 클래스를 정의 할 때 부모의 생성자에 대한 호출을 제거하는 방법을 보여줍니다.
bejonbee 2011 년

@hungryMind : 코드와 관련된 특정 문제에 대해 걱정이되는 경우 질문을 편집하고 무엇을 두려워하는지 정확히 알려주십시오. 코드가 괜찮은지 묻기 때문에 그다지 정의를 내리지 마십시오. 원하는 답을 얻지 못할 수도 있습니다. 따라서 Q를 편집하는 것이 좋습니다.
Robert Koritnik 2011 년

이 질문은 동일한 주제에 관한 것입니다 : stackoverflow.com/questions/711209/...
앤더슨 녹색

답변:


139

ECMAScript 5 에서 자바 스크립트 상속을 구현 하기 Object.create위해 객체의 프로토 타입을 정의하고 상속에 사용할 수 있습니다. 원하는만큼 속성을 추가 / 재정의 할 수도 있습니다.

예:

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.x = x;
    this.y = y;
}

// Inheritance
Translation.prototype = Object.create(Transform.prototype);

// Override
Translation.prototype.toString = function() {
    return Transform.prototype.toString() + this.type + " Translation " + this.x + ":" + this.y;
}

/**
 * Rotation class.
 */
function Rotation(angle) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.angle = angle;
}

// Inheritance
Rotation.prototype = Object.create(Transform.prototype);

// Override
Rotation.prototype.toString = function() {
    return Transform.prototype.toString() + this.type + " Rotation " + this.angle;
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

2
Translation.prototype = Object.create (new Transform ()); ? Translation.prototype = Object.create (Transform.prototype);
4esn0k

@ 4esn0k 맞습니다, 감사합니다.
Lorenzo Polidori 2012 년

왜 안돼 Translation.prototype = new Transform()? 또한 답변이 현재 작동하지 않으므로 편집 하시겠습니까?
Jörn Zaefferer 2013

@ JörnZaefferer 여기를보세요 : stackoverflow.com/q/4166616/885464 . 그리고 '현재 답변이 작동하지 않는다'는 의미는 무엇입니까?
Lorenzo Polidori 2013

4
또한 하위 클래스의 생성자를 명시 적으로 설정해야합니다 Translation.prototype.constructor = Translation.. 개체 복제에 유용합니다 (대부분의 기술에서).
barboaz 2014-06-09

41

나는 Crockfords 솔루션이 John과 마찬가지로 너무 복잡하다고 생각합니다. 둘 다 설명하는 것보다 자바 스크립트 상속을 얻는 것이 훨씬 간단합니다. 중히 여기다:

//Classes
function A() {
    B.call(this);
}

function B() {
    C.call(this);
    this.bbb = function() {
        console.log("i was inherited from b!");
    }
}

function C() {
    D.call(this);
}

function D() {
    E.call(this);
}

function E() {
    //instance property 
    this.id = Math.random()
}

//set up the inheritance chain (order matters) 
D.prototype = new E();
C.prototype = new D();
B.prototype = new C();
A.prototype = new B();

//Add custom functions to each
A.prototype.foo = function() {
    console.log("a");
};
B.prototype.bar = function() {
    console.log("b");
};
C.prototype.baz = function() {
    console.log("c");
};
D.prototype.wee = function() {
    console.log("d");
};
E.prototype.woo = function() {
    console.log("e");
};

//Some tests
a = new A();
a.foo();
a.bar();
a.baz();
a.wee();
a.woo();
console.log(a.id);
a.bbb();
console.log(a instanceof A);
console.log(a instanceof B);
console.log(a instanceof C);
console.log(a instanceof D);
console.log(a instanceof E);​
var b = new B();
console.log(b.id)

위의 솔루션에 대한 완전한 설명을 블로그에 작성했습니다 .


1
그것은 단지 모든 public 멤버를 지원한다는 점을 제외하고
로드리고 - 실 베이라

@ rodrigo-silveira, 무슨 뜻인지 잘 모르겠습니다. privates를 원하면 var x = "whatever"로 선언하면됩니다.
Marcosc 2011

2
@ rodrigo-silveira는 보호 된 구성원을 지원하지 않으며 솔루션도 지원하지 않는다는 의미라고 생각합니다. (정의에 따라 개인 멤버는 하위 클래스에서 액세스 할 수 없으므로 의미가 없습니다). this._myProtectedVariable = 5;보호 된 구성원을 만들려면 같은 것을 사용해야합니다 .
Ciantic

10
아주 좋은 솔루션, (약간) 단점, 생성자가 두 번 실행됩니다. 일단 D.call (this), 그리고 다시 : new D (). 이것은 일반적으로 큰 문제는 아니지만 피하고 싶다면 Object.create를 다음과 같이 사용할 수 있습니다. C.prototype = new D (); C.prototype = Object.create (D.prototype); 작성할 수 있습니다. 예 : jsfiddle.net/9Dxkb/1
Ray Hulha 2013 년

1
마지막으로 작동하는 이해하기 어려운 설명입니다! 나는 당신의 논리를 뒤집어 E가 역방향으로 상속하도록 만들었습니다. 감사!
Ed Bayiates 2013

12

JS 객체를 가지고 놀면서 더 최소한의 해결책을 찾았습니다. :-) 즐기세요!

function extend(b,a,t,p) { b.prototype = a; a.apply(t,p); }

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

function B(p1,p2) {
    extend(B,A,this);
    this.info2 = function() {
        alert("B"+p1+p2);
    }
}

function C(p) {
    extend(C,B,this,["1","2"]);
    this.info3 = function() {
        alert("C"+p);
    }
}


var c = new C("c");
c.info1(); // A
c.info2(); // B12
c.info3(); // Cc

8

여기에 가장 간단하고 JS에서 상속을 이해하는 가장 쉬운 방법이 있기를 바랍니다. 이 예제는 PHP 프로그래머에게 가장 도움이 될 것입니다.

function Mother(){
    this.canSwim = function(){
        console.log('yes');
    }
}

function Son(){};
Son.prototype = new Mother;
Son.prototype.canRun = function(){
    console.log('yes');
}

이제 아들은 하나의 재정의 된 방법과 하나의 새로운

function Grandson(){}
Grandson.prototype = new Son;
Grandson.prototype.canPlayPiano = function(){
    console.log('yes');
};
Grandson.prototype.canSwim = function(){
    console.log('no');
}

이제 손자는 두 개의 재정의 된 메서드와 하나의 새로운

var g = new Grandson;
g.canRun(); // => yes
g.canPlayPiano(); // => yes
g.canSwim(); // => no


물론 Object.create (new Son)로 구현할 수 있습니다
Alexander Serkin 2013

그것은 더 나쁠 것입니다.
Bergi

4

함수 대신 객체를 사용하지 않는 이유 :

var Base = {
    superalert : function() {
        alert('tst');
    }
};

var Child = Object.create(Base);
Child.width = 20;
Child.height = 15;
Child.a = ['s',''];
Child.childAlert = function () {
        alert(this.a.length);
        alert(this.height);
    }

var Child1 = Object.create(Child);
Child1.depth = 'depth';
Child1.height = 'h';
Child1.alert = function () {
    alert(this.height);
    alert(this.a.length);
    this.childAlert();
    this.superalert();
};

그리고 다음과 같이 부릅니다.

var child1 = Object.create(Child1);
child1.alert();

이 접근 방식은 함수보다 훨씬 더 깔끔합니다. 함수를 사용한 상속이 JS에서 적절한 방법이 아닌 이유를 설명하는이 블로그를 찾았습니다. http://davidwalsh.name/javascript-objects-deconstruction

편집하다

var Child는 다음과 같이 작성할 수도 있습니다.

var Child = Object.create(Base, {
    width : {value : 20},
    height  : {value : 15, writable: true},
    a : {value : ['s', ''], writable: true},
    childAlert : {value : function () {
        alert(this.a.length);
        alert(this.height);
    }}
});

4

Lorenzo Polidori의 답변에 설명 된 표준 프로토 타입 상속 방법을 기반으로하는 내 솔루션은 다음과 같습니다 .

먼저 다음과 같은 도우미 메서드를 정의하여 시작합니다.이를 통해 나중에 이해하기 쉽고 더 읽기 쉽습니다.

Function.prototype.setSuperclass = function(target) {
    // Set a custom field for keeping track of the object's 'superclass'.
    this._superclass = target;

    // Set the internal [[Prototype]] of instances of this object to a new object
    // which inherits from the superclass's prototype.
    this.prototype = Object.create(this._superclass.prototype);

    // Correct the constructor attribute of this class's prototype
    this.prototype.constructor = this;
};

Function.prototype.getSuperclass = function(target) {
    // Easy way of finding out what a class inherits from
    return this._superclass;
};

Function.prototype.callSuper = function(target, methodName, args) {
    // If methodName is ommitted, call the constructor.
    if (arguments.length < 3) {
        return this.callSuperConstructor(arguments[0], arguments[1]);
    }

    // `args` is an empty array by default.
    if (args === undefined || args === null) args = [];

    var superclass = this.getSuperclass();
    if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");

    var method = superclass.prototype[methodName];
    if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'");

    return method.apply(target, args);
};

Function.prototype.callSuperConstructor = function(target, args) {
    if (args === undefined || args === null) args = [];

    var superclass = this.getSuperclass();
    if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");

    return superclass.apply(target, args);
};

이제를 사용하여 클래스의 수퍼 클래스를 설정할 SubClass.setSuperclass(ParentClass)수있을뿐만 아니라 다음을 사용하여 재정의 된 메서드를 호출 할 수도 있습니다 SubClass.callSuper(this, 'functionName', [argument1, argument2...]).

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Translation.callSuper(this, arguments);

    // Public properties
    this.x = x;
    this.y = y;
}
// Inheritance
Translation.setSuperclass(Transform);

// Override
Translation.prototype.toString = function() {
    return Translation.callSuper(this, 'toString', arguments) + this.type + " Translation " + this.x + ":" + this.y;
}

/**
 * Rotation class.
 */
function Rotation(angle) {
    // Parent constructor
    Rotation.callSuper(this, arguments);

    // Public properties
    this.angle = angle;
}
// Inheritance
Rotation.setSuperclass(Transform);

// Override
Rotation.prototype.toString = function() {
    return Rotation.callSuper(this, 'toString', arguments) + this.type + " Rotation " + this.angle;
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

물론 헬퍼 함수를 ​​사용하더라도 여기의 구문은 꽤 어색합니다. 고맙게도 ECMAScript 6에서는 훨씬 더 예쁘게 만들기 위해 몇 가지 구문 설탕 ( 최대 최소 클래스 )이 추가되었습니다. 예 :

/**
 * Transform base class
 */
class Transform {
  constructor() {
    this.type = "2d";
  }

  toString() {
    return "Transform";
  } 
}

/**
 * Translation class.
 */
class Translation extends Transform {
  constructor(x, y) {
    super(); // Parent constructor

    // Public properties
    this.x = x;
    this.y = y;
  }

  toString() {
    return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y;
  }
}

/**
 * Rotation class.
 */
class Rotation extends Transform {
  constructor(angle) {
    // Parent constructor
    super(...arguments);

    // Public properties
    this.angle = angle;
  }

  toString() {
    return super(...arguments) + this.type + " Rotation " + this.angle;
  }
}

// Tests
translation = new Translation(10, 15);

console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false

console.log(translation.toString()) // Transform2d Translation 10:15

ECMAScript 6은이 시점에서 아직 초안 단계에 있으며 내가 아는 한 주요 웹 브라우저에서는 구현되지 않습니다. 그러나 원한다면 Traceur 컴파일러 와 같은 것을 사용 ECMAScript 6하여 평범한 오래된 ECMAScript 5기반 JavaScript 로 컴파일 할 수 있습니다 . 여기에서 Traceur를 사용하여 컴파일 된 위의 예제를 볼 수 있습니다 .


2

위의 모든 답변에 동의하지만 JavaScript가 객체 지향적 일 필요는없고 (상속 방지) 대부분의 경우 객체 기반 접근 방식 으로 충분해야한다고 생각합니다.

저는 Eloquent JavaScript 가 OO에 대해 이야기하는 객체 지향 프로그래밍에 관한 8 장을 시작 하는 방식을 좋아합니다 . 상속을 구현하는 가장 좋은 방법을 해독하는 대신 JavaScript의 기능적 측면을 배우는 데 더 많은 에너지를 투자해야하므로 함수형 프로그래밍에 대한 6 장을 더 흥미롭게 발견했습니다.


2
//This is an example of how to override a method, while preserving access to the original.
//The pattern used is actually quite simple using JavaScripts ability to define closures:

    this.somefunction = this.someFunction.override(function(args){
        var result = this.inherited(args);
        result += this.doSomethingElse();
        return result;
    });

//It is accomplished through this piece of code (courtesy of Poul Krogh):

/***************************************************************
    function.override overrides a defined method with a new one, 
    while preserving the old method.
    The old method is only accessible from the new one.
    Use this.inherited() to access the old method.
***************************************************************/

    Function.prototype.override = function(func)
    {
        var remember = this;
        var f = function() 
        {
             var save = this.inherited; 
             this.inherited = remember;
             var result = func.apply(this, Array.prototype.slice.call(arguments));
             this.inherited = save;
             return result;
        };
        return f;
    }

1

이 간단한 접근 방식은 어떻습니까

    function Body(){
        this.Eyes = 2;
        this.Arms = 2;
        this.Legs = 2;
        this.Heart = 1;
        this.Walk = function(){alert(this.FirstName + ' Is Walking')};
    }

    function BasePerson() {
        var BaseBody = new Body(this);
        BaseBody.FirstName = '';
        BaseBody.LastName = '';
        BaseBody.Email = '';
        BaseBody.IntroduceSelf = function () { alert('Hello my name is ' + this.FirstName + ' ' + this.LastName); };
        return BaseBody;
    }

    function Person(FirstName,LastName)
    {
        var PersonBuild = new BasePerson();
        PersonBuild.FirstName = FirstName;
        PersonBuild.LastName = LastName;
        return PersonBuild;
    }

    var Person1 = new Person('Code', 'Master');
    Person1.IntroduceSelf();
    Person1.Walk();

1

기본 프로토 타입 상속

JavaScript에서 상속을 수행하는 간단하지만 효과적인 방법은 다음 두 줄을 사용하는 것입니다.

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

이것은 이것을하는 것과 유사합니다 :

B.prototype = new A();

둘 다의 주요 차이점은의 생성자 A가를 사용할 때 실행되지 않는다는 것입니다 Object.create. 이는 더 직관적이고 클래스 기반 상속과 더 유사합니다.

의 생성자 에 추가하여 A새 인스턴스를 만들 때 의 생성자를 선택적으로 실행하도록 선택할 수 있습니다 .BB

function B(arg1, arg2) {
    A(arg1, arg2); // This is optional
}

당신의 모든 인수 전달하려는 경우 B에를 A, 당신은 또한 사용할 수 있습니다 Function.prototype.apply():

function B() {
    A.apply(this, arguments); // This is optional
}

다른 객체를의 생성자 체인에 혼합 B하려면 다음 Object.create과 결합 할 수 있습니다 Object.assign.

B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;

데모

function A(name) {
  this.name = name;
}

A.prototype = Object.create(Object.prototype);
A.prototype.constructor = A;

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

function mixin() {

}

mixin.prototype = Object.create(Object.prototype);
mixin.prototype.constructor = mixin;

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

C.prototype = Object.assign(Object.create(B.prototype), mixin.prototype);
C.prototype.constructor = C;

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());


나만의 래퍼 만들기

코드 전체에서 대략 동일한 2 줄짜리를 작성하는 것을 좋아하지 않는다면 다음과 같은 기본 래퍼 함수를 ​​작성할 수 있습니다.

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

이 래퍼의 작동 원리 :

  1. 하나의 매개 변수를 전달하면 프로토 타입이 Object.
  2. 두 개의 매개 변수를 전달하면 첫 번째 프로토 타입이 두 번째 매개 변수에서 상속됩니다.
  3. 두 개 이상의 매개 변수를 전달하면 첫 번째 프로토 타입이 두 번째 매개 변수에서 상속되고 다른 매개 변수의 프로토 타입이 혼합됩니다.

데모

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

function A(name) {
  this.name = name;
}

inheritance(A);

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

inheritance(B, A);

function mixin() {

}

inheritance(mixin);

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

inheritance(C, B, mixin);

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());


노트

Object.createIE9 +를 포함한 모든 최신 브라우저에서 안전하게 사용할 수 있습니다. Object.assignIE의 모든 버전이나 일부 모바일 브라우저에서는 작동하지 않습니다. 그것은에게 추천 polyfill Object.create 및 / 또는Object.assign 이를 사용하고이를 구현하지 않는 브라우저를 지원하려는 경우 .

당신의 polyfill을 찾을 수 있습니다 Object.create 여기 와 하나 Object.assign 여기 .


0
//
//  try this one:
//  
//    function ParentConstructor() {}
//    function ChildConstructor()  {}
//
//    var 
//        SubClass = ChildConstructor.xtendz( ParentConstructor );
//
Function.prototype.xtendz = function ( SuperCtorFn ) {

    return ( function( Super, _slice ) {

                // 'freeze' host fn 
                var
                    baseFn = this, 
                    SubClassCtorFn;

                // define child ctor
                SubClassCtorFn = function ( /* child_ctor_parameters..., parent_ctor_parameters[] */ ) {

                    // execute parent ctor fn on host object
                    // pass it last ( array ) argument as parameters
                    Super.apply( this, _slice.call( arguments, -1 )[0] );

                    // execute child ctor fn on host object
                    // pass remaining arguments as parameters
                    baseFn.apply( this, _slice.call( arguments, 0, -1 ) );

                };

                // establish proper prototype inheritance
                // 'inherit' methods
                SubClassCtorFn.prototype = new Super;

                // (re)establish child ctor ( instead of Super ctor )
                SubClassCtorFn.prototype.constructor = SubClassCtorFn;

                // return built ctor
                return SubClassCtorFn;

    } ).call( this, SuperCtorFn, Array.prototype.slice );
};

// declare parent ctor
function Sup( x1, x2 ) {
    this.parent_property_1 = x1;
    this.parent_property_2 = x2;
}

// define some methods on parent
Sup.prototype.hello = function(){ 
   alert(' ~  h e l l o   t h e r e  ~ ');
};


// declare child ctor
function Sub( x1, x2 ) {
    this.child_property_1 = x1;
    this.child_property_2 = x2;
}

var
    SubClass = Sub.xtendz(Sup), // get 'child class' ctor
    obj;

// reserve last array argument for parent ctor
obj = new SubClass( 97, 98, [99, 100] ); 

obj.hello();

console.log( obj );
console.log('obj instanceof SubClass      -> ', obj instanceof SubClass      );
console.log('obj.constructor === SubClass -> ', obj.constructor === SubClass );
console.log('obj instanceof Sup           -> ', obj instanceof Sup           );
console.log('obj instanceof Object        -> ', obj instanceof Object        );

//
//  Object {parent_property_1: 99, parent_property_2: 100, child_property_1: 97, child_property_2: 98}
//  obj instanceof SubClass      -> true
//  obj.constructor === SubClass -> true
//  obj instanceof Sup           -> true
//  obj instanceof Object        -> true
//

-1

AWeb 라이브러리 를 사용하는 가장 쉬운 방법 . 공식 샘플 :

   /**
     * A-class
     */
   var ClassA = AWeb.class({
     public : {
        /**
          * A-class constructor
          */
        constructor : function() {
           /* Private variable */
           this.variable1 = "A";
           this.calls = 0;
        },

        /**
          * Function returns information about the object
          */
        getInfo : function() {
           this.incCalls();

           return "name=" + this.variable1 + ", calls=" + this.calls;
        }
     },
     private : {
        /**
          * Private function
          */
        incCalls : function() {
           this.calls++;
        }
     }
  });
  /**
    * B-class
    */
  var ClassB = AWeb.class({
     extends : ClassA,
     public : {
        /**
          * B-class constructor
          */
        constructor : function() {
           this.super();

           /* Private variable */
           this.variable1 = "B";
        },

        /**
          * Function returns extended information about the object
          */
        getLongInfo : function() {
           return this.incCalls !== undefined ? "incCalls exists" : "incCalls undefined";
        }
     }
  });
  /**
    * Main project function
    */
  function main() {
     var a = new ClassA(),
         b = new ClassB();

     alert(
        "a.getInfo " + (a.getInfo ? "exists" : "undefined") + "\n" +
        "a.getLongInfo " + (a.getLongInfo ? "exists" : "undefined") + "\n" +

        "b.getInfo " + (b.getInfo ? "exists" : "undefined") + "\n" +
        "b.getLongInfo " + (b.getLongInfo ? "exists" : "undefined") + "\n" +

        "b.getInfo()=" + b.getInfo() + "\n" +
        "b.getLongInfo()=" + b.getLongInfo()
     );
  }

-1

확장하고 프로토 타이핑하는 것보다 훨씬 쉬운 솔루션을 찾았습니다. 실제로 깨끗하고 기능적으로 보이지만 이것이 얼마나 효율적인지 모르겠습니다.

var A = function (p) {
    if (p == null) p = this;
    p.a1 = 0;
    this.a2 = 0;
    var a3 = 0;
};

var B = function (p) {
    if (p == null) p = this;
    p.b1 = new A(this);
    this.b2 = new A(this);
    var b3 = new A(this);
    this b4 = new A();
};

var a = new A ();
var b = new B ();

결과:

a
    a1        0
    a2        0
b
    a1        0
    b1
        a2    0
    b2
        a2    0
    b4
        a1    0
        a2    0

실제 예 :

var Point = function (p) {
    if (p == null) p = this;
    var x = 0;
    var y = 0;
    p.getPoint = function () { return [x,y]; };
    p.setPoint = function (_x,_y) { x = _x; y = _y; };
};

var Dimension = function (p) {
    if (p == null) p = this;
    var w = 0;
    var h = 0;
    p.getDimension = function() { return [w,h] };
    p.setDimension = function(_w,_h) { w = _w; h = _h };
};

var Rect = function (p) {
    if (p == null) p = this;
    var dimension = new Dimension(this);
    var location  = new Point(this);
};

var rect = new Rect ();
rect.setDimension({w:30,h:40});
rect.setPoint({x:50,y:50});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.