Cara paling akurat untuk memeriksa tipe objek JS?

144

The typeofoperator tidak benar-benar membantu kita untuk menemukan jenis nyata dari suatu objek.

Saya sudah melihat kode berikut:

Object.prototype.toString.apply(t)  

Pertanyaan:

Apakah ini cara paling akurat untuk memeriksa tipe objek?

Royi Namir
sumber
2
Lihat artikel ini: javascriptweblog.wordpress.com/2011/08/08/…
James Allardice
4
Lihat posting ini: stackoverflow.com/questions/332422/…
isJustMe
3
Cara paling akurat adalah ... tidak menguji tipenya. Mengapa Anda membutuhkan tipe?
hugomg
Object.prototype.toString.call / Object.prototype.toString.apply
xgqfrms

Jawaban:

198

Spesifikasi JavaScript memberikan satu cara yang tepat untuk menentukan kelas suatu objek:

Object.prototype.toString.call(t);

http://bonsaiden.github.com/JavaScript-Garden/#types

kmatheny
sumber
5
Jika Anda mencari tipe tertentu, Anda mungkin ingin melakukan sesuatu di sepanjang baris: Object.prototype.toString.call(new FormData()) === "[object FormData]"yang benar. Anda juga dapat menggunakan slice(8, -1)untuk kembali FormDatasebagai ganti[object FormData]
Chris Marisic
4
Apakah ada perbedaan antara menggunakan Object.prototypedan {}?
Dapatkan Gratis
3
mungkin ini telah berubah selama bertahun-tahun, namun Object.prototype.toString.call(new MyCustomObject())hasil [object Object]sementara new MyCustomObject() instanceOf MyCustomObject returns trueyang adalah apa yang saya inginkan (Chrome 54.0.2840.99 m)
Maslow
@Maslow, saya mengalami masalah yang sama dengan yang Anda sampaikan. Setelah melihat beberapa dokumentasi online, saya akhirnya menggunakan new MyCustomObject().constructor === MyCustomObject.
solstice333
3
Ini menimbulkan pertanyaan, mengapa mereka tidak membungkus kode ini dengan metode yang lebih nyaman, atau mengizinkan operator tambahan mengkompilasi untuk ini. Saya tahu Anda hanyalah pembawa pesan, tapi terus terang itu buruk.
Andrew S
60

yang Object.prototype.toStringadalah cara yang baik, tapi kinerjanya adalah yang terburuk.

http://jsperf.com/check-js-type

periksa kinerja tipe js

Gunakan typeofuntuk memecahkan beberapa masalah dasar (String, Angka, Boolean ...) dan gunakan Object.prototype.toStringuntuk menyelesaikan sesuatu yang kompleks (seperti Array, Date, RegExp).

dan inilah solusi saya:

var type = (function(global) {
    var cache = {};
    return function(obj) {
        var key;
        return obj === null ? 'null' // null
            : obj === global ? 'global' // window in browser or global in nodejs
            : (key = typeof obj) !== 'object' ? key // basic: string, boolean, number, undefined, function
            : obj.nodeType ? 'object' // DOM element
            : cache[key = ({}).toString.call(obj)] // cached. date, regexp, error, object, array, math
            || (cache[key] = key.slice(8, -1).toLowerCase()); // get XXXX from [object XXXX], and cache it
    };
}(this));

digunakan sebagai:

type(function(){}); // -> "function"
type([1, 2, 3]); // -> "array"
type(new Date()); // -> "date"
type({}); // -> "object"
wiky
sumber
Tes di jsPerf itu kurang akurat. Tes-tes itu tidak sama (menguji hal yang sama). Misalnya, typeof [] mengembalikan "objek", typeof {} juga mengembalikan "objek", meskipun satu adalah objek Array dan yang lainnya adalah objek objek. Ada banyak masalah lain dengan tes itu ... Berhati-hatilah saat melihat jsPerf bahwa tes tersebut membandingkan Apel dengan Apel.
kmatheny
typeFungsi Anda bagus, tapi lihat bagaimana fungsinya dibandingkan dengan beberapa typefungsi lainnya . http://jsperf.com/code-type-test-a-test
Progo
19
Metrik kinerja ini harus disesuaikan dengan akal sehat. Tentu, prototype.toString lebih lambat dari yang lain berdasarkan urutan besarnya, tetapi dalam skema besar, dibutuhkan rata-rata beberapa ratus nanodetik per panggilan. Kecuali panggilan ini digunakan di jalur kritis yang sangat sering dijalankan, ini mungkin tidak berbahaya. Saya lebih suka memiliki kode langsung daripada kode yang menyelesaikan satu mikrodetik lebih cepat.
David
({}).toString.call(obj)lebih lambat dari Object.prototype.toString jsperf.com/object-check-test77
timaschew
Solusi bagus. Saya meminjam fungsi Anda ke lib saya :)
Dong Nguyen
21

