ES6 sınıf örneğinin sınıf adını alın


157

ES6 sınıfı örneğinden sınıf adını almanın 'uyumlu' yolları var mı? Ondan başka

someClassInstance.constructor.name

Şu anda Traceur uygulamasına güveniyorum. Ve Function.nameTraceur'da Babel'in çok amaçlı bir dolgusu var gibi görünüyor .

Her şeyi özetlemek gerekirse: ES6 / ES2015 / Harmony'de başka bir yol yoktu ve ES.Next'te ATM'den hiçbir şey beklenmiyor.

Minimuma indirilmemiş sunucu tarafı uygulamaları için yararlı desenler sağlayabilir, ancak tarayıcı / masaüstü / mobil amaçlı uygulamalarda istenmeyen bir durumdur.

Babel kullandığıcore-js Polyfill için Function.name, uygun şekilde Traceur ve typescript uygulamaları için elle yüklenmelidir.


2
Aynı konuyla karşılaştım; Traceur için tek çözüm, uyumlu olarak nitelendirmediğini sanmıyorum adı çıkarmak için gerçek sınıf kodunu ayrıştırmaktı. Sadece hapı yuttum ve Babil'e geçtim; Traceur'un gelişimi biraz durgun görünüyor ve birçok ES6 özelliği zayıf bir şekilde uygulanmış. Bahsettiğiniz olarak instance.constructor.nameve class.namedüzgün ES6 sınıf adını döndürür.
Andrew Odri

Tek yol gibi görünüyor.
Frederik Krautwald

Bu ES6 standardında mı?
drudru

12
someClassInstance.constructor.nameKodunuzu çirkin hale getirdiğinizde karışık olacağından bahsetmeye değer .
JamesB

stackoverflow.com/questions/2648293/… Buna bakmak isteyebilir, w / ile çalışmalıdır .constructor.
Florrie

Yanıtlar:


206

