Dapatkan nama jenis objek

1193

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

Ewen Cartwright
sumber
Pertanyaan ini menganggap kita tahu apa yang dilakukan class.getName () Java. Karena saya tidak, saya tidak yakin apakah jawabannya akan membantu saya.
user34660
2
@ user34660 Saya pikir kita dapat dengan aman berasumsi bahwa apa yang dilakukannya adalah mendapatkan nama tipe objek.
Stack Underflow
1
@StackUnderflow: Kecuali, sebenarnya tidak. Ia mendapat nama obyek kelas , yang tidak sama dengan obyek tipe .
Jörg W Mittag
1
@ JörgWMittag Ah ya, tentu saja. Ya lihat apa yang terjadi ketika Anda berkeliling dengan aman dengan asumsi sesuatu?
Stack Underflow

Jawaban:

1540

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

Tidak ada .

ES2015 Update : nama class Foo {}adalahFoo.name . Nama thingkelas, apa pun thingjenisnya, adalah thing.constructor.name. Konstruktor builtin di lingkungan ES2015 memiliki nameproperti yang benar ; misalnya (2).constructor.nameadalah "Number".


Tapi di sini ada berbagai peretasan yang semuanya jatuh dengan satu atau lain cara:

Berikut adalah retasan yang akan melakukan apa yang Anda butuhkan - perlu diketahui bahwa ia memodifikasi prototipe Object, sesuatu yang disukai orang (biasanya karena alasan yang baik)

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 FF3dan IE7saya tidak dapat berbicara untuk implementasi lainnya.

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 tidak terlalu sulit. Koreksi menyambut ...

Menggunakan constructorproperti ...

Setiap objectmemiliki nilai untuk constructorpropertinya, tetapi tergantung pada bagaimana objectitu dibangun serta apa yang ingin Anda lakukan dengan nilai itu, itu mungkin atau mungkin tidak berguna.

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

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

Jadi, itu bekerja dengan cukup baik untuk sebagian besar kebutuhan. Yang mengatakan ...

Peringatan

Tidak akan berfungsi sama sekali dalam banyak kasus

Pola ini, meskipun rusak, cukup umum:

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

Objectsdibangun melalui new Thingyakan memiliki constructorproperti yang menunjuk ke Object, bukan Thingy. Jadi kita jatuh tepat pada awalnya; Anda tidak bisa mempercayai constructorbasis kode yang tidak Anda kontrol.

Warisan Berganda

Contoh yang tidak terlalu 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 berfungsi seperti yang Anda perkirakan:

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 objectpengujian Anda memiliki objectset yang berbeda prototype. Ada beberapa cara di luar ruang lingkup diskusi ini.

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

Tidak akan bekerja lintas-bingkai dan lintas-jendela

