Bagaimana cara mendapatkan kelas objek JavaScript?

728

Saya membuat objek JavaScript, tetapi bagaimana saya bisa menentukan kelas objek itu?

Saya ingin sesuatu yang mirip dengan .getClass()metode Java .

DNB5brims
sumber
6
misalnya, saya membuat Orang seperti ini: var p = Orang baru (); Saya memiliki Object Person yang disebut "p", bagaimana saya bisa menggunakan "p" untuk mendapatkan kembali nama Class: "Person".
DNB5brims
7
Duplikat
Casebash
Pembaruan: Pada ECMAScript 6, JavaScript masih belum memiliki classtipe. Itu memang memiliki classkata kunci dan classsintaks untuk membuat prototipe di mana metode dapat lebih mudah diakses super.
james_womack
Bagaimana dengan Object.className?
Paul Basenko
@ Paul-Basenko: "className" tidak akan memberi tahu Anda kelas objek, tetapi akan mengembalikan konten properti "class" elemen HTML, yang merujuk ke kelas CSS. Anda juga ingin menggunakan "classList" untuk mengelolanya dengan mudah, tetapi itu tidak terkait dengan pertanyaan OP.
Obsidian

Jawaban:

1009

Tidak ada padanan pasti untuk Java getClass()di JavaScript. Sebagian besar itu karena JavaScript menjadi bahasa berbasis prototipe , sebagai lawan dari Jawa menjadi bahasa berbasis kelas .

Bergantung pada apa yang Anda butuhkan getClass(), ada beberapa opsi dalam JavaScript:

Beberapa contoh:

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

Catatan: jika Anda mengkompilasi kode Anda dengan Uglify akan mengubah nama kelas non-global. Untuk mencegah hal ini, Uglify memiliki --mangleparam yang dapat Anda setel ke false menggunakan tegukan atau dengusan .

pangeran
sumber
6
Itu mungkin seharusnya func.prototype(ya, fungsi adalah objek, tetapi prototypeproperti hanya relevan pada objek fungsi).
Miles
5
Anda mungkin juga ingin menyebutkan instanceof/ isPrototypeOf()dan non-standar__proto__
Christoph
9
ES5 memiliki secara resmiObject.getPrototypeOf()
Christoph
22
Peringatan : jangan mengandalkan constructor.namejika kode Anda sedang diperkecil. Nama fungsi akan berubah secara sewenang-wenang.
igorsantos07
3
@ igorsantos07, setidaknya pada tahun 2019; hasil Google 5-10 teratas untuk "minifier javascript online" dikenali construction.namesebagai token untuk diabaikan / tidak diperkecil. Selain itu sebagian besar (jika tidak semua) perangkat lunak minifier memberikan aturan pengecualian.
gagak vulcan
297
obj.constructor.name

adalah metode yang dapat diandalkan di peramban modern. Function.namesecara resmi ditambahkan ke standar dalam ES6, menjadikannya cara yang sesuai standar untuk mendapatkan "kelas" objek JavaScript sebagai string. Jika objek dipakai var obj = new MyClass(), itu akan mengembalikan "MyClass".

Ini akan mengembalikan "Nomor" untuk angka, "Array" untuk array dan "Fungsi" untuk fungsi, dll. Umumnya berperilaku seperti yang diharapkan. Satu-satunya kasus di mana ia gagal adalah jika suatu objek dibuat tanpa prototipe, melalui Object.create( null ), atau objek itu instantiated dari fungsi (tanpa nama) yang didefinisikan secara anonim.

Perhatikan juga bahwa jika Anda mengecilkan kode Anda, tidak aman untuk membandingkannya dengan string tipe hard-coded. Misalnya bukannya memeriksa jika obj.constructor.name == "MyType", bukannya memeriksa obj.constructor.name == MyType.name. Atau hanya membandingkan konstruktor sendiri, namun ini tidak akan bekerja melintasi batas DOM karena ada contoh berbeda dari fungsi konstruktor pada setiap DOM, sehingga melakukan perbandingan objek pada konstruktor mereka tidak akan berfungsi.

