SORU
20 EKİM 2009, Salı


Nasıl "düzgün" JavaScript özel bir nesne oluşturur?

JavaScript anlamaya çalışıyorum, ve en iyi yolu özellikleri ve yöntemleri olan bir nesne oluşturmak için ne olduğunu merak ediyorum.

Kişi "var self =" ve sonra "kendini tüm fonksiyonları kapsamında her zaman doğru olduğundan emin olmak için". kullanır. bu kullanılan örnekler gördüm

O zaman kullanma örnekleri gördüm .prototip Diğerleri satır içi bunu yaparken özellikler eklemek için.

Birisi bana bazı Özellikleri ve Yöntemleri ile JavaScript bir nesne uygun bir örnek verebilir misiniz?

Teşekkürler!

CEVAP
21 EKİM 2009, ÇARŞAMBA


JavaScript dersleri ve örnekleri uygulamak için iki model vardır: prototipleme ve kapatma yolu. Hem avantajları ve dezavantajları var, ve genişletilmiş varyasyonları bol vardır. Birçok programcı ve kitaplıklar farklı yaklaşımlar ve sınıf-işleme dili çirkin bazı parçalar üzerinde kağıt için yardımcı fonksiyonlar.

Sonuç olarak, karma şirkette metaclasses, tüm biraz farklı davranmak bir karışıklık olacak. Daha da kötüsü, öğretici malzeme JavaScript en korkunç ve-arasındaki tüm bazlar kapak için bir tür uzlaşmaya hizmet vermektedir, seni çok şaşkın bırakarak. (Muhtemelen yazarın da kafası karışık. JavaScript nesne modeli en programlama dilleri çok farklı, ve birçok yerde direkt olarak kötü tasarlanmış.)

La başlayalımprototip gibi. Bu en JavaScript-yerel elde edebilirsiniz: havai kod ve örneğin bu nesne türünün örnekleri ile çalışacak. en az var

function Shape(x, y) {
    this.x= x;
    this.y= y;
}

Bu yapıcı işlevi prototype arama için yazarak örnek new Shape tarafından oluşturulan yöntemleri ekleyebiliriz:

Shape.prototype.toString= function() {
    return 'Shape at ' this.x ', ' this.y;
};

Şimdi, mümkün olduğunca çok alt sınıf için JavaScript sınıflara yaptığı çağrı. Tamamen garip sihirli değiştirerek yaptığımız prototype özellik:

function Circle(x, y, r) {
    Shape.call(this, x, y); // invoke the base class's constructor function to take co-ords
    this.r= r;
}
Circle.prototype= new Shape();

bu yöntem eklemeden önce:

Circle.prototype.toString= function() {
    return 'Circular ' Shape.prototype.toString.call(this) ' with radius ' this.r;
}

Bu örnek çalışır ve birçok dersler içinde böyle bir kod göreceksiniz. Ama adam, new Shape() çirkin olduğunu: gerçek Şekli oluşturulacak olsa da temel sınıf başlatmasını ediyoruz. Başına gelir bu iş bu kadar basit durum, çünkü JavaScript bu kadar özensiz: sağlar sıfır bağımsız olmak geçti, bu durumda x y olmak undefined ve atanır prototip this.x this.y. Eğer kurucu işlevi daha karmaşık bir şey yapıyor olsaydı, onun yüzünde düz düşecek.

Bu yüzden yapmamız gereken şey, bir şekilde sınıf seviyesinde istiyoruz yöntemleri ve diğer üyeler içeren bir prototip nesne, temel sınıfın kurucu işlevi çağırmadan oluşturmak için bulmak. Bunu yapmak için yardımcı kod yazmak zorunda kalacağız. Bu benim bildiğim en basit yaklaşım

function subclassOf(base) {
    _subclassOf.prototype= base.prototype;
    return new _subclassOf();
}
function _subclassOf() {};

Bu hiçbir şey yapmaz, yeni bir yapıcı fonksiyon prototipi içinde temel sınıfın üyeleri transferler, bu oluşturucu kullanır. Şimdi sadece yazabiliriz:

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.prototype= subclassOf(Shape);

