Trình xây dựng trong các đối tượng JavaScript


Câu trả lời:


408

Sử dụng nguyên mẫu:

function Box(color) // Constructor
{
    this.color = color;
}

Box.prototype.getColor = function()
{
    return this.color;
};

Ẩn "màu" (hơi giống với biến thành viên riêng):

function Box(col)
{
   var color = col;

   this.getColor = function()
   {
       return color;
   };
}

Sử dụng:

var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue

var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green

3
@BorisB, vâng, bạn làm thế - điều này xác định màu sắc và getColor trên đối tượng Box, nếu không, bạn đang gán các biến trong phạm vi thông thường.
Nick

4
@Jeach đúng vậy. Tôi đã cung cấp một đoạn thay thế ẩn color. Tôi muốn đề xuất những gì bạn sử dụng phần lớn tùy thuộc vào sở thích cá nhân (bảo vệ so với đơn giản)
Nick

6
@CamiloMartin Mặc dù không phải lúc nào cũng cần thiết, tạo một biến "riêng tư" (hoặc trong trường hợp này, không thể đặt tên) có thể là một cách hữu ích để ngăn chặn mã bên ngoài trở nên phụ thuộc vào chi tiết triển khai của lớp. Thậm chí chỉ dấu hiệu cho thấy các thành phần nào của lớp là công khai / riêng tư có thể hữu ích cho người dùng bên ngoài.
Nick

49
varlàm một biến riêng. thistạo một biến công khai
EhevuTov

3
@AlanKis (Ít nhất là trong một số công cụ Javascript), dấu vết ngăn xếp sẽ trong trường hợp hàm ẩn danh thậm chí không được đề cập Foo, trong trường hợp sau nó sẽ biết rằng nó Foođược gọi. Rất hữu ích để gỡ lỗi.
Joachim Isaksson

248

Đây là một mẫu mà đôi khi tôi sử dụng cho hành vi tương tự OOP trong JavaScript. Như bạn có thể thấy, bạn có thể mô phỏng các thành viên riêng tư (cả tĩnh và cá thể) bằng cách sử dụng các bao đóng. Những gì new MyClass()sẽ trả về là một đối tượng chỉ có các thuộc tính được gán cho thisđối tượng và trong prototypeđối tượng của "lớp".

var MyClass = (function () {
    // private static
    var nextId = 1;

    // constructor
    var cls = function () {
        // private
        var id = nextId++;
        var name = 'Unknown';

        // public (this instance only)
        this.get_id = function () { return id; };

        this.get_name = function () { return name; };
        this.set_name = function (value) {
            if (typeof value != 'string')
                throw 'Name must be a string';
            if (value.length < 2 || value.length > 20)
                throw 'Name must be 2-20 characters long.';
            name = value;
        };
    };

    // public static
    cls.get_nextId = function () {
        return nextId;
    };

    // public (shared across instances)
    cls.prototype = {
        announce: function () {
            alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
                  'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
        }
    };

    return cls;
})();

Tôi đã được hỏi về thừa kế bằng cách sử dụng mẫu này, vì vậy ở đây đi:

// It's a good idea to have a utility class to wire up inheritance.
function inherit(cls, superCls) {
    // We use an intermediary empty constructor to create an
    // inheritance chain, because using the super class' constructor
    // might have side effects.
    var construct = function () {};
    construct.prototype = superCls.prototype;
    cls.prototype = new construct;
    cls.prototype.constructor = cls;
    cls.super = superCls;
}

var MyChildClass = (function () {
    // constructor
    var cls = function (surName) {
        // Call super constructor on this instance (any arguments
        // to the constructor would go after "this" in call(…)).
        this.constructor.super.call(this);

        // Shadowing instance properties is a little bit less
        // intuitive, but can be done:
        var getName = this.get_name;

        // public (this instance only)
        this.get_name = function () {
            return getName.call(this) + ' ' + surName;
        };
    };
    inherit(cls, MyClass); // <-- important!

    return cls;
})();

Và một ví dụ để sử dụng tất cả:

var bob = new MyClass();
bob.set_name('Bob');
bob.announce(); // id is 1, name shows as "Bob"

