Bir JavaScript nesnesinin sınıfı nasıl edinilir?


728

Bir JavaScript nesnesi oluşturdum, ancak bu nesnenin sınıfını nasıl belirleyebilirim?

Java'nın .getClass()yöntemine benzer bir şey istiyorum .


6
örneğin, böyle bir kişiyi yapıyorum: var p = new Person (); "P" adlı bir kişi nesnesi var, "p" sınıf adını geri almak için nasıl kullanabilirim: "kişi".
DNB5brims


Güncelleme: ECMAScript 6'dan itibaren JavaScript'in hala bir classtürü yok. Bu does bir var classanahtar kelime ve classyöntemler can daha kolay erişim prototip oluşturmak için sözdizimi super.
james_womack

Object.className nedir?
Paul Basenko

@ Paul-Basenko: "className" nesnenin sınıfını size söylemez, ancak HTML öğesinin CSS sınıflarını ifade eden "class" özelliğinin içeriğini döndürür. Ayrıca kolayca yönetmek için "classList" kullanmak istersiniz, ancak bu OP'nin sorusuyla ilgili değildir.
Obsidiyen

Yanıtlar:


1009

getClass()JavaScript'teki Java'ların tam karşılığı yoktur . Çoğu zaman JavaScript'in prototip tabanlı bir dil olması , Java'nın sınıf tabanlı bir dil olması nedeniyle .

İhtiyacınız getClass()olan şeye bağlı olarak , JavaScript'te birkaç seçenek vardır:

Birkaç örnek:

function Foo() {}
var foo = new Foo();

typeof Foo;             // == "function"
typeof foo;             // == "object"

foo instanceof Foo;     // == true
foo.constructor.name;   // == "Foo"
Foo.name                // == "Foo"    

Foo.prototype.isPrototypeOf(foo);   // == true

Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21);            // == 42

Not: Kodunuzu Uglify ile derliyorsanız, genel olmayan sınıf adlarını değiştirir. Bunu önlemek için, çirkinleştirmek bir sahiptir --manglekullanmakta olduğu false olarak ayarlanır ki param yudum veya hırıltı .


6
Bu muhtemelen olmalıdır func.prototype(evet, işlevler nesnedir, ancak prototypeözellik yalnızca işlev nesneleriyle ilgilidir).
Miles

5
Ayrıca bahsetmek isteyebilirsiniz instanceof/ isPrototypeOf()ve standart dışı__proto__
Christoph

9
ES5 ek olarakObject.getPrototypeOf()
Christoph

22
Uyarı : constructor.namekodunuz küçültülmüşse güvenmeyin . İşlev adı isteğe bağlı olarak değişecektir.
igorsantos07

3
@ igorsantos07, en azından 2019'da; "çevrimiçi javascript minifier" için en iyi 5-10 google sonuçları, construction.nameyok sayılacak / küçültülmeyecek bir simge olarak algılanır . Ayrıca çoğu (hepsi olmasa da) madencilik yazılımı istisna kuralları sağlar.
vulcan raven

296
obj.constructor.name

modern tarayıcılarda güvenilir bir yöntemdir. Function.nameresmi olarak ES6'daki standarda eklendi, bu da bir JavaScript nesnesinin "sınıfını" dize olarak almanın standartlara uygun bir araç olmasını sağladı. Nesne ile başlatılırsa var obj = new MyClass(), "Sınıfım" döndürür.

Sayılar için "Sayı", diziler için "Dizi" ve işlevler için "İşlev" vb. Döndürür. Genellikle beklendiği gibi davranır. Başarısız olduğu tek durum, bir nesnenin prototip olmadan oluşturulduğu, üzerinden Object.create( null )veya nesnenin anonim olarak tanımlanmış (adsız) işlevden başlatılmasıdır.

Ayrıca, kodunuzu küçültüyorsanız, sabit kodlu tür dizelerle karşılaştırmanın güvenli olmadığını unutmayın. Örneğin, kontrol etmek yerine, kontrol obj.constructor.name == "MyType"edin obj.constructor.name == MyType.name. Ya da sadece kurucuları karşılaştırın, ancak her DOM'da yapıcı işlevinin farklı örnekleri olduğundan DOM sınırlarında çalışmaz, böylece kurucularında nesne karşılaştırması yapmak işe yaramaz.


11
Function.nameJavaScript standardının (henüz) bir parçası değildir. Şu anda Chrome ve Firefox'ta destekleniyor, ancak IE'de desteklenmiyor (10).
Halcyon