yerine new Shape() yanlışlığı. Artık dahili sınıflar için ilkel kabul edilebilir bir set var.

Bu model altında düşünebilirsiniz birkaç iyileştirmeler ve uzantılar vardır. Örneğin burada sözdizimsel şeker bir sürüm değil

Function.prototype.subclass= function(base) {
    var c= Function.prototype.subclass.nonconstructor;
    c.prototype= base.prototype;
    this.prototype= new c();
};
Function.prototype.subclass.nonconstructor= function() {};

...

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.subclass(Shape);

Her iki sürüm yapıcı işlevini birçok dilde olduğu gibi miras, bu dezavantajı var. Eğer öyleyse alt yapı işlemi için hiçbir şey ekler bile, üs istediğini kurucu ile aramayı unutma. Bu biraz otomatik apply ama yine de yazmak için kullanıyor

function Point() {
    Shape.apply(this, arguments);
}
Point.subclass(Shape);

Çok yaygın bir uzantısı kendi işlevini yerine yapıcı içine hazırlama şarabı. Bu işlev, Tamam o zaman: tabanından devralabilir

function Shape() { this._init.apply(this, arguments); }
Shape.prototype._init= function(x, y) {
    this.x= x;
    this.y= y;
};

function Point() { this._init.apply(this, arguments); }
Point.subclass(Shape);
// no need to write new initialiser for Point!

Şimdi sadece her sınıf için aynı yapıcı işlevi birkaç yazı var. Belki de biz hareket içine kendi yardımcı işlevi bu yüzden gerek yok yazmaya devam et, örneğin yerine Function.prototype.subclass, dönüyor dönüyor ve icar temel sınıf İşlevi tükür alt:

Function.prototype.makeSubclass= function() {
    function Class() {
        if ('_init' in this)
            this._init.apply(this, arguments);
    }
    Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
    Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
    return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};

...

Shape= Object.makeSubclass();
Shape.prototype._init= function(x, y) {
    this.x= x;
    this.y= y;
};

Point= Shape.makeSubclass();

Circle= Shape.makeSubclass();
Circle.prototype._init= function(x, y, r) {
    Shape.prototype._init.call(this, x, y);
    this.r= r;
};

...diğer diller gibi biraz daha, biraz sakar sözdizimi ile de olsa görünmeye başladı. Eğer isterseniz birkaç ekstra özellikleri serpin. Belki de makeSubclass ve bir sınıf adı Al unutma ve bir varsayılan toString kullanmadan sağlamak. Belki yapıcı yanlışlıkla new operatör olmadan adı olmuştur aksi halde çok can sıkıcı genellikle hata ayıklama neden olan tespit yapmak istiyorum:

