JavaScript sınıflarının / nesnelerinin yapıcıları olabilir mi? Nasıl yaratılıyorlar?
JavaScript sınıflarının / nesnelerinin yapıcıları olabilir mi? Nasıl yaratılıyorlar?
Yanıtlar:
Prototipleri kullanma:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
"Renk" gizleme (özel üye değişkenine benziyor):
function Box(col)
{
var color = col;
this.getColor = function()
{
return color;
};
}
Kullanımı:
var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue
var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green
color
. Hangisini kullandığınızı büyük ölçüde kişisel tercihe bağlı olarak öneririm (koruma ve basitlik)
var
özel değişken yapar. this
ortak bir değişken yapıyor
Foo
belirtilmezken, ikinci durumda Foo
çağrıldığını bilecektir . Hata ayıklama için çok yararlı.
JavaScript'te bazen OOP benzeri davranışlar için kullandığım bir şablon. Gördüğünüz gibi kapanışları kullanarak özel (hem statik hem de örnek) üyeleri simüle edebilirsiniz. Ne new MyClass()
dönecektir atanmış yalnızca özelliklere sahip bir nesnedir this
nesne ve içinde prototype
nesnesi "sınıfına."
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;
})();
Bu kalıbı kullanarak kalıtım hakkında bana soru soruldu, işte gidiyor:
// 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;
})();
Ve hepsini kullanmak için bir örnek:
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
Gördüğünüz gibi, sınıflar birbirleriyle doğru bir şekilde etkileşime giriyorlar (statik kimliği paylaşıyorlar MyClass
, announce
yöntem doğru get_name
yöntemi kullanıyor vb.)
Dikkat edilmesi gereken bir şey, örnek özelliklerinin gölgelenmesi gerektiğidir. Aslında, inherit
işlevin , işlev olan tüm örnek özelliklerinden (kullanma hasOwnProperty
) geçmesini sağlayabilir ve otomatik olarak bir super_<method name>
özellik ekleyebilirsiniz . Bu, this.super_get_name()
onu geçici bir değerde saklamak yerine kullanarak çağırmanıza izin verir call
.
Prototip üzerindeki yöntemler için, yukarıdakiler hakkında endişelenmenize gerek yoktur, ancak süper sınıfın prototip yöntemlerine erişmek istiyorsanız, sadece arayabilirsiniz this.constructor.super.prototype.methodName
. Daha az ayrıntılı yapmak istiyorsanız, elbette kolaylık özellikleri ekleyebilirsiniz. :)
cls.prototype
Parça hakkında sadece bir not : "örnekler arasında paylaşılan" yalnızca değeri okumak (arama announce
) içindir. myClassInstance.announce
Başka bir değere ayarlarsanız , içinde yeni bir özellik oluşturur myClassInstance
, bu nedenle sınıfın diğer örnekleri için değil, yalnızca bu nesne için geçerlidir. Ancak atamak MyClass.prototype.announce
tüm örnekleri etkileyecektir.
MyClass.get_nextId()
Bana öyle geliyor ki birçoğunuz bir kurucu değil, alıcılar ve ayarlayıcılar örneği veriyorsunuz, yani http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) .
lunched-dan daha yakındı ama örnek jsFiddle'da işe yaramadı.
Bu örnek, yalnızca nesnenin oluşturulması sırasında çalışan özel bir yapıcı işlevi oluşturur.
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
Genel özellikler atamak istiyorsanız, kurucu şöyle tanımlanabilir:
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()
işlev olduğu için parametre yoktur :). Ancak bu örnek ve diğer cevaplardaki örnekler parametreleri kabul etmek için kolayca genişletilebilir.
Box
işlevini yapmak ve gitmek için iyi (hala "özel"). Javascript'teki "Özel" kelimesine sözcük alanı üzerinden erişilebileceği anlamına gelir; üyelere atanmasına gerek yok. Ayrıca: bu kod yanlış. Küresel bir __construct
değişken yaratır , ki bu oldukça kötüdür. var
kapsamını kısıtlamak için kullanılmalıdır __construct
.
Peki "yapıcı" mülkiyetin anlamı nedir? Nerede yararlı olabileceğini, herhangi bir fikri bulamıyor musunuz?
Constructor özelliğinin amacı, JavaScript sınıfları gibi davranmanın bir yolunu sağlamaktır. Eğer şeylerden biri olamaz yararlı yapmak oluşturulduktan geçirildikten sonra bir nesnenin yapıcısı değiştirmektir. Karmaşık.
Birkaç yıl önce üzerinde oldukça kapsamlı bir parça yazdım: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
Burada örnek: http://jsfiddle.net/FZ5nC/
Bu şablonu deneyin:
<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>
Statik bir sınıf tanımlıyorsanız, ad alanınızı ayarlamanız gerekir:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>
Örnek sınıf:
<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>
Örnek örnekleme:
<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>
Uyarı işlevleri AB = işlev A_B () olarak tanımlanır. Bu, betiğinizin hata ayıklamasını kolaylaştırmak içindir. Chrome'un Öğeyi Denetle panelini açın, bu komut dosyasını çalıştırın ve hata ayıklama geri izini genişletin:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};
//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}
Fail.Test();
</script>
Bu bir kurucu:
function MyClass() {}
Ne zaman yaparsın
var myObj = new MyClass();
MyClass
yürütülür ve bu sınıftan yeni bir nesne döndürülür.
alert(valuePassedInAsArgument);
ve bu her örnekleme için bir kez çalışacaktır, bu yüzden tüm sınıf kurucunun kendisidir.
new object is returned of that class
- daha çok bu işlevin yeni bir nesnesi döndürülmüş gibi değil mi?
Bu dersi çok faydalı buldum. Bu yaklaşım, jQuery eklentilerinin çoğu tarafından kullanılır.
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;
};
Şimdi,
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
Bu desen bana iyi hizmet etti. Bu kalıpla, ayrı dosyalarda sınıflar oluşturur ve bunları "gerektiği gibi" genel uygulamanıza yüklersiniz.
// 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
yapıcıda (veya işlev bağımsız değişkeninde veya yapıcı benzeri bir işlevde) yereldir .
Evet, sınıf bildiriminde aşağıdaki gibi bir kurucu tanımlayabilirsiniz:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Ben henüz kimse kapatma kullanmıyor çünkü sanırım javascript kapatma ile ne yapacağımı göndereceğim.
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);
}
};
};
Bu çözüm için görüş ve önerilerinizi bekliyoruz. :)
Yukarıdaki Nick'in numuneyi kullanarak, nesneler için bir kurucu oluşturabilir olmadan da nesne tanımında geçen ifadesi olarak bir dönüş ifadesini kullanarak parametreleri. Yapıcı işlevinizi aşağıdaki gibi döndürün ve nesneyi her oluşturduğunuzda kodu __construct içinde çalıştırır:
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();
Yukarıdaki satırda kullanmaya çalışırsanız alert("Object Created.");
hiçbir şey uyarılmaz. "GetColor tanımlanmadı" gibi bir hata oluşacaktır. Yapının nesnedeki diğer yöntemleri çağırabilmesini istiyorsanız, diğer tüm yöntemlerden sonra tanımlanması gerekir. Yani __construct();
son hatta çağırmak yerine sadece orada inşa tanımlamak ve ()
sonra otomatik yürütmek için zorla koymak .
()
__Construct tanımının sonuna eklenmesi hala hatayla sonuçlandı. __construct();
Hatayı önlemek için orijinal kodda olduğu gibi kendi hattında aramak zorunda kaldım .
Belki biraz daha basit oldu, ancak 2017'de şu an ortaya koyduğum şey:
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;
}
}
Yukarıdaki sınıfı kullanırken, aşağıdakilere sahibim:
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());
Gördüğünüz gibi, yapıcı iki parametre alır ve nesnenin özelliklerini ayarlıyoruz. Ayrıca, setter
işlevleri kullanarak nesnenin rengini ve şeklini değiştiririz ve getInfo()
bu değişikliklerden sonra değişimin değiştiğini kanıtlarız .
Biraz geç, ama umarım bu yardımcı olur. Bunu mocha
birim testi ile test ettim ve iyi çalışıyor.
Typescript - açık kaynak kodlu MicroSoft kullanıyorsanız yaparlar :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
Typcript, javascript yapılarına derlenen OO yapılarını 'sahte' hale getirmenizi sağlar. Büyük bir projeye başlıyorsanız, size çok zaman kazandırabilir ve henüz kilometre taşı 1.0 sürümüne ulaşmıştır.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
Yukarıdaki kod 'derlenir':
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
JavaScript'te çağırma türü işlevin davranışını tanımlar:
func()
obj.func()
new func()
func.call()
veyafunc.apply()
İşleç kullanılarak çağrı yaparken işlev yapıcı olarak çağrılır new
:
function Cat(name) {
this.name = name;
}
Cat.prototype.getName = function() {
return this.name;
}
var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
JavaScript'teki herhangi bir örnek veya prototip nesnesi constructor
, yapıcı işlevine başvuran bir özelliğe sahiptir.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Yapıcı özelliği hakkında bu gönderiyi kontrol edin .
Blixt'in harika şablonunu yukarıdan kullanırken, çok seviyeli kalıtımla (MyGhCCildClass genişletme MyChildClass genişletme MyClass) iyi çalışmadığını öğrendim - ilk ebeveynin yapıcısını tekrar tekrar çağırmaya devam ediyor. İşte basit bir çözüm - eğer böyle tanımlanmış zincir fonksiyonu ile this.constructor.super.call(this, surName);
kullanmak yerine, çok seviyeli mirasa ihtiyacınız varsa chainSuper(this).call(this, surName);
:
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/ Js'teki oop için oldukça iyi. Özel, korumalı, ortak değişken ve işlev ve ayrıca Kalıtım özelliği sağlarsa. Örnek Kod:
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
sadece biraz çeşitlilik sunmak için. ds.oop , javascript içinde kurucuları olan sınıfları bildirmenin güzel bir yoludur. Olası her türlü kalıtım türünü (c # bile desteklemeyen 1 tür dahil) ve güzel arayüzleri destekler.
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
Burada java betiğinde bir noktayı fark etmeliyiz, sınıfsız bir dildir, ancak java betiğindeki işlevleri kullanarak bunu başarabiliriz. Bunu başarmanın en yaygın yolu, java komut dosyasında bir işlev oluşturmanız ve bir nesne oluşturmak için yeni anahtar kelime kullanmamız ve özellik ve yöntemleri tanımlamak için bu anahtar kelimeyi kullanmamız gerekir.
// 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
Çoğu durumda, bu bilgileri ileten bir yöntemi çağırabilmeniz için bir şekilde ihtiyacınız olan özelliği bildirmeniz gerekir. Başlangıçta bir özellik ayarlamanız gerekmiyorsa, nesne içindeki bir yöntemi böyle çağırabilirsiniz. Muhtemelen bunu yapmanın en güzel yolu değil, ama yine de işe yarıyor.
var objectA = {
color: '';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();