devios1
sumber
11
Function.namebelum (belum) menjadi bagian dari standar JavaScript. Saat ini didukung di Chrome dan Firefox, tetapi tidak di IE (10).
Halcyon
13
obj.constructor.namehanya berfungsi untuk fungsi bernama . Yaitu, jika saya mendefinisikan var Foo = function() {}, maka untuk var foo = new Foo(), foo.constructor.nameakan memberi Anda string kosong.
KFL
29
Peringatan : jangan mengandalkan constructor.namejika kode Anda sedang diperkecil. Nama fungsi akan berubah secara sewenang-wenang.
igorsantos07
1
Function.name adalah bagian dari ES6, lihat developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Janus Troelsen
1
@adalbertpl Itu ada hubungannya dengan prototipe chaining secara manual, sebelum ES6. Adalah baik untuk mengetahui constructor.nameberperilaku seperti yang diharapkan dengan dukungan kelas baru di ES6.
devios1
29

Fungsi ini mengembalikan "Undefined"nilai yang tidak ditentukan dan "Null"untuk null.
Untuk semua nilai lainnya, CLASSNAME-part diekstrak dari [object CLASSNAME], yang merupakan hasil dari menggunakan 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...
Eli Gray
sumber
Object.prototype.getClass = function () {menggunakan 'this' bukannya obj akan menyenangkan
SparK
2
tentu saja nol dan tidak terdefinisi tidak akan dapat diperiksa karena hanya Object yang memiliki metode getClass
SparK
8
Ini hanya berfungsi pada objek asli. Jika Anda memiliki semacam warisan, Anda akan selalu mendapatkannya "Object".
Halcyon
Ya, baris terakhir dari fungsi seharusnya return obj.constructor.name. Itu memberikan hasil yang sama, plus juga menangani benda-benda non asli.
Steve Bennett
18

Untuk mendapatkan "pseudo class", Anda bisa mendapatkan fungsi konstruktor, oleh

obj.constructor

dengan asumsi constructordiatur dengan benar ketika Anda melakukan warisan - yang oleh sesuatu seperti:

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

dan dua baris ini, bersama dengan:

var woofie = new Dog()

akan woofie.constructormenunjukkan Dog. Catatan itu Dogadalah fungsi konstruktor, dan merupakan Functionobjek. Tapi kamu bisa melakukannya if (woofie.constructor === Dog) { ... }.

Jika Anda ingin mendapatkan nama kelas sebagai string, saya menemukan berikut ini berfungsi dengan baik:

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;
}

Ia sampai ke fungsi konstruktor, mengubahnya menjadi string, dan mengekstrak nama fungsi konstruktor.

Catatan yang obj.constructor.namebisa bekerja dengan baik, tetapi itu bukan standar. Ada di Chrome dan Firefox, tetapi tidak di IE, termasuk IE 9 atau IE 10 RTM.

nonopolaritas
sumber
13

Anda bisa mendapatkan referensi ke fungsi konstruktor yang membuat objek dengan menggunakan properti konstruktor :

function MyObject(){
}

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

Jika Anda perlu mengonfirmasi jenis objek saat runtime Anda dapat menggunakan instanceof operator:

obj instanceof MyObject // true
CMS
sumber
bukankah itu mengembalikan fungsi konstruktor itu sendiri, seperti, Anda dapat memanggilnya lagi dan membuat objek baru dari jenis itu?
SparK
1
@SparK Ya, meskipun Anda masih bisa menggunakan ini untuk perbandingan selama Anda berada di DOM yang sama (Anda membandingkan objek fungsi). Namun itu adalah praktik yang jauh lebih baik untuk mengubah konstruktor menjadi string dan membandingkannya, khususnya karena ia bekerja melintasi batas DOM saat menggunakan iframe.
devios1
Jawaban ini mengembalikan "kelas" (atau setidaknya pegangan objek yang dapat digunakan untuk membuat turunan kelas - yang sama dengan "kelas"). Jawaban di atas semua string yang dikembalikan yang tidak sama dengan "objek kelas" (seolah-olah).
Mike P.
8