Function.prototype.makeSubclass= function() {
    function Class() {
        if (!(this instanceof Class))
            throw('Constructor called without "new"');
        ...

Belki de tüm yeni üyelere geçişte ve makeSubclass prototip eklemek için, Class.prototype... bu kadar çok yazmak zorunda kalsın. Sınıf sistemleri bir sürü, örneğin:

Circle= Shape.makeSubclass({
    _init: function(x, y, z) {
        Shape.prototype._init.call(this, x, y);
        this.r= r;
    },
    ...
});

Nesne bir sistem arzu düşünebilirsiniz Olası özellikleri bir yeri vardır ve kimse gerçekten belirli bir formülü kabul eder.


kapatma yoluo zaman. Bu JavaScript sorunlarını tabanlı prototip miras, kalıtım kullanarak önler. Bunun yerine:

function Shape(x, y) {
    var that= this;

    this.x= x;
    this.y= y;

    this.toString= function() {
        return 'Shape at ' that.x ', ' that.y;
    };
}

function Circle(x, y, r) {
    var that= this;

    Shape.call(this, x, y);
    this.r= r;

    var _baseToString= this.toString;
    this.toString= function() {
        return 'Circular ' _baseToString(that) ' with radius ' that.r;
    };
};

var mycircle= new Circle();

Şimdi Shape her örnek toString yöntem (ve herhangi bir diğer yöntemleri ya da ekliyoruz diğer sınıf üyeleri) kendi kopyasını sahip olacak.

Her durumda, her bir sınıf üyesi kendi kopyasını sahip hakkında kötü şey, daha az verimli olmasıdır. Eğer alt örnekler çok sayıda ile ilgileniyor, prototip mirası, daha iyi hizmet edebilir. Bu yöntem, alt sınıf yapıcısı bunun üzerine önce ne olduğunu hatırlamak zorunda, ya da kayboluyor. temel sınıf yöntemi gördüğünüz gibi biraz can sıkıcı bir durum aynı zamanda arama:

Ayrıca miras burada yok çünkü, instanceof operatör işe yaramaz; eğer ihtiyacınız varsa sınıf-koklama için kendi mekanizmaya gerekir. Sen ikenolabilirkeman benzer bir şekilde prototip nesneleri prototip mirası olduğu gibi, biraz zor ve gerçekten buna değer.]

Her örnek kendi yöntemi olmasının güzel yanı Bu yöntem daha sonra onun sahibi olan belirli örneğine bağlı olabilir. Bu eğer sahibinden bir yöntem ayırırsanız bu sonuç hangi yöntem çağrıları, this bağlama JavaScript garip, çünkü yararlıdır:

var ts= mycircle.toString;
alert(ts());

bu yöntem beklendiği gibi Daire örneği olmayacak içinde this (aslında window genel nesne, yaygın hata ayıklama vay haline neden olur). Gerçekte bu bir yöntem ve genel ** 56 ** 55 EventListener alınan atandığında genellikle olur.

Prototip yolu ile, her tür görev için bir kapatma vardır:

setTimeout(function() {
    mycircle.move(1, 1);
}, 1000);

ya da, eğer sen hack Fonksiyonu. (şimdi ya da gelecekte prototip) de function.bind() ile yapabilecekleriniz:

setTimeout(mycircle.move.bind(mycircle, 1, 1), 1000);

eğer örnekleri hepsi kapatılmasına yol, bağlama yapılır için ücretsiz tarafından kapatılması üzerine örnek değişken (genellikle denir that self ama şahsen tavsiye ederim karşı ikinci olarak self zaten varsa, bir kere daha, farklı bir anlam JavaScript). Bağımsız 1, 1 ücretsiz olmasına rağmen yukarıdaki kod parçasında alamadım, yine de bunu yapmak için gerekirse başka bir kapatma veya bind() gerekir.

Kapatma yöntemi türevleri bir sürü de vardır. this tamamen ihmal etmek, that yeni oluşturma ve geri yerine new operatör kullanmayı tercih edebilirsiniz:

function Shape(x, y) {
    var that= {};

    that.x= x;
    that.y= y;

    that.toString= function() {
        return 'Shape at ' that.x ', ' that.y;
    };

    return that;
}

function Circle(x, y, r) {
    var that= Shape(x, y);

    that.r= r;

    var _baseToString= that.toString;
    that.toString= function() {
        return 'Circular ' _baseToString(that) ' with radius ' r;
    };

    return that;
};

var mycircle= Circle(); // you can include `new` if you want but it won't do anything

Hangi yol “mu? doğru Her ikisi de. “”? En iyi Bu duruma göre değişir. FWIW kuvvetle yapıyorum zaman gerçek JavaScript miras için prototip doğru OO şeyler ve basit ıskarta sayfa efektleri için kapama eğilimindedir.

Ama iki şekilde de birçok programcı için karşı sezgisel. Hem de birçok potansiyel dağınık farklılıklar var. Eğer diğer insanların kodunu/kütüphaneleri kullanırsanız her iki yanı arasında pek çok ve genellikle kırık düzenleri) bir araya gelecek. Genel kabul görmüş hiç bir cevap yoktur. JavaScript nesneler dünyasına hoş geldiniz.

[Bu bölüm 94 JavaScript Favori Programlama dilim Değil Neden olmuştur.]

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • alexis gillis

    alexis gilli

    23 HAZİRAN 2011
  • André Frizzo

    André Frizz

    16 Aralık 2006
  • tseyina

    tseyina

    2 AĞUSTOS 2006