Kế thừa JavaScript [đã đóng]


80

Tôi đang cố gắng triển khai kế thừa trong javascript. Tôi đã nghĩ ra mã tối thiểu sau đây để hỗ trợ nó.

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;
}

Các chuyên gia, vui lòng cho tôi biết nếu điều này sẽ đủ hoặc bất kỳ vấn đề quan trọng nào khác mà tôi có thể đã bỏ qua. Dựa trên các vấn đề tương tự gặp phải, vui lòng đề xuất các thay đổi khác.

Đây là tập lệnh thử nghiệm hoàn chỉnh:

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);

Nếu bạn cần kế thừa, có rất nhiều thư viện đã cung cấp điều này. Ít nhất hãy đọc chúng để biết bạn viết sai ở đâu. Nhưng tại sao phải phát minh lại? Hai thư viện thừa kế javascript tuyệt vời mà tôi suy nghĩ là klassselfish.js (Tôi đã sử dụng cả hai, họ tuyệt vời đang.)
bejonbee

Tôi đã sử dụng Klass nhưng có một số vấn đề trong việc ghi đè các biến mảng. Tôi sẽ cố gắng ích kỷ. Nhưng phiên bản của tôi là mã 4 dòng đơn giản, nhưng phù hợp với tôi trong hầu hết các trường hợp. Tôi chỉ muốn biết liệu sau này tôi có gặp khó khăn với cách tiếp cận này hay không.
đóiMind

2
Bạn có thể muốn xem lại câu trả lời SO này cho một câu hỏi tương tự ; trong số tất cả các mẹo tuyệt vời mà tác giả chỉ ra cách loại bỏ lệnh gọi tới hàm tạo của cha khi định nghĩa lớp con.
bejonbee

@hungryMind: Nếu bạn lo lắng về các vấn đề cụ thể liên quan đến mã của mình, tại sao bạn không chỉnh sửa câu hỏi của mình và cho chúng tôi biết chính xác điều bạn sợ. Bởi vì bạn chỉ hỏi xem mã của bạn có ổn hay không, không có nhiều sự công bằng cho nó. Bạn có thể sẽ không nhận được câu trả lời mà bạn đang tìm kiếm. Vì vậy, tôi đề nghị bạn sửa Q của bạn
Robert Koritnik

Câu hỏi này là về cùng một chủ đề: stackoverflow.com/questions/711209/...
Anderson Xanh

Câu trả lời:


139

Để triển khai kế thừa javascript trong ECMAScript 5, bạn có thể xác định nguyên mẫu của một đối tượng và sử dụng Object.createđể kế thừa. Bạn cũng có thể thêm / ghi đè các thuộc tính tùy thích.

Thí dụ:

/**
 * 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 đúng rồi, cảm ơn.
Lorenzo Polidori,

Tại sao không chỉ Translation.prototype = new Transform()? Ngoài ra, vì câu trả lời hiện không hoạt động, bạn có chỉnh sửa nó không?
Jörn Zaefferer

@ JörnZaefferer Hãy xem ở đây: stackoverflow.com/q/4166616/885464 . Và bạn có ý gì với 'câu trả lời hiện không hoạt động'?
Lorenzo Polidori

4
Bạn cũng nên thiết lập các constructor của lớp con một cách rõ ràng: Translation.prototype.constructor = Translation. Hữu ích để nhân bản đối tượng (trong hầu hết các kỹ thuật).
barboaz

41

Tôi nghĩ rằng giải pháp Crockfords là quá phức tạp, cũng như của John. Việc nhận thừa kế javascript đơn giản hơn nhiều so với cả hai cách mô tả. Xem xét:

//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)

Tôi đã viết mô tả đầy đủ về giải pháp trên trên blog của mình .


1
Ngoại trừ việc nó chỉ hỗ trợ tất cả các thành viên cộng đồng
Rodrigo-Silveira

@ rodrigo-silveira, không rõ ý bạn. Nếu bạn muốn private, bạn chỉ cần khai báo chúng với var x = "anything", không?
Marcosc

2
Tôi nghĩ @ rodrigo-silveira có nghĩa là nó không hỗ trợ các thành viên được bảo vệ, và cả giải pháp cũng vậy. (Các thành viên riêng theo định nghĩa không thể truy cập từ lớp con nên điều đó sẽ không có ý nghĩa). Bạn phải sử dụng một cái gì đó như this._myProtectedVariable = 5;để tạo thành viên được bảo vệ.
Ciantic

10
giải pháp rất hay, chỉ có một nhược điểm (nhỏ), các hàm tạo được thực thi hai lần. Một khi D.call (this), và một lần nữa: new D (). Điều này thường không phải là vấn đề lớn, nhưng nếu bạn muốn tránh nó, bạn có thể sử dụng Object.create như sau: thay vì C.prototype = new D (); bạn có thể viết C.prototype = Object.create (D.prototype); ví dụ: jsfiddle.net/9Dxkb/1
Ray Hulha

1
Cuối cùng, một lời giải thích KHÔNG LIÊN QUAN có hiệu quả! Tôi đã đảo ngược logic của bạn để làm cho E kế thừa theo hướng ngược lại (E có nhiều nhất với nó) vì điều đó có ý nghĩa với tôi. Cảm ơn!
Ed Bayiates

12

Khi tôi chơi với các đối tượng JS, tôi đã tìm thấy một giải pháp tối giản hơn :-) Hãy tận hưởng!

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

Thí dụ

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

Đây là cách đơn giản nhất và tôi hy vọng cách dễ nhất để hiểu kế thừa trong JS. Ví dụ này hữu ích nhất sẽ dành cho các lập trình viên PHP.

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

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

Bây giờ con trai có một phương thức bị ghi đè và một phương thức mới

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

Bây giờ cháu trai có hai phương thức bị ghi đè và một phương thức mới

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


Chắc chắn có thể triển khai dưới dạng Object.create (Con trai mới)
Alexander Serkin

Điều đó sẽ thậm chí còn tồi tệ hơn.
Bergi

4

Tại sao không sử dụng các đối tượng thay vì các hàm:

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();
};

Và gọi nó như thế này:

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

Cách tiếp cận này gọn gàng hơn nhiều với các chức năng. Tôi đã tìm thấy blog này giải thích lý do tại sao kế thừa với các hàm không phải là cách thích hợp để thực hiện điều đó trong JS: http://davidwalsh.name/javascript-objects-deconstruction

BIÊN TẬP

var Child cũng có thể được viết là:

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

Đây là giải pháp của tôi, dựa trên phương pháp kế thừa nguyên mẫu tiêu chuẩn được mô tả trong câu trả lời của Lorenzo Polidori .

Đầu tiên, tôi bắt đầu bằng cách xác định các phương thức trợ giúp này, giúp mọi thứ dễ hiểu hơn và dễ đọc hơn sau này:

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);
};

Bây giờ, bạn không chỉ có thể thiết lập lớp cha của một lớp SubClass.setSuperclass(ParentClass)mà còn có thể gọi các phương thức được ghi đè với 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

Phải thừa nhận rằng ngay cả với các hàm helper thì cú pháp ở đây cũng khá khó xử. Mặc dù vậy, rất may, trong ECMAScript 6, một số đường cú pháp ( các lớp tối thiểu tối đa ) đã được thêm vào để làm cho mọi thứ đẹp hơn nhiều. Ví dụ:

/**
 * 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

Lưu ý rằng ECMAScript 6 vẫn đang trong giai đoạn dự thảo tại thời điểm này và theo tôi biết thì nó chưa được triển khai trong bất kỳ trình duyệt web lớn nào. Tuy nhiên, nếu bạn muốn, bạn có thể sử dụng một cái gì đó như trình biên dịch Traceur để biên dịch ECMAScript 6xuống ECMAScript 5JavaScript thuần túy dựa trên cũ . Bạn có thể xem ví dụ trên được biên dịch bằng Traceur tại đây .


2

Mặc dù tôi đồng ý với tất cả các câu trả lời trên, tôi cảm thấy rằng JavaScript không cần phải Hướng đối tượng, (Tránh kế thừa), thay vào đó, một cách tiếp cận dựa trên đối tượng sẽ là đủ trong hầu hết các trường hợp.

Tôi thích cách Eloquent JavaScript bắt đầu Chương 8 về Lập trình hướng đối tượng nói về OO. Thay vì giải mã cách tốt nhất để thực hiện Kế thừa, nên dành nhiều năng lượng hơn để tìm hiểu các khía cạnh chức năng của JavaScript, do đó, tôi thấy Chương 6 về Lập trình chức năng, thú vị hơn.


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

Làm thế nào về cách tiếp cận đơn giản này

    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

Kế thừa nguyên mẫu cơ bản

Một cách đơn giản nhưng hiệu quả để thực hiện kế thừa trong JavaScript, là sử dụng hai lớp lót sau:

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

Điều đó tương tự như làm điều này:

B.prototype = new A();

Sự khác biệt chính giữa cả hai là hàm tạo của Akhông được chạy khi sử dụng Object.create, trực quan hơn và giống với kế thừa dựa trên lớp.

Bạn luôn có thể tùy chọn chạy hàm tạo của Akhi tạo một phiên bản mới của Bbằng cách thêm nó vào hàm tạo của B:

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

Nếu bạn muốn chuyển tất cả các đối số của Btới A, bạn cũng có thể sử dụng Function.prototype.apply():

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

Nếu bạn muốn trộn một đối tượng khác vào chuỗi hàm tạo của B, bạn có thể kết hợp Object.createvới Object.assign:

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

Bản giới thiệu

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());


Tạo trình bao bọc của riêng bạn

Nếu bạn không thích viết gần như giống nhau hai dòng trong suốt mã của mình, bạn có thể viết một hàm wrapper cơ bản như sau:

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;
  }
}

Cách thức hoạt động của trình bao bọc này:

  1. Nếu bạn truyền một tham số, thì nguyên mẫu của nó sẽ kế thừa từ đó Object.
  2. Nếu bạn truyền hai tham số, nguyên mẫu của thứ nhất sẽ kế thừa từ tham số thứ hai.
  3. Nếu bạn chuyển nhiều hơn hai tham số, nguyên mẫu của tham số đầu tiên sẽ kế thừa từ tham số thứ hai và nguyên mẫu của các tham số khác sẽ được trộn vào.

Bản giới thiệu

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());


Ghi chú

Object.createcó thể được sử dụng an toàn trong mọi trình duyệt hiện đại, kể cả IE9 +. Object.assignkhông hoạt động trong bất kỳ phiên bản IE nào cũng như một số trình duyệt di động. Bạn nên polyfill Object.create và / hoặc Object.assignnếu bạn muốn sử dụng chúng và hỗ trợ các trình duyệt không triển khai chúng.

Bạn có thể tìm thấy một polyfill Object.create ở đây và một polyfill Object.assign đây .


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

Cách dễ nhất để sử dụng thư viện AWeb . Mẫu chính thức:

   /**
     * 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

Tôi đã tìm thấy một giải pháp dễ dàng hơn nhiều so với việc mở rộng và tạo mẫu. Trên thực tế, tôi không biết điều này hiệu quả như thế nào mặc dù nó trông sạch sẽ và hoạt động.

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 ();

kết quả:

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

ví dụ thực tế:

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});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.