Jawaban yang diterima benar, tetapi saya ingin mendefinisikan utilitas kecil ini di sebagian besar proyek yang saya bangun.

var types = {
   'get': function(prop) {
      return Object.prototype.toString.call(prop);
   },
   'null': '[object Null]',
   'object': '[object Object]',
   'array': '[object Array]',
   'string': '[object String]',
   'boolean': '[object Boolean]',
   'number': '[object Number]',
   'date': '[object Date]',
}

Digunakan seperti ini:

if(types.get(prop) == types.number) {

}

Jika Anda menggunakan sudut, Anda bahkan dapat menyuntikkannya dengan bersih:

angular.constant('types', types);
parlemen
sumber
11
var o = ...
var proto =  Object.getPrototypeOf(o);
proto === SomeThing;

Pegang kendali pada prototipe yang Anda harapkan dimiliki objek, lalu bandingkan dengannya.

sebagai contoh

var o = "someString";
var proto =  Object.getPrototypeOf(o);
proto === String.prototype; // true
Raynos
sumber
Bagaimana ini lebih baik / berbeda dari mengatakan o instanceof String; //true?
Jamie Treworgy
@jamietre karena "foo" instanceof Stringistirahat
Raynos
OK, jadi "typeof (o) === 'object' && o instanceof SomeObject". Sangat mudah untuk menguji string. Sepertinya pekerjaan ekstra, tanpa memecahkan masalah dasar karena harus tahu sebelumnya untuk apa Anda menguji.
Jamie Treworgy
Maaf potongan kode itu tidak masuk akal tapi saya pikir Anda tahu apa yang saya maksud, jika Anda menguji string, gunakan typeof(x)==='string'saja.
Jamie Treworgy
BTW, Object.getPrototypeOf(true)gagal di mana (true).constructorkembali Boolean.
katspaugh
6

Saya berpendapat bahwa sebagian besar solusi yang ditampilkan di sini menderita karena rekayasa berlebihan. Mungkin cara paling sederhana untuk memeriksa apakah suatu nilai bertipe [object Object]adalah dengan memeriksa .constructorpropertinya:

function isObject (a) { return a != null && a.constructor === Object; }

atau bahkan lebih pendek dengan fungsi panah:

const isObject = a => a != null && a.constructor === Object;

Bagian a != nullini diperlukan karena salah satu mungkin lolos nullatau undefineddan Anda tidak dapat mengekstrak properti konstruktor dari salah satu dari ini.

Ia bekerja dengan objek apa pun yang dibuat melalui:

  • yang Objectkonstruktor
  • literal {}

Fitur rapi lainnya, adalah kemampuannya untuk memberikan laporan yang benar untuk kelas khusus yang memanfaatkan Symbol.toStringTag. Sebagai contoh:

class MimicObject {
  get [Symbol.toStringTag]() {
    return 'Object';
  }
}

Masalahnya di sini adalah ketika memanggil Object.prototype.toStringsebuah instance, laporan palsu [object Object]akan dikembalikan:

let fakeObj = new MimicObject();
Object.prototype.toString.call(fakeObj); // -> [object Object]

Tetapi memeriksa konstruktor memberikan hasil yang benar:

let fakeObj = new MimicObject();
fakeObj.constructor === Object; // -> false
David
sumber
4

