Cách chính xác nhất để kiểm tra loại đối tượng JS?


137

Các typeofnhà điều hành không thực sự giúp chúng ta tìm ra loại thực sự của một đối tượng.

Tôi đã thấy đoạn mã sau:

Object.prototype.toString.apply(t)  

Câu hỏi:

Đó có phải là hầu hết các con đường chính xác của kiểm tra kiểu của đối tượng?


2
Hãy xem bài viết này: javascriptweblog.wordpress.com/2011/08/08/
Khăn

4
Nhìn vào bài đăng này: stackoverflow.com/questions/332422/ trên
isJustMe


3
Cách chính xác nhất là ... không kiểm tra loại. Tại sao bạn cần các loại?
hugomg

Object.prototype.toString.call / Object.prototype.toString.apply
xgqfrms

Câu trả lời:


190

Đặc tả JavaScript cung cấp chính xác một cách thích hợp để xác định lớp của một đối tượng:

Object.prototype.toString.call(t);

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


5
Nếu bạn đang tìm kiếm một loại cụ thể, bạn có thể muốn làm một cái gì đó dọc theo dòng: Object.prototype.toString.call(new FormData()) === "[object FormData]"đó sẽ là sự thật. Bạn cũng có thể sử dụng slice(8, -1)để quay lại FormDatathay vì[object FormData]
Chris Marisic

4
Có sự khác biệt nào giữa việc sử dụng Object.prototype{}không?
GetFree

3
có thể điều này đã thay đổi qua nhiều năm, nhưng Object.prototype.toString.call(new MyCustomObject())trở lại [object Object]trong khi new MyCustomObject() instanceOf MyCustomObject returns trueđó là điều tôi muốn (Chrome 54.0.2840.99 m)
Maslow

@Maslow, tôi đã gặp phải vấn đề tương tự mà bạn đưa ra. Sau khi xem qua một số tài liệu trực tuyến, tôi đã kết thúc việc sử dụng new MyCustomObject().constructor === MyCustomObject.
solstice333 ngày

3
Nó đặt ra câu hỏi, tại sao họ không bọc mã này theo một phương thức thuận tiện hơn hoặc cho phép một toán tử bổ sung biên dịch cho mã này. Tôi biết bạn chỉ là người đưa tin, nhưng khá thẳng thắn đó là khủng khiếp.
Andrew S

60

đó Object.prototype.toStringlà một cách tốt, nhưng hiệu suất của nó là tồi tệ nhất.

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

kiểm tra hiệu suất loại js

Sử dụng typeofđể giải quyết một số vấn đề cơ bản (Chuỗi, Số, Boolean ...) và sử dụng Object.prototype.toStringđể giải quyết một vấn đề phức tạp (như Mảng, Ngày, RegExp).

và đây là giải pháp của tôi:

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

sử dụng như là:

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

Thử nghiệm đó trên jsPerf không hoàn toàn chính xác. Những thử nghiệm đó không bằng nhau (thử nghiệm cho cùng một thứ). Ví dụ, typeof [] trả về "object", typeof {} cũng trả về "object", mặc dù một cái là một mảng đối tượng và cái kia là một đối tượng Object. Có nhiều vấn đề khác với bài kiểm tra đó ... Hãy cẩn thận khi xem jsPerf rằng các bài kiểm tra đang so sánh Táo với Táo.
kmatheny

typeChức năng của bạn là tốt, nhưng nhìn vào cách nó làm so với một số typechức năng khác . http://jsperf.com/code-type-test-a-test
Progo

18
Những số liệu hiệu suất nên được tôi luyện với một số ý nghĩa thông thường. Chắc chắn, nguyên mẫu.toString chậm hơn các loại khác theo độ lớn, nhưng trong sơ đồ lớn của mọi thứ, trung bình mất vài trăm nano giây mỗi cuộc gọi. Trừ khi cuộc gọi này đang được sử dụng trong một đường dẫn quan trọng được thực hiện rất thường xuyên, điều này có thể vô hại. Tôi muốn có mã chuyển tiếp thẳng hơn mã hoàn thành nhanh hơn một micro giây.
David

({}).toString.call(obj)chậm hơn Object.prototype.toString jsperf.com/object-check-test77
timaschew

Giải pháp tốt đẹp. Tôi mượn chức năng của bạn vào lib của tôi :)
Dong Nguyen

19