Menggunakan .constructoruntuk pengecekan tipe akan pecah ketika Anda ingin memeriksa jenis objek yang berasal dari windowobjek yang berbeda , katakan bahwa iframe atau jendela sembulan. Ini karena ada versi berbeda dari setiap tipe inti constructordi setiap `jendela ', yaitu

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

Menggunakan instanceofoperator ...

The instanceofoperator adalah cara yang bersih dari pengujian objectjenis juga, tapi memiliki potensi masalah sendiri, seperti constructorproperti.

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

Tetapi instanceofgagal bekerja untuk nilai-nilai literal (karena literal tidak Objects)

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

Literal perlu dibungkus Objectagar instanceofdapat bekerja, misalnya

new Number(3) instanceof Number // true

The .constructorcek berfungsi dengan baik untuk literal karena .pemanggilan metode implisit membungkus literal di jenis objek masing-masing

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

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

Tidak akan bekerja lintas-bingkai dan lintas-jendela

instanceofjuga tidak akan bekerja di jendela yang berbeda, untuk alasan yang sama seperti constructorpemeriksaan properti.


Menggunakan nameproperti constructorproperti ...

Tidak berfungsi sama sekali dalam banyak kasus

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

TIDAK bekerja di <IE9

Menggunakan myObjectInstance.constructor.nameakan memberi Anda string yang berisi nama constructorfungsi yang digunakan, tetapi tunduk pada peringatan tentang constructorproperti yang disebutkan sebelumnya.

Untuk IE9 dan yang lebih baru, Anda dapat mendukung-monyet :

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 tersebut. 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 dalam 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, karena rincian pos ini , Anda dapat menggunakan Object.prototype.toString- level rendah dan implementasi generik 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]

Orang bisa menulis fungsi pembantu pendek seperti

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

untuk menghapus cruft dan dapatkan di hanya ketik nama

type('abc') // String

Namun, itu akan kembali Objectuntuk 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 adalah berbagai cara membangun objek dan nilai-nilai yang akan dikembalikan oleh metode pengecekan tipe yang berbeda:

// 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 serangkaian contoh ini, mudah-mudahan ada cukup untuk memberi Anda gagasan tentang bagaimana hal-hal yang berantakan mungkin tergantung pada kebutuhan Anda. Jangan berasumsi apa-apa, jika Anda tidak mengerti apa yang Anda cari, Anda mungkin berakhir dengan melanggar kode di mana Anda tidak mengharapkannya karena kurangnya mengasyikkan kehalusan.

CATATAN:

Diskusi typeofoperator mungkin tampak sebagai kelalaian mencolok, tetapi itu benar-benar tidak berguna dalam membantu mengidentifikasi apakah suatu objectjenis diberikan, karena sangat sederhana. Memahami di mana typeofberguna itu penting, tetapi saya saat ini tidak merasa bahwa itu sangat relevan dengan diskusi ini. Pikiranku terbuka untuk berubah. :)

Jason Bunting
sumber
58
Yah, saya pikir saya mungkin juga - titik Stack Overflow adalah menjadi sedikit seperti wiki, dan ini jauh lebih sesuai dengan maksud itu, saya pikir. Bagaimanapun, saya hanya ingin agak teliti.
Jason Bunting
Mengulangi jawaban di bawah ini --- ekstensi Anda ke prototipe Obyek tidak berfungsi di IE8 - apakah ada yang tahu apa yang akan bekerja di IE8?
Adam
5
Ini akan berfungsi jika Anda melakukannya seperti fungsi ini a () {this.a = 1;} fungsi b () {this.b = 2; } b.prototype = baru a (); // b mewarisi dari b.prototype.constructor = b; // Cara pewarisan prototipikal yang benar var f = new b (); // buat objek baru dengan b constructor (f.constructor == b); // TRUE (f.constructor == a); // FALSE
Boris Hamanov
9
Sekarang, beginilah seharusnya sebagian besar jawaban ada di StackOverflow. (jangan menganggap panjang jawaban sebagai parameter yang menentukan, tetapi kelengkapannya)
kumarharsh
44
Penting untuk dicatat bahwa teknik apa pun yang memeriksa constructormetode objek (baik dengan .toString()atau .name) akan gagal berfungsi jika Javascript Anda telah diperkecil dengan alat seperti uglify, atau pipa aset Rails. Minifikasi mengganti nama konstruktor, sehingga Anda akan berakhir dengan nama kelas yang salah seperti n. Jika Anda berada dalam skenario ini, Anda mungkin ingin secara manual mendefinisikan classNameproperti pada objek Anda dan menggunakannya.
Gabe Martin-Dempesy
126

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.nameakan kembali "MyObject".

Ewen Cartwright
sumber
22
Untuk kelengkapan, mungkin perlu disebutkan bahwa menggunakan constructor.name hanya berfungsi jika Anda menggunakan fungsi bernama sebagai konstruktor yang bertentangan dengan fungsi anonim yang ditugaskan ke variabel.
Matthew Crumley
20
Untuk kelengkapan, mungkin perlu disebutkan bahwa itu tidak berfungsi di browser IE --- mereka tidak mendukung atribut "nama" pada fungsi.
Eugene Lazutkin
2
@Eugene - Saya lupa tentang itu ... Saya kira saya telah menghabiskan terlalu banyak waktu melakukan javascript di luar browser.
Matthew Crumley
2
function getType(o) { return o && o.constructor && o.constructor.name }
justin.m.chase
Ini sangat komprehensif.
ibic
26

Trik kecil yang saya gunakan:

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

var MySquare = new Square();
console.log(MySquare.className); // "Square"
Daniel Szabo
sumber
11
Saya tidak terlalu suka ini. Ini lebih semacam trik kotor. Di sisi lain, jika Anda tidak memiliki terlalu banyak konstruktor, mungkin akan berfungsi dengan baik.
pimvdb
13
@ pimvdb: Saya pikir ini lebih bersih daripada memodifikasi prototipe objek, a la jawaban yang diterima.
Daniel Szabo
4
@DanielSzabo jika properti harus memiliki nilai yang sama antara semua contoh prototipe, saya pasti lebih suka hanya meletakkannya di prototipe - meletakkannya di setiap contoh super-redundan dan metadata hilang dari prototipe itu sendiri. Yang mengatakan, solusi paling bijak diadopsi dalam ES6: jika Anda punya class Square, namanya adalah Square.name/ MySquare.constructor.namebukan Square.prototype.name; dengan memakai namefungsi konstruktor, ia tidak mencemari prototipe atau contoh apa pun, tetapi dapat diakses dari keduanya.
Andy
17

Memperbarui

Lebih tepatnya, saya pikir OP meminta fungsi yang mengambil nama konstruktor untuk objek tertentu. Dalam hal Javascript, objecttidak memiliki tipe tetapi merupakan tipe dan dengan sendirinya . Namun, objek yang berbeda dapat memiliki konstruktor yang berbeda .

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 usang.

Sebuah posting blog dihubungkan oleh Christian Sciberras berisi contoh yang baik tentang bagaimana untuk melakukannya. Yaitu, dengan memperluas prototipe Obyek:

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
Saulus
sumber
2
Bagus, tapi kami ingin menamai lagi: JS tidak punya kelas.
mikemaccana
@ thumbnailer - Saya sarankan untuk menggunakan fungsi yang diperbarui, yang lama disimpan hanya untuk alasan historis.
Saul
Ini berfungsi tetapi harus dicatat bahwa itu bisa dilakukan tanpa memodifikasi Object.prototype, dengan membuat fungsi yang menggunakan objek sebagai argumen pertama dan menggunakannya sebagai ganti 'ini' di dalam fungsi.
Matt Browne
2
@ Mat - Tentu. Hanya saja memiliki metode objek lebih singkat: test.getClassName()vs getClassName.apply(test).
Saul
12

Menggunakan Object.prototype.toString

Ternyata, karena rincian pos ini, Anda dapat menggunakan Object.prototype.toString - implementasi toString tingkat rendah dan generik - 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]

Orang bisa menulis fungsi pembantu pendek 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
Gaurav Ramanan
sumber
6
Anda tidak perlu menggunakan regex untuk mem-parsing nama objek. Cukup gunakan .slice():Object.prototype.toString.call(obj).slice( 8, -1 );
bobobobo
9

Berikut ini adalah solusi yang saya temukan yang memecahkan kekurangan instanceof. Itu dapat memeriksa tipe objek dari cross-windows dan cross-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 memerlukan dua parameter: objek dan tipe. Trik sebenarnya untuk cara kerjanya adalah memeriksa apakah objek berasal 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 tipe juga bisa menjadi fungsi callback yang mengembalikan konstruktor. Fungsi panggilan balik 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 tes di atas untuk NodeList akan mengembalikan false dan juga isInstance (waspada, "Function") akan mengembalikan false.

Eli
sumber
8

Saya sebenarnya mencari hal yang sama dan menemukan pertanyaan ini. Inilah cara saya mendapatkan tipe: 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);
}
Mahdi
sumber
7

Anda harus menggunakan somevar.constructor.nameseperti:

    
    const getVariableType = a => a.constructor.name.toLowerCase();

    const d = new Date();
    const res1 = getVariableType(d); // 'date'
    const num = 5;
    const res2 = getVariableType(num); // 'number'
    const fn = () => {};
    const res3 = getVariableType(fn); // 'function'

    console.log(res1); // 'date'
    console.log(res2); // 'number'
    console.log(res3); // 'function'

aflex dykyі
sumber
6

Gunakan constructor.namesaat Anda bisa, dan regex berfungsi saat saya tidak bisa.

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

Fungsi kind () dari Agave.JS akan kembali:

  • prototipe terdekat di pohon warisan
  • untuk tipe yang selalu primitif seperti 'nol' dan 'tidak terdefinisi', nama primitif.

Ini bekerja pada semua objek dan primitif JS, terlepas dari bagaimana mereka dibuat , dan tidak memiliki 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'

Benda

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'
mikemaccana
sumber
5

Anda bisa menggunakan instanceofoperator untuk melihat apakah suatu objek adalah turunan dari yang lain, tetapi karena tidak ada kelas, Anda tidak bisa mendapatkan nama kelas.

Greg
sumber
Meskipun benar bahwa JavaScript tidak memiliki kelas sebagai konstruksi bahasa, konvensi generiknya masih berupa jenis objek yang disebut kelas ..
Saul
2
@reg Yakin tetapi instanceofhanya memeriksa apakah suatu objek mewarisi dari objek lain. Misalnya, []pewarisan sederhana dari Array, tetapi Array juga mewarisi dari Obyek. Karena sebagian besar objek memiliki beberapa tingkat warisan, menemukan prototipe terdekat adalah teknik yang lebih baik. Lihat jawaban saya untuk caranya.
mikemaccana
4

Berikut ini adalah implementasi berdasarkan jawaban yang diterima :

/**
 * Returns the name of an object's type.
 *
 * If the input is undefined, returns "Undefined".
 * If the input is null, returns "Null".
 * If the input is a boolean, returns "Boolean".
 * If the input is a number, returns "Number".
 * If the input is a string, returns "String".
 * If the input is a named function or a class constructor, returns "Function".
 * If the input is an anonymous function, returns "AnonymousFunction".
 * If the input is an arrow function, returns "ArrowFunction".
 * If the input is a class instance, returns "Object".
 *
 * @param {Object} object an object
 * @return {String} the name of the object's class
 * @see <a href="https://stackoverflow.com/a/332429/14731">https://stackoverflow.com/a/332429/14731</a>
 * @see getFunctionName
 * @see getObjectClass 
 */
function getTypeName(object)
{
  const objectToString = Object.prototype.toString.call(object).slice(8, -1);
  if (objectToString === "Function")
  {
    const instanceToString = object.toString();
    if (instanceToString.indexOf(" => ") != -1)
      return "ArrowFunction";
    const getFunctionName = /^function ([^(]+)\(/;
    const match = instanceToString.match(getFunctionName);
    if (match === null)
      return "AnonymousFunction";
    return "Function";
  }
  // Built-in types (e.g. String) or class instances
  return objectToString;
};

/**
 * Returns the name of a function.
 *
 * If the input is an anonymous function, returns "".
 * If the input is an arrow function, returns "=>".
 *
 * @param {Function} fn a function
 * @return {String} the name of the function
 * @throws {TypeError} if {@code fn} is not a function
 * @see getTypeName
 */
function getFunctionName(fn)
{
  try
  {
    const instanceToString = fn.toString();
    if (instanceToString.indexOf(" => ") != -1)
      return "=>";
    const getFunctionName = /^function ([^(]+)\(/;
    const match = instanceToString.match(getFunctionName);
    if (match === null)
    {
      const objectToString = Object.prototype.toString.call(fn).slice(8, -1);
      if (objectToString === "Function")
        return "";
      throw TypeError("object must be a Function.\n" +
        "Actual: " + getTypeName(fn));
    }
    return match[1];
  }
  catch (e)
  {
    throw TypeError("object must be a Function.\n" +
      "Actual: " + getTypeName(fn));
  }
};

/**
 * @param {Object} object an object
 * @return {String} the name of the object's class
 * @throws {TypeError} if {@code object} is not an Object
 * @see getTypeName
 */
function getObjectClass(object)
{
  const getFunctionName = /^function ([^(]+)\(/;
  const result = object.constructor.toString().match(getFunctionName)[1];
  if (result === "Function")
  {
    throw TypeError("object must be an Object.\n" +
      "Actual: " + getTypeName(object));
  }
  return result;
};


function UserFunction()
{
}

function UserClass()
{
}

let anonymousFunction = function()
{
};

let arrowFunction = i => i + 1;

console.log("getTypeName(undefined): " + getTypeName(undefined));
console.log("getTypeName(null): " + getTypeName(null));
console.log("getTypeName(true): " + getTypeName(true));
console.log("getTypeName(5): " + getTypeName(5));
console.log("getTypeName(\"text\"): " + getTypeName("text"));
console.log("getTypeName(userFunction): " + getTypeName(UserFunction));
console.log("getFunctionName(userFunction): " + getFunctionName(UserFunction));
console.log("getTypeName(anonymousFunction): " + getTypeName(anonymousFunction));
console.log("getFunctionName(anonymousFunction): " + getFunctionName(anonymousFunction));
console.log("getTypeName(arrowFunction): " + getTypeName(arrowFunction));
console.log("getFunctionName(arrowFunction): " + getFunctionName(arrowFunction));
//console.log("getFunctionName(userClass): " + getFunctionName(new UserClass()));
console.log("getTypeName(userClass): " + getTypeName(new UserClass()));
console.log("getObjectClass(userClass): " + getObjectClass(new UserClass()));
//console.log("getObjectClass(userFunction): " + getObjectClass(UserFunction));
//console.log("getObjectClass(userFunction): " + getObjectClass(anonymousFunction));
//console.log("getObjectClass(arrowFunction): " + getObjectClass(arrowFunction));
console.log("getTypeName(nativeObject): " + getTypeName(navigator.mediaDevices.getUserMedia));
console.log("getFunctionName(nativeObject): " + getFunctionName(navigator.mediaDevices.getUserMedia));

Kami hanya menggunakan properti konstruktor ketika kami tidak punya pilihan lain.

Gili
sumber
3

Anda dapat menggunakan operator "instanceof" untuk menentukan apakah suatu objek adalah turunan dari kelas tertentu atau tidak. Jika Anda tidak tahu nama tipe objek, Anda bisa menggunakan properti konstruktornya. Properti konstruktor objek, adalah referensi ke fungsi yang digunakan untuk menginisialisasi mereka. Contoh:

function Circle (x,y,radius) {
    this._x = x;
    this._y = y;
    this._radius = raduius;
}
var c1 = new Circle(10,20,5);

Sekarang c1.constructor adalah referensi ke Circle()fungsi. Anda juga dapat menggunakan typeofoperator, tetapi typeofoperator menunjukkan informasi yang terbatas. Salah satu solusinya adalah dengan menggunakan toString()metode Object global object. Misalnya jika Anda memiliki objek, katakan myObject, Anda dapat menggunakan toString()metode Obyek global untuk menentukan jenis kelas myObject. Gunakan ini:

Object.prototype.toString.apply(myObject);
farzad
sumber
3

Katakan sudah var obj;

Jika Anda hanya ingin nama jenis objek, seperti "Objek", "Array", atau "String", Anda dapat menggunakan ini:

Object.prototype.toString.call(obj).split(' ')[1].replace(']', '');
CommandoScorch
sumber
2

Yang paling dekat Anda dapatkan adalah typeof, tetapi hanya mengembalikan "objek" untuk semua jenis jenis kustom. Untuk itu, lihat Jason Bunting .

Sunting, Jason menghapus posnya karena alasan tertentu, jadi gunakan saja constructorproperti Object .

merah muda
sumber
Ya, maaf - saya menghapusnya karena saya pikir instanceof () adalah cara yang lebih baik untuk melakukan sesuatu, tetapi saya hanya membatalkannya sehingga dapat berfungsi sebagai referensi.
Jason Bunting
2
Jawaban yang kurang sempurna masih berguna, jika hanya untuk orang lain untuk datang ke pertanyaan nanti karena mereka memiliki masalah yang sama. Jadi Anda tidak harus menghapusnya. Simpan penghapusan untuk jawaban yang salah.
sblundy
2
Ya, saya tahu - Anda berkhotbah kepada paduan suara, saya telah mengatakan hal yang persis sama kepada orang lain. Menjalani hal-hal yang kita tahu benar seringkali lebih sulit daripada yang terlihat. :)
Jason Bunting
0

Jika ada yang mencari solusi yang bekerja dengan jQuery, di sini adalah kode wiki yang disesuaikan (istirahat asli jQuery).

Object.defineProperty(Object.prototype, "getClassName", {
    value: function() {
        var funcNameRegex = /function (.{1,})\(/;
        var results = (funcNameRegex).exec((this).constructor.toString());
        return (results && results.length > 1) ? results[1] : "";
    }
});
Daniel Jankowski
sumber
Ya, jQuery gagal melakukan cek 'hasOwnProperty' dan menghitung getNamedan jatuh.
nicodemus13
0

Lodash memiliki banyak isMethods jadi jika Anda menggunakan Lodash mungkin mixin seperti ini dapat berguna:

  // Mixin for identifying a Javascript Object

  _.mixin({
      'identify' : function(object) {
        var output;
          var isMethods = ['isArguments', 'isArray', 'isArguments', 'isBoolean', 'isDate', 'isArguments', 
              'isElement', 'isError', 'isFunction', 'isNaN', 'isNull', 'isNumber', 
              'isPlainObject', 'isRegExp', 'isString', 'isTypedArray', 'isUndefined', 'isEmpty', 'isObject']

          this.each(isMethods, function (method) {
              if (this[method](object)) {
                output = method;
                return false;
              }
          }.bind(this));
      return output;
      }
  });

Itu menambahkan metode untuk lodash yang disebut "mengidentifikasi" yang berfungsi sebagai berikut:

console.log(_.identify('hello friend'));       // isString

Plunker: http://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN

Orang
sumber
0

Ok, orang-orang saya telah perlahan-lahan membangun semua metode untuk ini selama beberapa tahun lol! Caranya adalah dengan:

  1. Miliki mekanisme untuk membuat kelas.
  2. Memiliki mekanisme untuk memeriksa semua kelas yang dibuat pengguna, primitif dan nilai-nilai yang dibuat / dihasilkan oleh konstruktor asli.
  3. Miliki mekanisme untuk memperluas kelas yang dibuat pengguna ke yang baru sehingga fungsionalitas di atas menembus melalui kode / aplikasi / perpustakaan / dll.

Sebagai contoh (atau untuk melihat bagaimana saya mengatasi masalah) lihat kode berikut di github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js dan cari:

classOf =,, classOfIs =dan atau defineSubClass =(tanpa backticks (`)).