Sesuai dengan catatan kompatibilitas ke belakang yang tidak terputus, ECMAScript 6, JavaScript masih tidak memiliki classtipe (walaupun tidak semua orang mengerti ini). Itu memang memiliki classkata kunci sebagai bagian dari classsintaks untuk membuat prototipe — tetapi masih tidak ada yang disebut kelas . JavaScript tidak sekarang dan tidak pernah menjadi bahasa OOP klasik . Berbicara tentang JS dalam hal kelas hanya menyesatkan atau pertanda belum mendapatkan warisan prototipikal (hanya membuatnya nyata).

Itu berarti this.constructormasih cara yang bagus untuk mendapatkan referensi ke constructorfungsi. Dan this.constructor.prototypeadalah cara untuk mengakses prototipe itu sendiri. Karena ini bukan Java, ini bukan kelas. Ini adalah objek prototipe tempat instantiasi Anda berasal. Berikut ini adalah contoh menggunakan gula sintaksis ES6 untuk membuat rantai prototipe:

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)

Inilah yang dihasilkan oleh keluaran 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'

Itu dia! Pada 2016, ada classkata kunci dalam JavaScript, tetapi masih tidak ada tipe kelas. this.constructoradalah cara terbaik untuk mendapatkan fungsi konstruktor, this.constructor.prototypecara terbaik untuk mendapatkan akses ke prototipe itu sendiri.

james_womack
sumber
7

Saya punya situasi untuk bekerja generik sekarang dan menggunakan ini:

class Test {
  // your class definition
}

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

console.log(nameByType(Test));

Itulah satu-satunya cara yang saya temukan untuk mendapatkan nama kelas berdasarkan jenis input jika Anda tidak memiliki turunan objek.

(ditulis dalam ES2017)

notasi titik juga berfungsi dengan baik

console.log(Test.prototype.constructor.name); // returns "Test" 
mtizziani
sumber
Ah inilah yang saya cari. Jika tidak dipakai, Anda harus menggunakan 'prototipe' untuk mendapatkan nama kelas. Terima kasih banyak!
Artokun
4

Untuk Javascript Classes di ES6 bisa Anda gunakan object.constructor. Pada kelas contoh di bawah ini getClass()metode mengembalikan kelas ES6 seperti yang Anda harapkan:

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!"

Jika Anda instantiate kelas dari getClassmetode pastikan Anda membungkusnya dalam tanda kurung misalnyaruffles = new ( fluffy.getClass() )( args... );

Hugheth
sumber
3

Saya menemukan object.constructor.toString()kembali [object objectClass]di IE, daripada function objectClass () {}kembali di chome. Jadi, saya pikir kode di http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects mungkin tidak berfungsi dengan baik di IE. Dan saya memperbaiki kodenya sebagai berikut:

kode:

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; 
    };
zzy7186
sumber
2

Dalam javascript, tidak ada kelas, tapi saya pikir Anda menginginkan nama konstruktor dan obj.constructor.toString()akan memberi tahu Anda apa yang Anda butuhkan.

Jikhan
sumber
1
Ini akan mengembalikan seluruh definisi fungsi konstruktor sebagai string. Yang benar-benar Anda inginkan adalah .name.
devios1
4
tetapi .nametidak didefinisikan bahkan pada IE 9
nonopolaritas
1

Setuju dengan dfa, itu sebabnya saya menganggap prototye sebagai kelas ketika tidak ada kelas bernama yang ditemukan