var john = new MyChildClass('Doe');
john.set_name('John');
john.announce(); // id is 2, name shows as "John Doe"

alert(john instanceof MyClass); // true

Như bạn có thể thấy, các lớp tương tác chính xác với nhau (chúng chia sẻ id tĩnh từ MyClass, announcephương thức sử dụng get_namephương thức đúng , v.v.)

Một điều cần lưu ý là sự cần thiết phải làm mờ các thuộc tính. Bạn thực sự có thể làm cho inherithàm đi qua tất cả các thuộc tính thể hiện (sử dụng hasOwnProperty) là các hàm và tự động thêm một thuộc super_<method name>tính. Điều này sẽ cho phép bạn gọi this.super_get_name()thay vì lưu trữ nó trong một giá trị tạm thời và gọi nó bị ràng buộc bằng cách sử dụng call.

Đối với các phương thức trên nguyên mẫu, bạn không cần phải lo lắng về vấn đề trên, nếu bạn muốn truy cập các phương thức nguyên mẫu của siêu lớp, bạn chỉ cần gọi this.constructor.super.prototype.methodName. Nếu bạn muốn làm cho nó ít dài dòng hơn, tất nhiên bạn có thể thêm các thuộc tính tiện lợi. :)


7
Chỉ cần một lưu ý về cls.prototypephần: "chia sẻ giữa các trường hợp" chỉ để đọc giá trị (gọi announce). Nếu bạn đặt myClassInstance.announcethành một giá trị khác, nó sẽ tạo một thuộc tính mới myClassInstance, vì vậy nó chỉ áp dụng cho đối tượng đó, không phải các thể hiện khác của lớp. Việc chỉ định MyClass.prototype.announcesẽ ảnh hưởng đến tất cả các trường hợp mặc dù.
Matthew Crumley

1
Không có vấn đề, vui mừng khi được giúp đỡ! :)
Blixt

2
Cảm ơn bạn! Rất thích! Bạn có thể chỉ ra ví dụ về kế thừa lớp trong phương pháp này.
Dmitrij Golubev

2
@DmitrijGolubev, Brad Dwyer và Nathan C. Tresch: Tôi đã thêm quyền thừa kế, nhưng nó trở nên khá phức tạp nên tôi thường khuyên bạn nên đi với một giải pháp đơn giản hơn, trừ khi bạn cần sự kế thừa khó khăn như vậy trong JavaScript (thực sự chỉ là một ngôn ngữ nguyên mẫu).
Blixt

1
@guiomie Đó là một phương thức "công khai tĩnh" vì vậy bạn sẽ gọi nó trên hàm xây dựng ("lớp"), chứ không phải ví dụ:MyClass.get_nextId()
Blixt

166

Dường như với tôi, hầu hết các bạn đang đưa ra ví dụ về getters và setters không phải là một constructor, tức là http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) .

lunched-dan đã gần hơn nhưng ví dụ không hoạt động trong jsFiddle.

Ví dụ này tạo ra một hàm xây dựng riêng chỉ chạy trong khi tạo đối tượng.

var color = 'black';

function Box()
{
   // private property
   var color = '';

   // private constructor 
   var __construct = function() {
       alert("Object Created.");
       color = 'green';
   }()

   // getter
   this.getColor = function() {
       return color;
   }

   // setter
   this.setColor = function(data) {
       color = data;
   }

}

var b = new Box();

alert(b.getColor()); // should be green

b.setColor('orange');

alert(b.getColor()); // should be orange

alert(color); // should be black

Nếu bạn muốn gán các thuộc tính công cộng thì hàm tạo có thể được định nghĩa như sau:

var color = 'black';

function Box()
{
   // public property
   this.color = '';

   // private constructor 
   var __construct = function(that) {
       alert("Object Created.");
       that.color = 'green';
   }(this)

   // getter
   this.getColor = function() {
       return this.color;
   }

   // setter
   this.setColor = function(color) {
       this.color = color;
   }

}

var b = new Box();

alert(b.getColor()); // should be green

b.setColor('orange'); 

alert(b.getColor()); // should be orange

alert(color); // should be black