Câu trả lời được chấp nhận là chính xác, nhưng tôi muốn xác định tiện ích nhỏ này trong hầu hết các dự án tôi xây dựng.

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]',
}

Được sử dụng như thế này:

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

}

Nếu bạn đang sử dụng góc, bạn thậm chí có thể tiêm sạch:

angular.constant('types', types);

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

Giữ một tay cầm trên nguyên mẫu mà bạn mong muốn đối tượng có, sau đó so sánh với nó.

ví dụ

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

Làm thế nào là tốt hơn / khác hơn so với nói o instanceof String; //true?
Jamie Treworgy

@jamietre vì "foo" instanceof Stringphá vỡ
Raynos

OK, vì vậy "typeof (o) === 'object' && o instanceof someObject". Thật dễ dàng để kiểm tra các chuỗi. Có vẻ như là việc làm thêm, mà không giải quyết vấn đề cơ bản là phải biết trước những gì bạn đang kiểm tra.
Jamie Treworgy

Xin lỗi, đoạn mã đó không có ý nghĩa gì nhưng tôi nghĩ bạn biết ý tôi là gì, nếu bạn đang kiểm tra chuỗi, thì hãy sử dụng typeof(x)==='string'thay thế.
Jamie Treworgy

BTW, Object.getPrototypeOf(true)không (true).constructortrả lại được Boolean.
katspaugh

5

Tôi cho rằng hầu hết các giải pháp được trình bày ở đây đều bị quá kỹ sư. Có lẽ cách đơn giản nhất để kiểm tra xem giá trị có thuộc loại hay không [object Object]là kiểm tra đối với thuộc .constructortính của nó:

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

hoặc thậm chí ngắn hơn với các chức năng mũi tên:

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

Phần a != nullnày là cần thiết bởi vì người ta có thể chuyển vào nullhoặc undefinedbạn không thể trích xuất thuộc tính của hàm tạo từ một trong hai thuộc tính này.

Nó hoạt động với bất kỳ đối tượng nào được tạo thông qua:

  • người Objectxây dựng
  • chữ {}

Một tính năng thú vị khác của nó là khả năng đưa ra các báo cáo chính xác cho các lớp tùy chỉnh sử dụng Symbol.toStringTag. Ví dụ:

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

Vấn đề ở đây là khi gọi Object.prototype.toStringmột thể hiện của nó, báo cáo sai [object Object]sẽ được trả về:

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

Nhưng kiểm tra đối với các nhà xây dựng cho một kết quả chính xác:

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

4

Cách tốt nhất để tìm ra loại REAL của một đối tượng (bao gồm cả HAI đối tượng gốc hoặc tên DataType (chẳng hạn như String, Date, Number, ..etc) VÀ loại REAL của một đối tượng (thậm chí là tùy chỉnh); thuộc tính tên của hàm tạo của đối tượng:

Kiểu bản địa Ex1:

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

hiển thị:

String

Ex2:

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

hiển thị:

Array

Các lớp tùy chỉnh:

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

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

hiển thị:

CustomClass

Điều này thất bại nếu đối tượng là nullhoặc undefined.
Julian Knight

2

Câu hỏi cũ tôi biết. Bạn không cần phải chuyển đổi nó. Xem chức năng này:

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;

}; 

Ví dụ:

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

Chi phí thấp và đơn giản.


Trả về falsenếu đối tượng thử nghiệm là nullhoặcundefined
Julian Knight

hoặc truehoặcfalse
Julian Knight

@JulianKnight false là ổn ở null hoặc không xác định, nó không có gì hữu ích. Vậy vấn đề là gì?
Codebeat

ví dụ của bạn trả về dữ liệu không nhất quán. Một số kết quả là kiểu dữ liệu và những kết quả khác là giá trị false. Làm thế nào điều này giúp trả lời câu hỏi?
Julian Knight

1
@JulianKnight Xem thay đổi, đó có phải là điều bạn muốn không? Nếu bạn thích không xác định hoặc "không xác định" là kết quả, bạn có thể thay thế sai cuối cùng nếu bạn muốn.
Codebeat

0

Tôi kết hợp một tiện ích kiểm tra loại nhỏ lấy cảm hứng từ các câu trả lời đúng ở trên:

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

thí dụ:

if (thetypeof(prop).isnt('String')) thetypeof(prop).error('String')
if (thetypeof(prop).is('Number')) // do something

Không có vẻ làm việc cho đối tượng là nullhay undefinedhay truehayfalse
Julian Hiệp sĩ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.