Ini adalah fungsi yang ditingkatkan dari yang diposting oleh Eli Gray, agar sesuai dengan cara pikiranku

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;
}
Antkhan
sumber
1

Jika Anda tidak hanya perlu MENDAPATKAN kelas tetapi juga MEMPERPANJANG dari hanya memiliki sebuah instance, tulis:

mari kita miliki

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

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

jadi untuk memperpanjang A memiliki instance hanya gunakan:

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

console.log(a2.name)//'hello a2'
AlexNikonov
sumber
0

Saya sarankan menggunakan 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'
Sapphire_Brick
sumber
0

Berikut ini adalah implementasi dari getClass()dangetInstance()

Anda bisa mendapatkan referensi untuk menggunakan kelas Object this.constructor.

Dari konteks contoh:

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

Dari konteks statis:

function A() {};

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

A.getInstance() {
  return new this;
}
Bruno Finger
sumber
2
Kenapa tidak adil this.constructor?
Solomon Ucko
1
Saya tidak tahu, tetapi jika lebih baik, Anda pasti dapat mengedit jawaban untuk memperbaikinya karena Anda merasa lebih baik, setelah semua ini adalah sebuah komunitas.
Bruno Finger
0

Anda juga dapat melakukan hal seperti ini

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

Ini akan memberi tahu Anda apakah inputnya kelas atau tidak

iRohitBhatia
sumber
-2

Javascript adalah bahasa tanpa kelas: tidak ada kelas yang mendefinisikan perilaku kelas secara statis seperti di Jawa. JavaScript menggunakan prototipe sebagai ganti kelas untuk mendefinisikan properti objek, termasuk metode, dan pewarisan. Dimungkinkan untuk mensimulasikan banyak fitur berbasis kelas dengan prototipe dalam JavaScript.

dfa
sumber
12
Saya sering mengatakan bahwa Javascript tidak memiliki kelas :)
Steven
4
Pembaruan: Pada ECMAScript 6, JavaScript masih belum memiliki classtipe. Itu memang memiliki classkata kunci dan classsintaks untuk membuat prototipe di mana metode dapat lebih mudah diakses super.
james_womack
-3

Pertanyaan sepertinya sudah dijawab tetapi OP ingin mengakses kelas dan objek, seperti yang kita lakukan di Jawa dan jawaban yang dipilih tidak cukup (imho).

Dengan penjelasan berikut, kita bisa mendapatkan kelas objek (sebenarnya disebut prototipe dalam javascript).

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

Anda dapat menambahkan properti seperti ini:

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

Tetapi .lastproperti hanya akan tersedia untuk arrobjek yang dibuat dari prototipe Array. Jadi, agar .lastproperti tersedia untuk semua objek yang dibuat dari prototipe Array, kita harus mendefinisikan .lastproperti untuk prototipe Array:

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

Masalahnya di sini adalah, Anda harus tahu jenis objek (prototipe) mana variabel ' arr' dan ' arr2' milik! Dengan kata lain, jika Anda tidak tahu tipe kelas (prototipe) dari objek ' arr', maka Anda tidak akan dapat mendefinisikan properti untuk mereka. Dalam contoh di atas, kita tahu arr adalah turunan dari objek Array, itu sebabnya kami menggunakan Array.prototype untuk mendefinisikan properti untuk Array. Tetapi bagaimana jika kita tidak tahu kelas (prototipe) dari ' arr'?

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

Seperti yang Anda lihat, tanpa mengetahui bahwa ' arr' adalah Array, kita dapat menambahkan properti baru hanya dengan merujuk kelas ' arr' dengan menggunakan ' arr.__proto__'.

Kami mengakses prototipe ' arr' tanpa mengetahui bahwa itu adalah contoh dari Array dan saya pikir itulah yang ditanyakan OP.

Ramazan Polat
sumber
The __proto__properti sudah ditinggalkan, dan memiliki hampir tidak ada keuntungan atas prototypeproperti.
Sapphire_Brick