45
Làm thế nào đây không phải là câu trả lời số 1? Chỉ có Jon tạo ra một hàm tạo với các tham số.
Rap

1
Có cách nào chúng ta có thể lấy một ví dụ về thừa kế bằng cách sử dụng mô hình này cho các nhà xây dựng không?
Nathan C. Tresch

1
@Rap Ví dụ về hàm tạo của Jon không có tham số vì nó là Box()hàm :). Nhưng ví dụ này cũng như các ví dụ trong các câu trả lời khác có thể dễ dàng được mở rộng để chấp nhận các tham số.
Alexander Stepaniuk

2
@AndersonGreen bạn có thể thêm một tham số vào Box và sau đó chuyển nó đến hàm tạo riêng dưới dạng tham số hàm.
Gautham C.

1
Không cần "nhà xây dựng tư nhân". Chỉ cần thực hiện công việc của bạn trong Boxchức năng và bạn sẽ ổn (vẫn còn "riêng tư"). "Riêng tư" trong Javascript chỉ có nghĩa là có thể truy cập thông qua phạm vi từ vựng; không cần gán cho thành viên. Ngoài ra: mã này là sai. Nó tạo ra một __constructbiến toàn cục, khá tệ. varnên được sử dụng để hạn chế phạm vi __construct.
mattbasta

23

Vì vậy, điểm của tài sản "xây dựng" là gì? Không thể tìm ra nơi nó có thể hữu ích, bất kỳ ý tưởng?

Điểm của thuộc tính constructor là cung cấp một số cách giả vờ JavaScript có các lớp. Một trong những điều bạn không thể làm một cách hữu ích là thay đổi hàm tạo của đối tượng sau khi nó được tạo. Nó phức tạp lắm.

Tôi đã viết một tác phẩm khá toàn diện về nó vài năm trước: http://joost.zeekat.nl/constructor-considered-mildly- bối rối.html


Vấn đề là sử dụng từ khóa "mới". "d = new Drofto ()" tạo một đối tượng trống và chạy chức năng Drofto với đối tượng mới được giới hạn là "này". Hàm Drofto có thể trả lại bất cứ thứ gì, nhưng theo thông lệ, nó sẽ trả lại một cái gì đó được coi là một thành viên của lớp Drofto.
Juan Lanus

16

Ví dụ ở đây: http://jsfiddle.net/FZ5nC/

Hãy thử mẫu này:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Name = Name||{};
Name.Space = Name.Space||{};

//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Name.Space.ClassName = function Name_Space_ClassName(){}

//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Name.Space.ClassName.prototype = {
  v1: null
 ,v2: null
 ,f1: function Name_Space_ClassName_f1(){}
}

//============================================================
// Static Variables
//------------------------------------------------------------
Name.Space.ClassName.staticVar = 0;

//============================================================
// Static Functions
//------------------------------------------------------------
Name.Space.ClassName.staticFunc = function Name_Space_ClassName_staticFunc(){
}
</script>

Bạn phải điều chỉnh không gian tên của mình nếu bạn đang xác định một lớp tĩnh:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>

Lớp ví dụ:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};

//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Shape.Rectangle = function Shape_Rectangle(width, height, color){
    this.Width = width;
    this.Height = height;
    this.Color = color;
}

//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Shape.Rectangle.prototype = {
  Width: null
 ,Height: null
 ,Color: null
 ,Draw: function Shape_Rectangle_Draw(canvasId, x, y){
    var canvas = document.getElementById(canvasId);
    var context = canvas.getContext("2d");
    context.fillStyle = this.Color;
    context.fillRect(x, y, this.Width, this.Height);
 }
}

//============================================================
// Static Variables
//------------------------------------------------------------
Shape.Rectangle.Sides = 4;

//============================================================
// Static Functions
//------------------------------------------------------------
Shape.Rectangle.CreateSmallBlue = function Shape_Rectangle_CreateSmallBlue(){
    return new Shape.Rectangle(5,8,'#0000ff');
}
Shape.Rectangle.CreateBigRed = function Shape_Rectangle_CreateBigRed(){
    return new Shape.Rectangle(50,25,'#ff0000');
}
</script>

Ví dụ khởi tạo:

<canvas id="painting" width="500" height="500"></canvas>
<script>
alert("A rectangle has "+Shape.Rectangle.Sides+" sides.");

var r1 = new Shape.Rectangle(16, 12, "#aa22cc");
r1.Draw("painting",0, 20);

var r2 = Shape.Rectangle.CreateSmallBlue();
r2.Draw("painting", 0, 0);

Shape.Rectangle.CreateBigRed().Draw("painting", 10, 0);
</script>

Các hàm thông báo được định nghĩa là AB = function A_B (). Điều này là để làm cho kịch bản của bạn dễ dàng hơn để gỡ lỗi. Mở bảng điều khiển Thành phần kiểm tra của Chrome, chạy tập lệnh này và mở rộng nền tảng gỡ lỗi:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};

//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
    A.Func.That.Does.Not.Exist();
}

Fail.Test();
</script>

Ví dụ được thêm vào. Cũng thêm thông tin về cải thiện đầu ra gỡ lỗi.
bitlather

1
Có lẽ bởi vì nó thêm một mức độ phức tạp không cần thiết cho vấn đề. Thật khó để tìm câu trả lời trong bài viết của bạn vì khoảng cách tên phạm vi và khai báo lớp tĩnh. Đừng hiểu sai ý tôi, đó là thông tin tốt nhưng chắc chắn sẽ khó hiểu hơn là hữu ích nếu bạn đang cố gắng để hiểu được. Tôi có khả năng nửa chừng về JS và tôi hầu như không hiểu những gì bạn đang làm ở đây hoặc tại sao nó liên quan đến "Làm thế nào để tôi xây dựng?"
Bmo

1
Cảm ơn vì sự sáng suốt, Bmo. Đó là một bài viết dài, nhưng đó là vì tôi không hiểu việc sử dụng hàm tạo nếu nó không được gắn với một đối tượng được xác định rõ và triển khai lớp tĩnh. Khi học C ++ hoặc Java, bạn phải học cách triển khai các lớp cùng với cách triển khai các hàm tạo. Web dev đã trở nên thú vị hơn nhiều kể từ khi tôi tình cờ thấy phương pháp viết javascript này và tôi chỉ muốn chia sẻ. Tôi đã di chuyển chiếc bấc lên trên cùng để dễ tìm hơn. Tôi hy vọng rằng sẽ làm rõ bất kỳ sự nhầm lẫn.
bitlather

1
@Bmo Bạn có nghiêm túc không khi hai dòng về không gian tên khó tìm ra hàm tạo chính xác bên dưới, đặc biệt là đưa ra nhận xét Trình xây dựng - PHẢI Ở ĐẦU TẬP TIN? Cung cấp một ví dụ với không gian tên là rất đáng hoan nghênh, cộng đồng dev javascript bỏ qua các không gian tên gây ra lỗi khó tìm khi tên xung đột. Thật buồn khi thấy các nhà phát triển js nghĩ rằng nếu họ sao chép một đoạn văn bản từ một bài đăng trên internet và làm điều gì đó tương tự với những gì họ cần thì công việc của họ đã hoàn tất.
dùng3285954

1
Vấn đề chính với js và phát triển web nói chung là hầu hết các nhà phát triển bỏ qua tất cả các thực hành những gì ngành công nghiệp tạo ra trong hơn 50 năm và nghĩ rằng nếu họ có thể thực hiện một cuộc gọi ajax thì họ là vua. Thật buồn khi thấy rằng phải mất rất nhiều năm để bắt đầu sử dụng các mô hình và thực tiễn nổi tiếng trong javascript.
dùng3285954

10

Đây là một hàm tạo:

function MyClass() {}

Khi bạn làm

var myObj = new MyClass();

MyClass được thực thi và một đối tượng mới được trả về của lớp đó.


1
Để làm rõ, điều này có nghĩa là gì ở đầu lớp bạn có thể nói alert(valuePassedInAsArgument);và điều này sẽ chạy một lần cho mỗi lần khởi tạo, vì vậy toàn bộ lớp là chính hàm tạo.
Martin Lyne

new object is returned of that class- không phải nó giống như một đối tượng mới được trả về của hàm đó sao?
Don Cheadle

