2011-10-25 14 views
95

Operator typeof tak naprawdę nie pomaga nam w znalezieniu prawdziwego typu obiektu.Najbardziej dokładny sposób sprawdzenia typu obiektu JS?

Już widziałem następujący kod:

Object.prototype.toString.apply(t) 

Pytanie:

Czy to najbardziej dokładny sposób sprawdzania typu obiektu?

+2

Zapraszamy do obejrzenia tego artykułu: http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ –

+4

Spójrz na ten post: http: //stackoverflow.com/questions/332422/how-do-i-get-the-name-of-an-objects-type-in-javascript – isJustMe

+0

http://tobyho.com/2011/01/28/checking- types-in-javascript/ – airportyh

Odpowiedz

129

Specyfikacja JavaScript daje dokładnie jeden właściwy sposób określić klasę obiektu:

Object.prototype.toString.call(t); 

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

+3

Jeśli szukasz określonego typu, prawdopodobnie chcesz zrobić coś w stylu: Object.prototype.toString.call (new FormData()) === "[object FormData]", co byłoby prawdą . Możesz także użyć 'slice (8, -1)', aby zwrócić 'FormData' zamiast' [object FormData] ' –

+3

Czy istnieje jakaś różnica między używaniem' Object.prototype' i '{}'? – GetFree

+3

Może to się zmieniło przez lata, ale 'Object.prototype.toString.call (new MyCustomObject())' zwraca '[Object Object]' podczas gdy 'new MyCustomObject() instanceOf MyCustomObject zwraca true' co jest tym czego chciałem (Chrome 54.0.2840.99 m) – Maslow

9
var o = ... 
var proto = Object.getPrototypeOf(o); 
proto === SomeThing; 

Trzymać uchwyt na prototypie można oczekiwać obiekt, aby mieć, a następnie porównać przeciwko niemu.

np

var o = "someString"; 
var proto = Object.getPrototypeOf(o); 
proto === String.prototype; // true 
+0

Jak to jest lepsze/inne niż wypowiadanie 'o instanceof String; // true'? –

+0

@jamietre ponieważ '" foo "instanceof String' breaks – Raynos

+0

OK, więc" typeof (o) === 'object' && o instanceof SomeObject ". Łatwo jest przetestować ciągi. Wydaje się, że jest to dodatkowa praca, bez rozwiązania podstawowego problemu konieczności wcześniejszego sprawdzenia, co testujesz. –

52

Object.prototype.toString to dobry sposób, ale jego wydajność jest najgorsza.

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

check js type performance

Zastosowanie typeof rozwiązać podstawowe problemy (String, Number, Boolean ...) i używać Object.prototype.toString rozwiązać coś złożonego (jak Array, data, RegExp).

i to jest moje rozwiązanie:

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

zastosowanie jako:

type(function(){}); // -> "function" 
type([1, 2, 3]); // -> "array" 
type(new Date()); // -> "date" 
type({}); // -> "object" 
+0

Ten test na jsPerf nie jest całkiem dokładny. Te testy nie są równe (testowanie na to samo). Na przykład, typeof [] zwraca "object", typeof {} również zwraca "object", mimo że jeden jest obiektem Array, a drugi jest obiektem Object. Jest wiele innych problemów z tym testem ... Uważaj, patrząc na jsPerf, że testy porównują jabłka z jabłkami. – kmatheny

+0

Twoja funkcja 'type' jest dobra, ale spójrz na jej działanie w porównaniu do innych funkcji' type'. [http://jsperf.com/code-type-test-a-test](http://jsperf.com/code-type-test-a-test) – Progo

+13

Te wskaźniki wydajności powinny być hartowane z pewnym zdrowiem. Oczywiście, prototype.toString jest wolniejszy od innych o rząd wielkości, ale w wielkim układzie rzeczy zajmuje średnio kilkaset * nanosekund * na połączenie. O ile połączenie to nie jest wykorzystywane w krytycznej ścieżce, która jest bardzo często wykonywana, prawdopodobnie jest to nieszkodliwe. Wolałbym mieć prosty kod niż kod, który kończy się o mikrosekundę szybciej. – David

7

Akceptowane odpowiedź jest poprawna, ale chciałbym, aby zdefiniować tę małą przydatność w większości projektów buduję.

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

Używane tak:

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

} 

Jeśli używasz kątowe można nawet to czysto wstrzykiwany:

angular.constant('types', types); 
0

ułożyła małą użyteczność wyboru typu Zainspirowany powyżej prawidłowych odpowiedzi:

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

przykład:

if (thetypeof(prop).isnt('String')) thetypeof(prop).error('String') 
if (thetypeof(prop).is('Number')) // do something 
Powiązane problemy