Cara terbaik untuk mengetahui tipe NYATA dari suatu objek (termasuk KEDUA objek asli atau nama Tipe Data (seperti String, Tanggal, Angka, ..etc) DAN tipe NYATA dari suatu objek (bahkan yang khusus); adalah dengan mengambil properti nama konstruktor prototipe objek:

Jenis Asli Ex1:

var string1 = "Test";
console.log(string1.__proto__.constructor.name);

menampilkan:

String

Ex2:

var array1 = [];
console.log(array1.__proto__.constructor.name);

menampilkan:

Array

Kelas Kustom:

function CustomClass(){
  console.log("Custom Class Object Created!");
}
var custom1 = new CustomClass();

console.log(custom1.__proto__.constructor.name);

menampilkan:

CustomClass
beliha
sumber
Ini gagal jika objeknya adalah salah satu nullatau undefined.
Julian Knight
2

Pertanyaan lama yang saya tahu. Anda tidak perlu mengubahnya. Lihat fungsi ini:

function getType( oObj )
{
    if( typeof oObj === "object" )
    {
          return ( oObj === null )?'Null':
          // Check if it is an alien object, for example created as {world:'hello'}
          ( typeof oObj.constructor !== "function" )?'Object':
          // else return object name (string)
          oObj.constructor.name;              
    }   

    // Test simple types (not constructed types)
    return ( typeof oObj === "boolean")?'Boolean':
           ( typeof oObj === "number")?'Number':
           ( typeof oObj === "string")?'String':
           ( typeof oObj === "function")?'Function':false;

}; 

Contoh:

function MyObject() {}; // Just for example

console.log( getType( new String( "hello ") )); // String
console.log( getType( new Function() );         // Function
console.log( getType( {} ));                    // Object
console.log( getType( [] ));                    // Array
console.log( getType( new MyObject() ));        // MyObject

var bTest = false,
    uAny,  // Is undefined
    fTest  function() {};

 // Non constructed standard types
console.log( getType( bTest ));                 // Boolean
console.log( getType( 1.00 ));                  // Number
console.log( getType( 2000 ));                  // Number
console.log( getType( 'hello' ));               // String
console.log( getType( "hello" ));               // String
console.log( getType( fTest ));                 // Function
console.log( getType( uAny ));                  // false, cannot produce
                                                // a string

Biaya rendah dan sederhana.

Codebeat
sumber
Mengembalikan falsejika objek uji adalah nullatauundefined
Julian Knight
atau trueataufalse
Julian Knight
@JulianKnight false tidak apa-apa di null atau undefined, tidak ada yang berguna. Jadi apa gunanya?
Codebeat
contoh Anda menampilkan data yang tidak konsisten. Beberapa hasil adalah tipe data dan lainnya adalah nilainya false. Bagaimana ini membantu menjawab Pertanyaan?
Julian Knight
1
@JulianKnight Lihat perubahan, apakah itu yang Anda inginkan? Jika Anda lebih suka hasil yang tidak ditentukan atau "tidak ditentukan", Anda dapat mengganti salah terakhir jika Anda mau.
Codebeat
1

The solusi terbaik adalah toString(seperti yang disebutkan di atas):

function getRealObjectType(obj: {}): string {
    return Object.prototype.toString.call(obj).match(/\[\w+ (\w+)\]/)[1].toLowerCase();
}

masukkan deskripsi gambar di sini

FAIR PERINGATAN: toString menganggap NaNsuatu numbersehingga Anda harus secara manual menjaga kemudian dengan Number.isNaN(value).

Solusi lain yang disarankan, menggunakan Object.getPrototypeOf gagal dengan nulldanundefined

Menggunakan konstruktor

Șerban Ghiță
sumber
0

Saya mengumpulkan utilitas pemeriksaan tipe kecil yang terinspirasi oleh jawaban yang benar di atas:

thetypeof = function(name) {
        let obj = {};
        obj.object = 'object Object'
        obj.array = 'object Array'
        obj.string = 'object String'
        obj.boolean = 'object Boolean'
        obj.number = 'object Number'
        obj.type = Object.prototype.toString.call(name).slice(1, -1)
        obj.name = Object.prototype.toString.call(name).slice(8, -1)
        obj.is = (ofType) => {
            ofType = ofType.toLowerCase();
            return (obj.type === obj[ofType])? true: false
        }
        obj.isnt = (ofType) => {
            ofType = ofType.toLowerCase();
            return (obj.type !== obj[ofType])? true: false
        }
        obj.error = (ofType) => {
            throw new TypeError(`The type of ${name} is ${obj.name}: `
            +`it should be of type ${ofType}`)
        }
        return obj;
    };

contoh:

if (thetypeof(prop).isnt('String')) thetypeof(prop).error('String')
if (thetypeof(prop).is('Number')) // do something
Abraham Juliot
sumber
1
Tampaknya tidak berfungsi untuk objek yang nullatau undefinedatau trueataufalse
Julian Knight