trong các chức năng javascript là các đối tượng
Leo

8

Tôi thấy hướng dẫn này rất hữu ích. Cách tiếp cận này được sử dụng bởi hầu hết các trình cắm jQuery.

http://www.htmlgoodies.com/html5/tutorials/create-an-object-oriented-javascript- class-constructor.html#fbid=OVYAQL_TDpK

var Class = function(methods) {   
    var klass = function() {    
        this.initialize.apply(this, arguments);          
    };  

    for (var property in methods) { 
       klass.prototype[property] = methods[property];
    }

    if (!klass.prototype.initialize) klass.prototype.initialize = function(){};      

    return klass;    
};

Hiện nay ,

var Person = Class({ 
    initialize: function(name, age) {
        this.name = name;
        this.age  = age;
    },
    toString: function() {
        return "My name is "+this.name+" and I am "+this.age+" years old.";
    }
}); 

var alice = new Person('Alice', 26);
alert(alice.name); //displays "Alice"
alert(alice.age); //displays "26"
alert(alice.toString()); //displays "My name is Alice and I am 26 years old" in most browsers.
//IE 8 and below display the Object's toString() instead! "[Object object]"

10
Tôi co rúm bất cứ khi nào tôi thấy mọi người sử dụngklass
Madbreaks

8

Mô hình này đã phục vụ tôi tốt. Với mẫu này, bạn tạo các lớp trong các tệp riêng biệt, tải chúng vào ứng dụng tổng thể của bạn "khi cần thiết".

// Namespace
// (Creating new if not instantiated yet, otherwise, use existing and just add to it)
var myApp = myApp || {};

// "Package" 
// Similar to how you would establish a package in other languages
(function() {

// "Class"
var MyClass = function(params) {
    this.initialize(params);
}

    // "Private Static" vars 
    //    - Only accessible to functions in this class.
    //    - Doesn't get wiped out when we create a new instance.
    var countInstances = 0;
    var allInstances = [];

    // "Private Static" functions 
    //    - Same as above, but it's a function accessible 
    //      only to other functions in this class.
    function doSomething(){
    }

    // "Public Static" vars
    //    - Everyone has access.
    //    - Doesn't get wiped out when we create a new instance.
    MyClass.counter = 0;

    // "Public Static" functions
    //    - Same as above, but anyone can call this "static method".
    //    - Kinda like a singleton class situation.
    MyClass.foobar = function(){
    }

    // Public properties and methods are built into the "prototype"
    //    - This is how each instance can become unique unto itself.
    //    - Establishing "p" as "local" (Static Private) variable 
    //      simply so we don't have to keep typing "MyClass.prototype" 
    //      for each property and function.
var p = MyClass.prototype;

    // "Public" vars
    p.id = null;
    p.firstname = null;
    p.lastname = null;

    // "Private" vars
    //    - Only used by "this" instance.
    //    - There isn't "true" privacy for each 
    //      instance so we have to fake it. 
    //    - By tradition, we indicate "privacy"  
    //      by prefixing it with an underscore. 
    //    - So technically, anyone can access, but we simply 
    //      don't tell anyone about it (e.g. in your API)
    //      so no one knows about it :)
    p._foo = null;

    p.initialize = function(params){
        this.id = MyClass.counter++;
        this.firstname = params.firstname;
        this.lastname = params.lastname;
        MyClass.counter++;
        countInstances++;
        allInstances.push(this);
    }

    p.doAlert = function(theMessage){
        alert(this.firstname + " " + this.lastname + " said: " + theMessage + ". My id:" + this.id + ".  Total People:" + countInstances + ". First Person:" + allInstances[0].firstname + " " + allInstances[0].lastname);
    }


// Assign class to app
myApp.MyClass = MyClass;

// Close the "Package"
}());

// Usage example:
var bob = new myApp.MyClass({   firstname   :   "bob",
                                lastname    :   "er"
                            });

bob.doAlert("hello there");

Đó là các biến đối tượng nhưng chúng có khả năng truy cập "công khai", không "riêng tư" như trong C ++ hoặc Java.
Potatoswatter