13
obj.constructor.nameyalnızca adlandırılmış işlevler için çalışır . Yani, eğer tanımlarsam var Foo = function() {}, o zaman var foo = new Foo(), foo.constructor.namesize boş bir dize verecektir.
KFL

29
Uyarı : constructor.namekodunuz küçültülmüşse güvenmeyin . İşlev adı isteğe bağlı olarak değişecektir.
igorsantos07

1
Function.name ES6'nın bir parçasıdır, bkz. Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Janus Troelsen

1
@adalbertpl ES6'dan önce manuel olarak zincirleme prototiplerle ilgisi vardı. constructor.nameES6'daki yeni sınıf desteğiyle beklendiği gibi davrandığını bilmek güzel.
devios1

29

Bu işlev "Undefined"tanımsız değerler ve "Null"null için döndürür .
Diğer tüm değerler için, CLASSNAME-part ayıklanır [object CLASSNAME], ki bu kullanım sonucudur Object.prototype.toString.call(value).

function getClass(obj) {
  if (typeof obj === "undefined") return "Undefined";
  if (obj === null) return "Null";
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}

getClass("")   === "String";
getClass(true) === "Boolean";
getClass(0)    === "Number";
getClass([])   === "Array";
getClass({})   === "Object";
getClass(null) === "Null";
// etc...

Object.prototype.getClass = function () {obj yerine 'this' kullanmak güzel olurdu
SparK

2
Tabii ki null ve undefined kontrol edilemez çünkü yalnızca Object getClass yöntemine sahip olacaktır
SparK

8
Bu yalnızca yerel nesneler üzerinde çalışır. Eğer bir çeşit mirasınız varsa her zaman alırsınız "Object".
Halcyon

Evet, fonksiyonun son satırı sadece olmalı return obj.constructor.name. Bu aynı sonuçları verir, ayrıca yerel olmayan nesneleri de işler.
Steve Bennett

18

"Sözde sınıf" almak için yapıcı işlevini,

obj.constructor

constructormiras yaptığınızda doğru ayarlandığını varsayarsak - ki bunun gibi bir şeydir:

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

ve bu iki çizgi ile birlikte:

var woofie = new Dog()

yapacak woofie.constructorgelin Dog. Not Dogyapıcı fonksiyonudur, ve a, Functionnesne. Ama yapabilirsin if (woofie.constructor === Dog) { ... }.

Sınıf adını bir dize olarak almak istiyorsanız, aşağıdaki iyi çalışıyor bulundu:

http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects

function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2) {
            return arr[1];
        }
    }

    return undefined;
}

Yapıcı işlevine ulaşır, dizeye dönüştürür ve yapıcı işlevinin adını ayıklar.

Bunun iyi obj.constructor.nameçalışabileceğini unutmayın , ancak standart değildir. Chrome ve Firefox'ta, ancak IE 9 veya IE 10 RTM dahil olmak üzere IE'de değil.


13

Constructor özelliğini kullanarak nesneyi oluşturan yapıcı işlevine bir başvuru alabilirsiniz :

function MyObject(){
}

var obj = new MyObject();
obj.constructor; // MyObject

Çalışma zamanında bir nesnenin türünü onaylamanız gerekiyorsa instanceof operatörünü kullanabilirsiniz :

obj instanceof MyObject // true

yapıcı işlevinin kendisini döndürmez mi, örneğin, tekrar çağırabilir ve bu türde yeni bir nesne oluşturabilirsiniz?
SparK

1
@SparK Evet, yine de bunu aynı DOM'da olduğunuz sürece bir karşılaştırma için kullanabilirsiniz (işlev nesnelerini karşılaştırıyorsunuz). Bununla birlikte, özellikle iframe'leri kullanırken DOM sınırlarında çalıştığı için kurucuyu bir dizeye dönüştürmek ve karşılaştırmak çok daha iyi bir uygulamadır.
devios1

Bu yanıt "sınıfı" döndürür (veya en azından sınıfın bir örneğini oluşturmak için kullanılabilen - "sınıf" ile aynı olan nesneyi tanıtır). Yukarıdaki, "sınıf nesnesi" ile aynı olmayan (olduğu gibi) döndürülen tüm dizeleri yanıtlar.
Mike P.

8

ECMAScript 6'nın geriye dönük uyumluluğun kesintisiz kaydına uygun olarak, JavaScript'in hala bir classtürü yoktur (ancak herkes bunu anlamaz). Bu does bir var classonun bir parçası olarak anahtar kelime classprototipleri-ama oluşturmak için sözdizimi hala sınıf denilen hiçbir şey . JavaScript artık değil ve hiçbir zaman klasik bir OOP dili olmamıştır . Sınıf açısından JS'den bahsetmek sadece yanıltıcıdır ya da henüz prototipik kalıtımdan ibaret değildir (sadece gerçek tutmak).