Seperti yang Anda lihat, saya memiliki beberapa mekanisme untuk memaksa classOfagar selalu memberi saya kelas / konstruktor jenis nama terlepas dari apakah itu primitif, kelas yang ditentukan pengguna, nilai yang dibuat menggunakan konstruktor asli, Null, NaN, dll. Untuk setiap nilai javascript tunggal saya akan mendapatkan nama tipe unik dari classOffungsi. Selain itu saya dapat meneruskan konstruktor yang sebenarnya ke sjl.classOfIsuntuk memeriksa tipe nilai selain untuk dapat lulus dalam nama tipe itu juga! Jadi misalnya:

`` `// Maafkan ruang nama yang panjang! Saya tidak tahu dampaknya sampai setelah menggunakannya sebentar (mereka payah haha)

var SomeCustomClass = sjl.package.stdlib.Extendable.extend({
    constructor: function SomeCustomClass () {},
    // ...
}),

HelloIterator = sjl.ns.stdlib.Iterator.extend( 
    function HelloIterator () {}, 
    { /* ... methods here ... */ },
    { /* ... static props/methods here ... */ }
),

helloIt = new HelloIterator();

sjl.classOfIs(new SomeCustomClass(), SomeCustomClass) === true; // `true`
sjl.classOfIs(helloIt, HelloIterator) === true; // `true`

var someString = 'helloworld';

sjl.classOfIs(someString, String) === true; // `true`

sjl.classOfIs(99, Number) === true; // true

sjl.classOf(NaN) === 'NaN'; // true

sjl.classOf(new Map()) === 'Map';
sjl.classOf(new Set()) === 'Set';
sjl.classOfIs([1, 2, 4], Array) === true; // `true`

// etc..

// Also optionally the type you want to check against could be the type's name
sjl.classOfIs(['a', 'b', 'c'], 'Array') === true; // `true`!
sjl.classOfIs(helloIt, 'HelloIterator') === true; // `true`!

`` `

Jika Anda tertarik untuk membaca lebih lanjut tentang bagaimana saya menggunakan pengaturan yang disebutkan di atas, lihat repo: https://github.com/elycruz/sjljs

Juga buku-buku dengan konten pada subjek: - "Pola JavaScript" oleh Stoyan Stefanov. - "Javascript - Panduan Definitif." oleh David Flanagan. - dan banyak lainnya .. (search le` web).

Anda juga dapat dengan cepat menguji fitur yang saya bicarakan di sini: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (juga jalur 0,5.18 di url memiliki sumber dari github di sana minus node_modules dan semacamnya).

Selamat Coding!

elydelacruz
sumber
0

Cukup sederhana!

  • Metode favorit saya untuk mendapatkan jenis apa pun di JS
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • metode favorit saya untuk memeriksa jenis apa pun di JS
function checkType(entity, type){
    return getType(entity) === type
}
ZenG
sumber
-1

Gunakan class.name. Ini juga berfungsi dengan function.name.

class TestA {}
console.log(TestA.name); // "TestA"

function TestB() {}
console.log(TestB.name); // "TestB"
qwertzguy
sumber
Pertanyaannya dengan jelas mengatakan classdan bukan contoh.
qwertzguy