someClassInstance.constructor.namebunu yapmanın doğru yolu. Transpiller bunu desteklemeyebilir, ancak şartnameye göre standart yoldur. ( nameClassDeclaration yapımları ile beyan edilen fonksiyonların özellikleri 14.5.15 , adım 6'da belirtilmiştir.)


2
Ben de bundan korkuyordum. Bunun için makul bir çoklu dolgunun farkında mısınız? Babel'in bunu nasıl yaptığını anlamaya çalıştım ama çok az başarılı oldum.
Estus Flask

Bir dil özelliği (sınıflar) için bir çoklu dolgu ile ne demek istediğinizi gerçekten bilmiyorum.
Domenic

Yani constructor.name için çok dolgu. Görünüşe göre Babil uyguladı, ama bunu nasıl yaptığını anlamada başarılı olamadım.
Estus Flask

2
@estus someClassInstance.constructorbir işlevdir . Tüm İşlevlerin nameadlarına ayarlanmış bir özelliği vardır. Bu yüzden babel'in hiçbir şey yapmasına gerek yok. Lütfen developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
Esteban

2
@Ebeban Görünüşe göre Babel, core-js çoklu dolgularını (Function.name için bir çoklu dolgu dahil) sürekli olarak teşvik ediyor gibi görünüyor, bu yüzden bazı Babel yapıları tüm tarayıcılarda kutunun dışında çalışabilir.
Estus Flask

53

@Domenic'in dediği gibi kullanın someClassInstance.constructor.name. @Ebeban yorumlarda bahsediyor ki

someClassInstance.constructorbir işlevdir. Tüm İşlevlerin bir nameözelliği vardır ...

Bu nedenle, sınıf adına statik olarak erişmek için aşağıdakileri yapın (bu benim Babel BTW sürümüm ile çalışır. @Domenic hakkındaki yorumlara göre kilometreniz değişebilir).

class SomeClass {
  constructor() {}
}

var someClassInstance = new SomeClass();
someClassInstance.constructor.name;      // === 'SomeClass'
SomeClass.name                           // === 'SomeClass'

Güncelleme

Babel iyiydi, ama çirkinlik / küçülme sonunda sorunlara neden oldu. Bir oyun yapıyorum ve bir araya getirilmiş Sprite kaynaklarının bir karmasını oluşturuyorum (anahtar işlev adıdır). Küçültmeden sonra her işlev / sınıf adlandırıldı t. Bu hash öldürür. GulpBu projede kullanıyorum ve bulduğum gulp-uglify belgelerini okuduktan sonra bu yerel değişken / işlev adı yönetiminin gerçekleşmesini önleyen bir parametre var. Böylece, gf dosyamda değiştim

.pipe($.uglify()) için .pipe($.uglify({ mangle: false }))

Burada performans ile okunabilirlik karşılaştırması var. Adların yönetilmemesi (biraz) daha büyük bir derleme dosyasına (daha fazla ağ kaynağı) ve potansiyel olarak daha yavaş kod yürütülmesine neden olur (alıntı gerekir - BS olabilir). Öte yandan, aynı getClassNametutsaydım, her ES6 sınıfında statik ve örnek düzeyinde manuel olarak tanımlamam gerekirdi. Hayır teşekkürler!

Güncelleme

Yorumlardaki tartışmadan sonra, .namebu işlevleri tanımlamak lehine sözleşmeden kaçınmak iyi bir paradigma gibi görünüyor . Yalnızca birkaç satır kod alır ve kodunuzun tam olarak küçültülmesine ve genelleştirilmesine izin verir (kitaplıkta kullanılıyorsa). Bu yüzden sanırım fikrimi değiştiriyorum ve getClassNamederslerimi manuel olarak tanımlayacağım . Teşekkürler @estus! . Getter / Setters, özellikle istemci tabanlı bir uygulamada, doğrudan değişken erişime kıyasla genellikle iyi bir fikirdir.

class SomeClass {
  constructor() {}
  static getClassName(){ return 'SomeClass'; }
  getClassName(){ return SomeClass.getClassName(); }
}
var someClassInstance = new SomeClass();
someClassInstance.constructor.getClassName();      // === 'SomeClass' (static fn)
someClassInstance.getClassName();                  // === 'SomeClass' (instance fn)
SomeClass.getClassName()                           // === 'SomeClass' (static fn)

3
Mangling'i tamamen devre dışı bırakmak çok iyi bir fikir değildir, çünkü mangling minimizasyona çok katkıda bulunur. İlk olarak, istemci tarafı kodunda konuyu kullanmak çok iyi bir fikir değildir, ancak sınıflar reservedUglify seçeneğiyle yönetilmeye karşı korunabilir (regexp veya herhangi bir şekilde bir sınıf listesi elde edilebilir).
Estus Flask

Çok doğru. Daha büyük bir dosya boyutuna sahip olmak için bir değiş tokuş vardır. Görünüşe göre RegEx'i yalnızca belirli öğeler için karıştırmayı önlemek için kullanabilirsiniz . Ne demek "konuyu istemci tarafı kodunda kullanmak çok iyi bir fikir değil"? Bazı senaryolarda güvenlik riski oluşturur mu?
James L.

1
Hayır, zaten söylenenler. İstemci tarafı JS'nin küçültülmesi normaldir, bu nedenle bu kalıbın uygulama için sorunlara neden olacağı zaten bilinmektedir. Düzgün namedesen yerine sınıf dizesi tanımlayıcısı için fazladan bir kod satırı sadece bir kazan-kazan olabilir. Aynı şey Düğüme uygulanabilir, ancak daha az bir ölçüde (örn. Gizlenmiş Elektron uygulaması). Genel bir kural olarak name, sunucu koduna güvenirim , ancak tarayıcı koduna değil, ortak kütüphaneye güvenirdim .
Estus Flask

Tamam, bu yüzden cehennemde dolaşmak ve tam küçültmeye izin vermek için (can sıkıcı bir RegEx olmadan) 2 getClassName işlevini (statik & örnek) manuel olarak tanımlamanızı öneririz. Kütüphane ile ilgili bu nokta çok mantıklı. Çok mantıklı. Benim için, projem kendi kendine yapılan küçük bir Cordova uygulaması, bu yüzden bunlar gerçekten sorun değil. Bunun ötesinde herhangi bir şeyin bu konuların yükseldiğini görebiliyorum. Tartışma için teşekkürler! Gönderi üzerinde herhangi bir gelişme düşünebilirseniz, düzenlemekten çekinmeyin.
James L.

1
Evet, başlangıçta namesınıftan sınıf (hizmet, eklenti, vb.) Kullanan varlığın adını ayıklamak için DRYer kodunu kullandım, ancak sonunda bunu açıkça statik prop ( id, _name) ile çoğalttığını buldum sadece en sağlam yaklaşım. İyi bir alternatif, sınıf adını önemsememek, sınıfın kendisini (işlev nesnesi) bu sınıfa eşlenen bir varlık için tanımlayıcı olarak ve importgerektiğinde (Açısal 2 DI tarafından kullanılan bir yaklaşım) kullanmaktır.
Estus Flask

8

Sınıf adını doğrudan sınıftan alma

Önceki cevaplar someClassInstance.constructor.nameişe yaradığını açıkladı , ancak sınıf adını bir dizeye programlı olarak dönüştürmeniz gerekiyorsa ve bunun için bir örnek oluşturmak istemiyorsanız şunu unutmayın:

typeof YourClass === "function"

Ve her işlevin bir nameözelliği olduğundan, sınıf adınızla bir dize almanın başka bir güzel yolu da sadece şunu yapmaktır:

YourClass.name

Aşağıda, bunun neden faydalı olduğuna dair iyi bir örnek verilmiştir.

Web bileşenlerini yükleme

MDN belgelerinin bize öğrettiği gibi, bir web bileşenini şu şekilde yüklersiniz :

customElements.define("your-component", YourComponent);

Nereden YourComponentuzanan bir sınıf HTMLElement. Bileşen etiketinin kendisinden sonra bileşeninizin sınıfını adlandırmak iyi bir uygulama olarak kabul edildiğinden, tüm bileşenlerinizin kendilerini kaydetmek için kullanabileceği bir yardımcı işlev yazmak iyi olurdu. İşte bu fonksiyon:

function registerComponent(componentClass) {
    const componentName = upperCamelCaseToSnakeCase(componentClass.name);
    customElements.define(componentName, componentClass);
}

Tek yapmanız gereken:

registerComponent(YourComponent);

Bu da güzel çünkü bileşen etiketini kendiniz yazmaktan daha az hataya açık. Sarmak için bu upperCamelCaseToSnakeCase()işlev:

// converts `YourString` into `your-string`
function upperCamelCaseToSnakeCase(value) {
    return value
        // first char to lower case
        .replace(/^([A-Z])/, $1 => $1.toLowerCase())
        // following upper chars get preceded with a dash
        .replace(/([A-Z])/g, $1 => "-" + $1.toLowerCase());
}

Teşekkürler. Örnek istemci tarafıdır. Daha önce de belirtildiği gibi, tarayıcılarda işlev adlarının kullanılmasında bazı sorunlar vardır. Hemen hemen her tarayıcı kod parçasının küçültülmesi bekleniyor, ancak bu işlev adına dayanan kodu bozacaktır.
Estus Flask

Evet, tamamen haklısın. Küçültücü, bu yaklaşımın çalışması için sınıf adlarına dokunmayacak şekilde yapılandırılmalıdır.
Lucio Paiva

1

Babil transpilasyonu için (küçültmeden önce)

Babel ile kullanıyorsanız @babel/preset-env, sınıf tanımlarını işlevlere dönüştürmeden (özelliği kaldırır constructor) tutmak mümkündür

Bu yapılandırmayla bazı eski tarayıcı uyumluluğunu aşağıdakilere bırakabilirsiniz babel.config / babelrc:

{
  "presets": [
    ["@babel/preset-env", {"targets": {"browsers": ["> 2%"]}}]
  ]
}

Hakkında daha fazla bilgi targets: https://babeljs.io/docs/en/babel-preset-env#targets

Babil minimizasyonu için (transpilasyondan sonra)

Şu anda kolay bir çözüm yok gibi görünüyor ... Hariç tutulan istisnalara bakmamız gerekiyor.


Bunun küçültmeye nasıl yardımcı olacağını daha ayrıntılı açıklayabilir misiniz? herhangi bir hedefte olduğu class Foo {}gibi bir şeye küçültülecektir class a{}. FooKüçültülmüş kaynak kodunda hiçbir kelime olmayacak .
Estus Flask

Dürüst olmak gerekirse, bu konfigürasyonu kullanmama yardımcı olduğu için dokümantasyondan daha fazlasını kazmadım ... ECSY'yi babil aktarılan projeye kullanıyorum ve geçerli sınıf isimleri almak için bu paramayı gerektiriyor: github.com/MozillaReality/ecsy/issues/ 119
Değilse

Anlıyorum. Bu, ele aldığınız koda çok özeldir. Örneğin, ES modülleri ve ES6 için adlar korunabilir, çünkü export class Foo{}daha da verimli bir şekilde geliştirilemez, ancak bu başka yerlerde farklı olabilir, derleme sırasında belirli kod parçalarıyla ne olduğunu iyi bir fikre sahip olmadan tam olarak nasıl bilemeyiz. Herhangi bir şekilde, bu 2015'ten beri değişmedi. Bazı derleme yapılandırmaları ve kodları için her zaman mümkün oldu. Ve bu olasılığın hala uygulama mantığı için sınıf isimlerini kullanmak için çok kırılgan olduğunu söyleyebilirim.
Güvendiğiniz

1
Tamam koda bakarak neler olduğunu buldum. Benim çözümüm sınıfların işlevlere aktarılmasını düzeltir. Bu yüzden minyatürden önce yardımcı olur. Ama küçültme sorunu ile değil. Kazmaya devam etmeliyim, çünkü tüm constructor.name
kodlarımın
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.