Các lớp / đối tượng JavaScript có thể có các hàm tạo không? Chúng được tạo ra như thế nào?
Các lớp / đối tượng JavaScript có thể có các hàm tạo không? Chúng được tạo ra như thế nào?
Câu trả lời:
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
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)
var
làm một biến riêng. this
tạo một biến công khai
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.
Đâ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
, announce
phương thức sử dụng get_name
phươ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 inherit
hà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. :)
cls.prototype
phần: "chia sẻ giữa các trường hợp" chỉ để đọc giá trị (gọi announce
). Nếu bạn đặt myClassInstance.announce
thà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.announce
sẽ ảnh hưởng đến tất cả các trường hợp mặc dù.
MyClass.get_nextId()
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
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ố.
Box
chứ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 __construct
biến toàn cục, khá tệ. var
nên được sử dụng để hạn chế phạm vi __construct
.
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í 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>
Đâ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 đó.
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.
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?
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.
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]"
klass
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");
var
trong hàm tạo (hoặc đối số hàm hoặc trong hàm giống như hàm tạo).
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;
}
}
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. :)
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();
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.
()
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.
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 setter
chứ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 mocha
thử nghiệm đơn vị, và nó hoạt động tốt.
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;
})();
Trong JavaScript, kiểu gọi xác định hành vi của hàm:
func()
obj.func()
new func()
func.call()
hoặcfunc.apply()
Hàm được gọi như một hàm tạo khi gọi bằng new
toá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.
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;
}
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
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
Ở đâ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
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();