Làm thế nào bạn sẽ đi về việc tạo một biến riêng tư (theo nghĩa cổ điển) có liên quan đến thể hiện, nhưng không phổ biến cho tất cả các trường hợp?
bob

Xem trang web của Douglas Crockford , anh ấy là một trong những nhà thiết kế ngôn ngữ và là người có thẩm quyền hàng đầu. Tôi không luôn luôn tuân theo các mẫu của anh ta, nhưng nói chung, một biến riêng là một cục bộ vartrong hàm tạo (hoặc đối số hàm hoặc trong hàm giống như hàm tạo).
Potatoswatter

Cảm ơn vì mẹo ... trang sau giải thích những gì tôi đang tìm kiếm: javascript.crockford.com/private.html
bob

Ồ, xin lỗi vì đã không kiểm tra liên kết: P
Potatoswatter

8

Có, bạn có thể định nghĩa một hàm tạo bên trong một khai báo lớp như thế này:

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

cho va chạm IE> 12
zloctb

Đối với phiên bản IE> = 12 :) msdn.microsoft.com/en-au/l Library / dn802832 (v
Bruno

1
Đây là câu trả lời thực tế duy nhất cho câu hỏi. : /
MarcD

6

Tôi đoán tôi sẽ đăng những gì tôi làm với đóng javascript vì chưa có ai sử dụng bao đóng.

var user = function(id) {
  // private properties & methods goes here.
  var someValue;
  function doSomething(data) {
    someValue = data;
  };

  // constructor goes here.
  if (!id) return null;

  // public properties & methods goes here.
  return {
    id: id,
    method: function(params) {
      doSomething(params);
    }
  };
};

Bình luận và đề xuất cho giải pháp này đều được chào đón. :)


1
Một vài nhận xét: 1) tuyên bố nếu (! Id) không an toàn, các giá trị như 0 hoặc sai sẽ khiến nó đánh giá đúng và trả về null. Tôi đoán bạn muốn kiểm tra không xác định hoặc null trong trường hợp nào === null và === không xác định sẽ tốt hơn. 2) Điều này gần giống với mẫu Mô-đun hơn ( adequTHERgood.com/2010/3/JavaScript-Module-Potype-In-Depth ) so với hàm tạo, sự khác biệt là Mô-đun trả về một Đối tượng từ hàm trong khi hàm tạo tạo một đối tượng khi được ghép nối với từ khóa mới và trong trường hợp đó, bạn sẽ đặt giá trị trên 'this' thay vì một đối tượng.
Giàu

4

Sử dụng mẫu của Nick ở trên, bạn có thể tạo một hàm tạo cho các đối tượng không có tham số bằng cách sử dụng câu lệnh return làm câu lệnh cuối cùng trong định nghĩa đối tượng của bạn. Trả về hàm constructor của bạn như bên dưới và nó sẽ chạy mã trong __construct mỗi khi bạn tạo đối tượng:

function Box()
{
   var __construct = function() {
       alert("Object Created.");
       this.color = 'green';
   }

  this.color = '';

   this.getColor = function() {
       return this.color;
   }

   __construct();
}

var b = new Box();

1
Bạn không trả về hàm tạo, bạn chỉ gọi nó.
David Conrad

Nếu bạn cố gắng sử dụng this.getColor(); trên dòng trênalert("Object Created."); sẽ không có gì được cảnh báo. Sẽ có một lỗi như "getColor không được xác định". Nếu bạn muốn xây dựng để có thể gọi các phương thức khác trong đối tượng, nó cần được xác định sau tất cả các phương thức khác. Vì vậy, thay vì gọi __construct();đến dòng cuối cùng, chỉ cần xác định cấu trúc ở dưới đó và đặt ()sau nó để buộc nó tự động thực thi.
thinsoldier

Điều chỉnh. Thêm ()vào cuối định nghĩa __construct vẫn dẫn đến lỗi. Tôi đã phải gọi __construct();trên đường dây của chính nó như trong mã gốc để tránh lỗi.
thinsoldier

4

Có thể nó đã đơn giản hơn một chút, nhưng dưới đây là những gì tôi đã nghĩ ra trong năm 2017:

class obj {
  constructor(in_shape, in_color){
    this.shape = in_shape;
    this.color = in_color;
  }