Bu this.constructor, constructorişleve referans almanın harika bir yolu olduğu anlamına gelir . Ve this.constructor.prototypeprototipin kendisine erişmenin yolu budur. Bu Java olmadığı için bir sınıf değil. Örneğinizin örneklendiği prototip nesnedir. Prototip zinciri oluşturmak için ES6 sözdizimsel şekeri kullanan bir örnek:

class Foo {
  get foo () {
    console.info(this.constructor, this.constructor.name)
    return 'foo'
  }
}

class Bar extends Foo {
  get foo () {
    console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
    console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))

    return `${super.foo} + bar`
  }
}

const bar = new Bar()
console.dir(bar.foo)

Bu çıktı kullanarak babel-node:

> $ babel-node ./foo.js                                                                                                                    6.2.0 master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'

İşte aldın! 2016'da classJavaScript'te bir anahtar kelime var , ancak yine de sınıf türü yok. this.constructoryapıcı işlevini this.constructor.prototypeelde etmenin en iyi yoludur, prototipin kendisine erişmenin en iyi yoludur.


7

şimdi genel çalışmak için bir durum vardı ve bu kullanılır:

class Test {
  // your class definition
}

nameByType = function(type){
  return type.prototype["constructor"]["name"];
};

console.log(nameByType(Test));

bir nesne örneği yoksa bu tür girdi girdi tarafından sınıf adını almak için buldum tek yol.

(ES2017 ile yazılmış)

nokta gösterimi de iyi çalışıyor

console.log(Test.prototype.constructor.name); // returns "Test" 

Ah aradığım şey bu. Örneklenmemişse, sınıf adını almak için 'prototip' kullanmanız gerekir. Bir ton teşekkürler!
Artokun

4

ES6'daki Javascript Sınıfları için kullanabilirsiniz object.constructor. Aşağıdaki örnek sınıfta getClass()yöntem ES6 sınıfını beklediğiniz gibi döndürür:

var Cat = class {

    meow() {

        console.log("meow!");

    }

    getClass() {

        return this.constructor;

    }

}

var fluffy = new Cat();

...

var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();

ruffles.meow();    // "meow!"

Sınıfı getClassyöntemden başlatırsanız, köşeli parantez içine aldığınızdan emin olun.ruffles = new ( fluffy.getClass() )( args... );


3

Chome iade yerine IE, object.constructor.toString()dönüş bulabilirsiniz . Bu nedenle, http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects kodunun IE'de iyi çalışmayabileceğini düşünüyorum ve kodu aşağıdaki gibi düzelttim:[object objectClass]function objectClass () {}

kod:

var getObjectClass = function (obj) {
        if (obj && obj.constructor && obj.constructor.toString()) {

                /*
                 *  for browsers which have name property in the constructor
                 *  of the object,such as chrome 
                 */
                if(obj.constructor.name) {
                    return obj.constructor.name;
                }
                var str = obj.constructor.toString();
                /*
                 * executed if the return of object.constructor.toString() is 
                 * "[object objectClass]"
                 */

                if(str.charAt(0) == '[')
                {
                        var arr = str.match(/\[\w+\s*(\w+)\]/);
                } else {
                        /*
                         * executed if the return of object.constructor.toString() is 
                         * "function objectClass () {}"
                         * for IE Firefox
                         */
                        var arr = str.match(/function\s*(\w+)/);
                }
                if (arr && arr.length == 2) {
                            return arr[1];
                        }
          }
          return undefined; 
    };

2

Javascript'te, hiçbir sınıf yok, ama yapıcı adını istediğinizi ve obj.constructor.toString()size neye ihtiyacınız olduğunu söyleyeceğini düşünüyorum.


1
Bu, yapıcı işlevinin tüm tanımını dize olarak döndürür. Gerçekten istediğin şey .name.
devios1

4
ancak .nameIE 9'da bile tanımlanmadı
nonopolarite

1

Dfa ile katılıyorum, bu yüzden adlandırılmış bir sınıf bulunamadı zaman prototye sınıf olarak kabul

İşte Eli Gray tarafından yayınlanan, zihin şeklimize uyacak bir yükseltilmiş işlevi

function what(obj){
    if(typeof(obj)==="undefined")return "undefined";
    if(obj===null)return "Null";
    var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
    if(res==="Object"){
        res = obj.constructor.name;
        if(typeof(res)!='string' || res.length==0){
            if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
            if(obj instanceof Array)return "Array";// Array prototype is very sneaky
            return "Object";
        }
    }
    return res;
}

