Pertanyaan Bagaimana cara mendapatkan nama tipe objek dalam JavaScript?


Apakah ada JavaScript yang setara dengan Java class.getName()?


1051
2017-12-01 22:06


asal


Jawaban:


Apakah ada JavaScript yang setara dengan Java class.getName()?

Tidak.

ES2015 Pembaruan: nama dari class Foo {} aku s Foo.name. Nama dari thingkelas, terlepas dari thingtipe, adalah thing.constructor.name. Konstruktor bawaan dalam lingkungan ES2015 memiliki yang benar name milik; contohnya (2).constructor.name aku s "Number".


Tapi di sini ada berbagai hacks yang semuanya jatuh dalam satu atau lain cara:

Berikut ini adalah peretasan yang akan melakukan apa yang Anda perlukan - sadar bahwa itu memodifikasi prototipe Object, sesuatu yang disukai orang (biasanya karena alasan yang bagus)

Object.prototype.getName = function() { 
   var funcNameRegex = /function (.{1,})\(/;
   var results = (funcNameRegex).exec((this).constructor.toString());
   return (results && results.length > 1) ? results[1] : "";
};

Sekarang, semua objek Anda akan memiliki fungsi, getName(), yang akan mengembalikan nama konstruktor sebagai string. Saya telah menguji ini FF3 dan IE7Saya tidak bisa berbicara untuk implementasi lain.

Jika Anda tidak ingin melakukan itu, berikut adalah diskusi tentang berbagai cara menentukan jenis dalam JavaScript ...


Saya baru-baru ini memperbarui ini menjadi sedikit lebih lengkap, meskipun hampir tidak. Koreksi diterima ...

Menggunakan constructor milik...

Setiap object memiliki nilai untuk itu constructor properti, tetapi tergantung pada bagaimana itu object dibangun serta apa yang ingin Anda lakukan dengan nilai itu, mungkin atau mungkin tidak berguna.

Secara umum, Anda dapat menggunakan constructor properti untuk menguji jenis objek seperti:

var myArray = [1,2,3];
(myArray.constructor == Array); // true

Jadi, itu berfungsi cukup baik untuk sebagian besar kebutuhan. Itu mengatakan ...

Peringatan

Tidak akan berhasil SAMA SEKALI dalam banyak kasus

Pola ini, meskipun rusak, cukup umum:

function Thingy() {
}
Thingy.prototype = {
    method1: function() {
    },
    method2: function() {
    }
};

Objects dibangun melalui new Thingy akan memiliki constructor properti yang menunjuk ke Objecttidak Thingy. Jadi kita jatuh tepat di awal; Anda tidak bisa percaya constructor dalam basis kode yang tidak Anda kendalikan.

Warisan ganda

Contoh di mana tidak begitu jelas adalah menggunakan multiple inheritance:

function a() { this.foo = 1;}
function b() { this.bar = 2; }
b.prototype = new a(); // b inherits from a

Hal-hal sekarang tidak bekerja seperti yang Anda harapkan mereka untuk:

var f = new b(); // instantiate a new object with the b constructor
(f.constructor == b); // false
(f.constructor == a); // true

Jadi, Anda mungkin mendapatkan hasil yang tidak terduga jika object pengujian Anda memiliki perbedaan object ditetapkan sebagai miliknya prototype. Ada banyak cara di luar lingkup diskusi ini.

Ada kegunaan lain untuk constructor properti, beberapa di antaranya menarik, yang lain tidak begitu banyak; untuk saat ini kami tidak akan menyelidiki penggunaan tersebut karena tidak relevan dengan diskusi ini.

Tidak akan berfungsi lintas-bingkai dan lintas-jendela

Menggunakan .constructor untuk pemeriksaan jenis akan pecah ketika Anda ingin memeriksa jenis objek yang berasal dari berbagai window objek, mengatakan bahwa iframe atau jendela munculan. Ini karena ada versi yang berbeda dari setiap tipe inti constructor di setiap `jendela ', yaitu

iframe.contentWindow.Array === Array // false

Menggunakan instanceof operator...

Itu instanceof operator adalah cara pengujian yang bersih object ketik juga, tetapi memiliki masalah potensial sendiri, sama seperti constructor milik.

var myArray = [1,2,3];
(myArray instanceof Array); // true
(myArray instanceof Object); // true

Tapi instanceof gagal bekerja untuk nilai literal (karena literal tidak Objects)

3 instanceof Number // false
'abc' instanceof String // false
true instanceof Boolean // false

Literal perlu dibungkus dalam Object agar instanceofuntuk bekerja, misalnya

new Number(3) instanceof Number // true

Itu .constructor cek berfungsi dengan baik untuk literal karena . pemanggilan metode secara implisit membungkus literal dalam jenis objek masing-masing

3..constructor === Number // true
'abc'.constructor === String // true
true.constructor === Boolean // true

Mengapa dua titik untuk 3? Karena Javascript menafsirkan titik pertama sebagai titik desimal;)

Tidak akan berfungsi lintas-bingkai dan lintas-jendela

instanceof juga tidak akan berfungsi di berbagai jendela, untuk alasan yang sama seperti constructor pemeriksaan properti.


Menggunakan name milik dari constructor milik...

Tidak bekerja SAMA SEKALI dalam banyak kasus

Sekali lagi, lihat di atas; itu cukup umum untuk constructor benar-benar salah dan tidak berguna.

TIDAK bekerja di <IE9

Menggunakan myObjectInstance.constructor.name akan memberi Anda string yang berisi nama constructor fungsi yang digunakan, tetapi tunduk pada peringatan tentang constructor properti yang disebutkan sebelumnya.

Untuk IE9 dan di atas, Anda bisa monkey-patch dalam dukungan:

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s+([^\s(]+)\s*\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1] : "";
        },
        set: function(value) {}
    });
}

Versi terbaru dari artikel yang dipermasalahkan. Ini ditambahkan 3 bulan setelah artikel itu diterbitkan, ini adalah versi yang direkomendasikan untuk digunakan oleh penulis artikel Matthew Scharley. Perubahan ini terinspirasi oleh komentar yang menunjukkan potensi jebakan di kode sebelumnya.

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s([^(]{1,})\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1].trim() : "";
        },
        set: function(value) {}
    });
}

Menggunakan Object.prototype.toString

Ternyata, seperti detail posting ini, Kamu dapat memakai Object.prototype.toString - Implementasi tingkat rendah dan umum toString - untuk mendapatkan tipe untuk semua tipe bawaan

Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call(/abc/) // [object RegExp]
Object.prototype.toString.call([1,2,3]) // [object Array]

Seseorang dapat menulis fungsi pembantu singkat seperti

function type(obj){
    return Object.prototype.toString.call(obj).slice(8, -1);
}

untuk menghapus cruft dan mendapatkan hanya nama jenis

type('abc') // String

Namun, itu akan kembali Object untuk semua jenis yang ditentukan pengguna.


Peringatan untuk semua ...

Semua ini tunduk pada satu masalah potensial, dan itu adalah pertanyaan tentang bagaimana objek tersebut dibangun. Berikut ini berbagai cara untuk membuat objek dan nilai-nilai yang akan digunakan oleh metode yang berbeda untuk memeriksa jenis:

// using a named function:
function Foo() { this.a = 1; }
var obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // true
(obj.constructor.name == "Foo");  // true

// let's add some prototypical inheritance
function Bar() { this.b = 2; }
Foo.prototype = new Bar();
obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // false
(obj.constructor.name == "Foo");  // false


// using an anonymous function:
obj = new (function() { this.a = 1; })();
(obj instanceof Object);              // true
(obj.constructor == obj.constructor); // true
(obj.constructor.name == "");         // true


// using an anonymous function assigned to a variable
var Foo = function() { this.a = 1; };
obj = new Foo();
(obj instanceof Object);      // true
(obj instanceof Foo);         // true
(obj.constructor == Foo);     // true
(obj.constructor.name == ""); // true


// using object literal syntax
obj = { foo : 1 };
(obj instanceof Object);            // true
(obj.constructor == Object);        // true
(obj.constructor.name == "Object"); // true

Meskipun tidak semua permutasi hadir dalam sekumpulan contoh ini, semoga ada cukup banyak untuk memberi Anda gambaran tentang bagaimana hal-hal yang berantakan dapat bergantung pada kebutuhan Anda. Jangan berasumsi apa pun, jika Anda tidak memahami apa yang Anda cari, Anda mungkin berakhir dengan pemecahan kode di mana Anda tidak mengharapkannya karena kurangnya grokking kehalusan.

CATATAN:

Diskusi tentang typeof operator mungkin tampak sebagai kelalaian yang mencolok, tetapi sebenarnya tidak berguna dalam membantu mengidentifikasi apakah suatu object adalah tipe yang diberikan, karena sangat sederhana. Memahami di mana typeof berguna adalah penting, tetapi saya saat ini tidak merasa bahwa itu sangat relevan dengan diskusi ini. Pikiranku terbuka untuk berubah. :)


1399
2017-12-01 22:21



Jawaban Jason Bunting memberi saya cukup petunjuk untuk menemukan apa yang saya butuhkan:

<<Object instance>>.constructor.name

Jadi, misalnya, dalam potongan kode berikut:

function MyObject() {}
var myInstance = new MyObject();

myInstance.constructor.name akan kembali "MyObject".


103
2018-06-16 22:25



Sedikit trik yang saya gunakan:

function Square(){
    this.className = "Square";
    this.corners = 4;
}

var MySquare = new Square();
console.log(MySquare.className); // "Square"

24
2017-08-28 15:59



Memperbarui

Tepatnya, saya pikir OP meminta fungsi yang mengambil nama konstruktor untuk objek tertentu. Dalam hal Javascript, object tidak memiliki tipe tetapi merupakan tipe dari dan dalam dirinya sendiri. Namun, objek yang berbeda bisa berbeda konstruktor.

Object.prototype.getConstructorName = function () {
   var str = (this.prototype ? this.prototype.constructor : this.constructor).toString();
   var cname = str.match(/function\s(\w*)/)[1];
   var aliases = ["", "anonymous", "Anonymous"];
   return aliases.indexOf(cname) > -1 ? "Function" : cname;
}

new Array().getConstructorName();  // returns "Array"
(function () {})().getConstructorName(); // returns "Function"


catatan: contoh di bawah ini sudah ditinggalkan.

SEBUAH posting blog dihubungkan oleh Sciberras Kristen berisi contoh bagus tentang cara melakukannya. Yakni, dengan memperluas prototipe Object:

if (!Object.prototype.getClassName) {
    Object.prototype.getClassName = function () {
        return Object.prototype.toString.call(this).match(/^\[object\s(.*)\]$/)[1];
    }
}

var test = [1,2,3,4,5];

alert(test.getClassName()); // returns Array

16
2018-03-24 12:26



Menggunakan Object.prototype.toString

Ternyata, karena rincian posting ini, Anda dapat menggunakan Object.prototype.toString - implementasi toString tingkat rendah dan generik - untuk mendapatkan jenis untuk semua tipe bawaan

Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call(/abc/) // [object RegExp]
Object.prototype.toString.call([1,2,3]) // [object Array]

Seseorang dapat menulis fungsi pembantu singkat seperti

function type(obj){
    return Object.prototype.toString.call(obj]).match(/\s\w+/)[0].trim()
}

return [object String] as String
return [object Number] as Number
return [object Object] as Object
return [object Undefined] as Undefined
return [object Function] as Function

9
2018-03-05 14:42



Berikut ini adalah solusi yang telah saya buat dengan memecahkan kekurangan-kekurangan contoh. Ini dapat memeriksa jenis objek dari lintas-jendela dan lintas-frame dan tidak memiliki masalah dengan tipe primitif.

function getType(o) {
    return Object.prototype.toString.call(o).match(/^\[object\s(.*)\]$/)[1];
}
function isInstance(obj, type) {
    var ret = false,
    isTypeAString = getType(type) == "String",
    functionConstructor, i, l, typeArray, context;
    if (!isTypeAString && getType(type) != "Function") {
        throw new TypeError("type argument must be a string or function");
    }
    if (obj !== undefined && obj !== null && obj.constructor) {
        //get the Function constructor
        functionConstructor = obj.constructor;
        while (functionConstructor != functionConstructor.constructor) {
            functionConstructor = functionConstructor.constructor;
        }
        //get the object's window
        context = functionConstructor == Function ? self : functionConstructor("return window")();
        //get the constructor for the type
        if (isTypeAString) {
            //type is a string so we'll build the context (window.Array or window.some.Type)
            for (typeArray = type.split("."), i = 0, l = typeArray.length; i < l && context; i++) {
                context = context[typeArray[i]];
            }
        } else {
            //type is a function so execute the function passing in the object's window
            //the return should be a constructor
            context = type(context);
        }
        //check if the object is an instance of the constructor
        if (context) {
            ret = obj instanceof context;
            if (!ret && (type == "Number" || type == "String" || type == "Boolean")) {
                ret = obj.constructor == context
            }
        }
    }
    return ret;
}

isInstance membutuhkan dua parameter: objek dan tipe. Trik nyata untuk cara kerjanya adalah ia memeriksa apakah objek dari jendela yang sama dan jika tidak mendapatkan jendela objek.

Contoh:

isInstance([], "Array"); //true
isInstance("some string", "String"); //true
isInstance(new Object(), "Object"); //true

function Animal() {}
function Dog() {}
Dog.prototype = new Animal();

isInstance(new Dog(), "Dog"); //true
isInstance(new Dog(), "Animal"); //true
isInstance(new Dog(), "Object"); //true
isInstance(new Animal(), "Dog"); //false

Argumen type juga bisa menjadi fungsi callback yang mengembalikan konstruktor. Fungsi callback akan menerima satu parameter yang merupakan jendela dari objek yang disediakan.

Contoh:

//"Arguments" type check
var args = (function() {
    return arguments;
}());

isInstance(args, function(w) {
    return w.Function("return arguments.constructor")();
}); //true

//"NodeList" type check
var nl = document.getElementsByTagName("*");

isInstance(nl, function(w) {
    return w.document.getElementsByTagName("bs").constructor;
}); //true

Satu hal yang perlu diingat adalah bahwa IE <9 tidak menyediakan konstruktor pada semua objek sehingga pengujian di atas untuk NodeList akan mengembalikan false dan juga isInstance (alert, "Function") akan mengembalikan false.


8
2017-08-12 19:38



Menggunakan constructor.name kapan Anda bisa, dan fungsi regex ketika saya tidak bisa.

Function.prototype.getName = function(){
  if (typeof this.name != 'undefined')
    return this.name;
  else
    return /function (.+)\(/.exec(this.toString())[1];
};

6
2017-10-23 15:04



Itu jenis() fungsi dari Agave.JS akan kembali:

  • prototipe terdekat di pohon warisan
  • untuk tipe yang selalu primitif seperti 'null' dan 'undefined', nama primitif.

Ia bekerja pada semua objek JS dan primitif, terlepas dari bagaimana mereka diciptakan, dan tidak ada kejutan. Contoh:

Angka

kind(37) === 'Number'
kind(3.14) === 'Number'
kind(Math.LN2) === 'Number'
kind(Infinity) === 'Number'
kind(Number(1)) === 'Number'
kind(new Number(1)) === 'Number'

NaN

kind(NaN) === 'NaN'

String

kind('') === 'String'
kind('bla') === 'String'
kind(String("abc")) === 'String'
kind(new String("abc")) === 'String'

Boolean

kind(true) === 'Boolean'
kind(false) === 'Boolean'
kind(new Boolean(true)) === 'Boolean'

Array

kind([1, 2, 4]) === 'Array'
kind(new Array(1, 2, 3)) === 'Array'

Objek

kind({a:1}) === 'Object'
kind(new Object()) === 'Object'

tanggal

kind(new Date()) === 'Date'

Fungsi

kind(function(){}) === 'Function'
kind(new Function("console.log(arguments)")) === 'Function'
kind(Math.sin) === 'Function'

tidak terdefinisi

kind(undefined) === 'undefined'

batal

kind(null) === 'null'

6
2017-12-01 22:13



Anda dapat menggunakan instanceof operator untuk melihat apakah suatu objek adalah turunan dari yang lain, tetapi karena tidak ada kelas, Anda tidak dapat memperoleh nama kelas.


5
2017-12-07 13:00



Saya sebenarnya mencari hal yang serupa dan menemukan pertanyaan ini. Inilah cara saya mendapatkan jenis: jsfiddle

var TypeOf = function ( thing ) {

    var typeOfThing = typeof thing;

    if ( 'object' === typeOfThing ) {

        typeOfThing = Object.prototype.toString.call( thing );

        if ( '[object Object]' === typeOfThing ) {

            if ( thing.constructor.name ) {
                return thing.constructor.name;
            } 

            else if ( '[' === thing.constructor.toString().charAt(0) ) {
                typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
            } 

            else {

                typeOfThing = thing.constructor.toString().match( /function\s*(\w+)/ );

                if ( typeOfThing ) { 
                    return typeOfThing[1];
                } 

                else {
                    return 'Function';
                }
            }
        } 

        else {
            typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
        }
    }

    return typeOfThing.charAt(0).toUpperCase() + typeOfThing.slice(1);
}

5
2017-12-02 18:52