  getInfo(){
    return this.shape + ' and ' + this.color;
  }
  setShape(in_shape){
    this.shape = in_shape;
  }
  setColor(in_color){
    this.color = in_color;
  }
}

Khi sử dụng lớp trên, tôi có những điều sau đây:

var newobj = new obj('square', 'blue');

//Here, we expect to see 'square and blue'
console.log(newobj.getInfo()); 

newobj.setColor('white');
newobj.setShape('sphere');

//Since we've set new color and shape, we expect the following: 'sphere and white'
console.log(newobj.getInfo());

Như bạn có thể thấy, hàm tạo có hai tham số và chúng ta đặt các thuộc tính của đối tượng. Chúng tôi cũng thay đổi màu sắc và hình dạng của đối tượng bằng cách sử dụng các setterchức năng và chứng minh rằng sự thay đổi của nó vẫn còn khi gọi getInfo()sau những thay đổi này.

Một chút muộn, nhưng tôi hy vọng điều này sẽ giúp. Tôi đã thử nghiệm điều này với một mochathử nghiệm đơn vị, và nó hoạt động tốt.


3

Họ làm nếu bạn sử dụng nguyên cảo - mã nguồn mở từ Microsoft :-)

class BankAccount {
 balance: number;
 constructor(initially: number) {
 this.balance = initially;
 }
 deposit(credit: number) {
 this.balance += credit;
 return this.balance;
 }
}

Bản đánh máy cho phép bạn xây dựng các cấu trúc OO 'giả' được biên dịch thành các cấu trúc javascript. Nếu bạn đang bắt đầu một dự án lớn, nó có thể giúp bạn tiết kiệm rất nhiều thời gian và nó đã đạt đến phiên bản mốc 1.0.

http://www.typescriptlang.org/Content/TypeScript%20L Language% 20Specification.pdf

Đoạn mã trên được 'biên dịch' thành:

var BankAccount = (function () {
    function BankAccount(initially) {
        this.balance = initially;
    }
    BankAccount.prototype.deposit = function (credit) {
        this.balance += credit;
        return this.balance;
    };
    return BankAccount;
})();

Tôi đang làm việc trong một dự án lớn và tôi đang cố gắng thuyết phục mọi người rằng TypeScript sẽ cho chúng tôi một buổi chụp. Chúng ta sẽ thấy điều đó diễn ra như thế nào.
wootscootinboogie

@wootscootinboogie Trong một ngày (kết thúc lúc 5h30 ngay bây giờ) Tôi đã đi khá xa và khá thoải mái với nó. Tôi thực sự khuyên bạn nên đọc thông số kỹ thuật thông qua và trong khi bạn có thể bỏ qua một nửa những thứ khó chịu thực sự mà bạn đang ưu tiên đọc nó ít nhất một lần. video của anh chàng này là tuyệt vời youtube.com/user/basaratali/ideo . chúc may mắn)
Simon_Weaver

1

Trong JavaScript, kiểu gọi xác định hành vi của hàm:

  • Gọi trực tiếp func()
  • Gọi phương thức trên một đối tượng obj.func()
  • Constructor gọinew func()
  • Gọi gián tiếp func.call()hoặcfunc.apply()

Hàm được gọi như một hàm tạo khi gọi bằng newtoán tử:

function Cat(name) {
   this.name = name;
}
Cat.prototype.getName = function() {
   return this.name;
}

var myCat = new Cat('Sweet'); // Cat function invoked as a constructor

Bất kỳ đối tượng hoặc nguyên mẫu nào trong JavaScript đều có thuộc tính constructor, tham chiếu đến hàm tạo.

Cat.prototype.constructor === Cat // => true
myCat.constructor         === Cat // => true

Kiểm tra bài này về tài sản xây dựng.


0

Trong khi sử dụng mẫu tuyệt vời của Blixt từ trên xuống, tôi phát hiện ra rằng nó không hoạt động tốt với tính kế thừa đa cấp (MyGrandChildClass mở rộng MyChildClass mở rộng MyClass) - nó lặp đi lặp lại việc gọi hàm tạo của cha mẹ đầu tiên. Vì vậy, đây là một cách giải quyết đơn giản - nếu bạn cần kế thừa nhiều cấp, thay vì sử this.constructor.super.call(this, surName);dụng chainSuper(this).call(this, surName);với hàm chuỗi được định nghĩa như sau:

function chainSuper(cls) {
  if (cls.__depth == undefined) cls.__depth = 1; else cls.__depth++;
  var depth = cls.__depth;
  var sup = cls.constructor.super;
  while (depth > 1) {
    if (sup.super != undefined) sup = sup.super;
    depth--;
  }
  return sup;
}

0

http://www.jsoops.net/ khá tốt cho oop trong Js. Nếu cung cấp riêng tư, được bảo vệ, biến công khai và chức năng, và cả tính năng Kế thừa. Mã ví dụ:

var ClassA = JsOops(function (pri, pro, pub)
{// pri = private, pro = protected, pub = public

    pri.className = "I am A ";

    this.init = function (var1)// constructor
    {
        pri.className += var1;
    }

    pub.getData = function ()
    {
        return "ClassA(Top=" + pro.getClassName() + ", This=" + pri.getClassName()
        + ", ID=" + pro.getClassId() + ")";
    }

    pri.getClassName = function () { return pri.className; }
    pro.getClassName = function () { return pri.className; }
    pro.getClassId = function () { return 1; }
});

var newA = new ClassA("Class");

//***Access public function
console.log(typeof (newA.getData));
// function
console.log(newA.getData());
// ClassA(Top=I am A Class, This=I am A Class, ID=1)

//***You can not access constructor, private and protected function
console.log(typeof (newA.init));            // undefined
console.log(typeof (newA.className));       // undefined
console.log(typeof (newA.pro));             // undefined
console.log(typeof (newA.getClassName));    // undefined

0

chỉ để cung cấp một số loại. ds.oop là một cách hay để khai báo các lớp với các hàm tạo trong javascript. Nó hỗ trợ mọi kiểu thừa kế có thể (Bao gồm 1 loại mà thậm chí c # không hỗ trợ) cũng như Giao diện rất đẹp.

var Color = ds.make.class({
    type: 'Color',
    constructor: function (r,g,b) { 
        this.r = r;                     /* now r,g, and b are available to   */
        this.g = g;                     /* other methods in the Color class  */
        this.b = b;                     
    }
});
var red = new Color(255,0,0);   // using the new keyword to instantiate the class

0

Ở đây chúng ta cần lưu ý một điểm trong tập lệnh java, đó là ngôn ngữ không có lớp, tuy nhiên, chúng ta có thể đạt được nó bằng cách sử dụng các hàm trong tập lệnh java. Cách phổ biến nhất để đạt được điều này, chúng ta cần tạo một hàm trong tập lệnh java và sử dụng từ khóa mới để tạo một đối tượng và sử dụng từ khóa này để xác định thuộc tính và phương thức.Below là ví dụ.

// Function constructor

   var calculator=function(num1 ,num2){
   this.name="This is function constructor";
   this.mulFunc=function(){
      return num1*num2
   };

};

var objCal=new calculator(10,10);// This is a constructor in java script
alert(objCal.mulFunc());// method call
alert(objCal.name);// property call

//Constructors With Prototypes

var calculator=function(){
   this.name="Constructors With Prototypes";
};

calculator.prototype.mulFunc=function(num1 ,num2){
 return num1*num2;
};
var objCal=new calculator();// This is a constructor in java script
alert(objCal.mulFunc(10,10));// method call
alert(objCal.name); // property call

-2

Trong hầu hết các trường hợp, bạn phải khai báo tài sản bạn cần bằng cách nào đó trước khi bạn có thể gọi một phương thức truyền thông tin này. Nếu ban đầu bạn không phải thiết lập một thuộc tính, bạn chỉ có thể gọi một phương thức trong đối tượng như vậy. Có lẽ không phải là cách đẹp nhất để làm điều này nhưng điều này vẫn hoạt động.

var objectA = {
    color: ''; 
    callColor : function(){
        console.log(this.color);
    }
    this.callColor(); 
}
var newObject = new objectA(); 
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.