1

Sadece GET sınıfına değil, aynı zamanda sadece bir örneğe sahip olmasını EXTEND etmeniz gerekiyorsa, şunu yazın:

Hadi sahip olalım

 class A{ 
   constructor(name){ 
     this.name = name
   }
 };

 const a1 = new A('hello a1');

böylece A örneğini yalnızca aşağıdaki örneği kullanarak genişletmek için:

const a2 = new ((Object.getPrototypeOf(a)).constructor())('hello a2')
// the analog of const a2 = new A()

console.log(a2.name)//'hello a2'

0

Şunu kullanmanızı öneririm Object.prototype.constructor.name:

Object.defineProperty(Object.prototype, "getClass", {
    value: function() {
      return this.constructor.name;
    }
});

var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'

var y = new Error("");
console.log(y.getClass()); // `Error'

0

İşte getClass()vegetInstance()

Kullanarak bir Object sınıfı için bir referans alabilirsiniz this.constructor.

Bir örnek bağlamından:

function A() {
  this.getClass = function() {
    return this.constructor;
  }

  this.getNewInstance = function() {
    return new this.constructor;
  }
}

var a = new A();
console.log(a.getClass());  //  function A { // etc... }

// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true

Statik bağlamdan:

function A() {};

A.getClass = function() {
  return this;
}

A.getInstance() {
  return new this;
}

2
Neden sadece this.constructor?
Solomon Ucko

1
Bilmiyorum, ama eğer daha iyiyse, cevabı daha iyi bulduğunuz gibi geliştirmek için kesinlikle düzenleyebilirsiniz, sonuçta bu bir topluluktur.
Bruno Finger

0

Bunun gibi bir şey de yapabilirsiniz

 class Hello {
     constructor(){
     }
    }
    
      function isClass (func) {
        return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
    }
    
   console.log(isClass(Hello))

Bu, girişin sınıf olup olmadığını söyleyecektir


-2

Javascript sınıfsız bir dildir: Java'da olduğu gibi bir sınıfın davranışını statik olarak tanımlayan hiçbir sınıf yoktur. JavaScript, yöntemler ve miras dahil nesne özelliklerini tanımlamak için sınıflar yerine prototipler kullanır. JavaScript'te prototiplerle sınıf tabanlı birçok özelliği simüle etmek mümkündür.


12
Sık sık Javascript'in sınıftan yoksun olduğunu söyledim :)
Steven

4
Güncelleme: ECMAScript 6'dan itibaren JavaScript'in hala bir classtürü yok. Bu does bir var classanahtar kelime ve classyöntemler can daha kolay erişim prototip oluşturmak için sözdizimi super.
james_womack

-3

Soru zaten cevaplanmış gibi görünüyor, ancak OP, Java'da yaptığımız gibi ve seçilen cevap yeterli değil (imho).

Aşağıdaki açıklama ile, bir nesnenin sınıfını alabiliriz (aslında javascript'te prototip olarak adlandırılır).

var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');

Bunun gibi bir mülk ekleyebilirsiniz:

Object.defineProperty(arr,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue

Ancak .lastözellik yalnızca arrArray prototipinden başlatılan nesne için kullanılabilir olacaktır . Bu nedenle, .lastözelliğin Array prototipinden başlatılmış tüm nesneler için kullanılabilir olması için, Array prototipinin .lastözelliğini tanımlamamız gerekir :

Object.defineProperty(Array.prototype,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Buradaki problem, ' arr' ve ' arr2' değişkenlerinin hangi nesne türüne (prototip) ait olduğunu bilmeniz gerekir! Başka bir deyişle, ' arr' nesnesinin sınıf türünü (prototip) bilmiyorsanız , onlar için bir özellik tanımlayamazsınız. Yukarıdaki örnekte, arr'ın Array nesnesinin bir örneği olduğunu biliyoruz, bu yüzden Array için bir özellik tanımlamak için Array.prototype kullandık. Ama ya ' arr' sınıfını (prototip) bilmeseydik ?

Object.defineProperty(arr.__proto__,'last2', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Gördüğünüz gibi, ' arr' bir Array olduğunu bilmeden, sadece ' arr' sınıfını kullanarak ' arr.__proto__' kullanarak yeni bir özellik ekleyebiliriz .

Array'ın arrbir örneği olduğunu bilmeden ' ' prototipine eriştik ve bence OP bunu sordu.


__proto__Mülkiyet kaldırılmış ve üzerinde neredeyse hiçbir avantajı vardır prototypemülkiyet.
Sapphire_Brick
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.