Lấy tên của loại đối tượng


1193

JavaScript tương đương với Java s' class.getName()?


Câu hỏi này giả định rằng chúng ta biết class.getName () của Java làm gì. Vì tôi không chắc chắn nếu câu trả lời sẽ giúp tôi.
user34660

2
@ user34660 Tôi nghĩ rằng chúng ta có thể giả định một cách an toàn rằng những gì nó làm là lấy tên của một loại đối tượng.
Stack Underflow

1
@StackUnderflow: Ngoại trừ, nó thực sự không. Nó được tên của một đối tượng lớp , đó là không giống như của một đối tượng kiểu .
Jörg W Mittag

1
@ JörgWMittag À, tất nhiên rồi. Ya xem điều gì xảy ra khi bạn đi xung quanh giả định mọi thứ một cách an toàn?
Stack Underflow

Câu trả lời:


1540

Có JavaScript tương đương với Java class.getName()không?

Không .

Cập nhật ES2015 : tên của class Foo {}Foo.name . Tên của thinglớp, bất kể thingloại nào, là thing.constructor.name. Các nhà xây dựng dựng sẵn trong môi trường ES2015 có thuộc tính chính xác name; ví dụ (2).constructor.name"Number".


Nhưng đây là những bản hack khác nhau mà tất cả đều rơi xuống bằng cách này hay cách khác:

Đây là một bản hack sẽ làm những gì bạn cần - lưu ý rằng nó sửa đổi nguyên mẫu của Object, thứ mà mọi người cau mày (thường là vì lý do chính đáng)

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

Bây giờ, tất cả các đối tượng của bạn sẽ có hàm, getName()sẽ trả về tên của hàm tạo dưới dạng một chuỗi. Tôi đã thử nghiệm điều này FF3IE7, tôi không thể nói cho các triển khai khác.

Nếu bạn không muốn làm điều đó, đây là một cuộc thảo luận về các cách xác định các loại khác nhau trong JavaScript ...


Gần đây tôi đã cập nhật điều này để hoàn thiện hơn một chút, mặc dù điều đó khó xảy ra. Sửa chữa chào mừng ...

Sử dụng constructortài sản ...

Mỗi cái đều objectcó một giá trị cho thuộc tính của nó constructor, nhưng tùy thuộc vào cách nó objectđược xây dựng cũng như những gì bạn muốn làm với giá trị đó, nó có thể có hoặc không hữu ích.

Nói chung, bạn có thể sử dụng thuộc constructortính để kiểm tra loại đối tượng như vậy:

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

Vì vậy, nó hoạt động đủ tốt cho hầu hết các nhu cầu. Mà nói...

Hãy cẩn thận

Sẽ không hoạt động TẠI TẤT CẢ trong nhiều trường hợp

Mẫu này, mặc dù bị hỏng, khá phổ biến:

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

Objectsxây dựng thông qua new Thingysẽ có một constructortài sản mà trỏ đến Object, không Thingy. Vì vậy, chúng tôi rơi ngay từ đầu; bạn chỉ đơn giản là không thể tin tưởng constructorvào một cơ sở mã mà bạn không kiểm soát.

Đa kế thừa

Một ví dụ không rõ ràng là sử dụng nhiều kế thừa:

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

Mọi thứ bây giờ không hoạt động như bạn có thể mong đợi:

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

Vì vậy, bạn có thể nhận được kết quả không mong muốn nếu objectthử nghiệm của bạn có một objectbộ khác prototype. Có nhiều cách xung quanh vấn đề này ngoài phạm vi của cuộc thảo luận này.

Có những cách sử dụng khác cho constructortài sản, một số trong số chúng thú vị, một số khác không quá nhiều; bây giờ chúng tôi sẽ không đi sâu vào những sử dụng đó vì nó không liên quan đến cuộc thảo luận này.

Sẽ không làm việc chéo khung và cửa sổ chéo

Việc sử dụng .constructorđể kiểm tra loại sẽ bị hỏng khi bạn muốn kiểm tra loại đối tượng đến từ các windowđối tượng khác nhau , giả sử đó là iframe hoặc cửa sổ bật lên. Điều này là do có một phiên bản khác nhau của từng loại lõi constructortrong mỗi 'cửa sổ', nghĩa là

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

Sử dụng instanceoftoán tử ...

Các instanceofnhà điều hành là một cách sạch sẽ thử nghiệm objectloại là tốt, nhưng có vấn đề về tiềm năng riêng của mình, giống như constructorbất động sản.

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

Nhưng instanceofkhông hoạt động cho các giá trị nghĩa đen (vì nghĩa đen là không Objects)

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

Các chữ cần phải được bọc trong một Objecttheo thứ tự cho instanceofđến công việc, ví dụ

new Number(3) instanceof Number // true

Các .constructorkiểm tra hoạt động tốt cho literals vì .phương pháp gọi trình ngầm kết thúc tốt đẹp các literals trong loại đối tượng tương ứng của họ

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

Tại sao hai dấu chấm cho 3? Bởi vì Javascript diễn giải dấu chấm đầu tiên dưới dạng dấu thập phân;)

Sẽ không làm việc chéo khung và cửa sổ chéo

instanceofcũng sẽ không hoạt động trên các cửa sổ khác nhau, vì lý do tương tự như constructorkiểm tra tài sản.


Sử dụng nametài sản của constructortài sản ...

Không hoạt động TẠI TẤT CẢ trong nhiều trường hợp

Một lần nữa, xem ở trên; nó khá phổ biến đối với constructorviệc hoàn toàn sai lầm và hoàn toàn sai lầm và vô dụng.

KHÔNG hoạt động trong <IE9

Việc sử dụng myObjectInstance.constructor.namesẽ cung cấp cho bạn một chuỗi chứa tên của constructorhàm được sử dụng, nhưng phải chịu sự cảnh báo về thuộc constructortính đã được đề cập trước đó.

Đối với IE9 trở lên, bạn có thể hỗ trợ khỉ :

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

Phiên bản cập nhật từ bài viết trong câu hỏi. Điều này đã được thêm 3 tháng sau khi bài báo được xuất bản, đây là phiên bản được đề xuất để sử dụng bởi tác giả của bài báo Matthew Scharley. Thay đổi này được lấy cảm hứng từ các bình luận chỉ ra những cạm bẫy tiềm ẩn trong mã trước đó.

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

Sử dụng Object.prototype.toString

Hóa ra, như chi tiết bài đăng này , bạn có thể sử dụng Object.prototype.toString- mức độ thấp và triển khai chung của toString- để lấy loại cho tất cả các loại tích hợp

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

Người ta có thể viết một hàm trợ giúp ngắn như

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

để loại bỏ cruft và chỉ nhận được tên loại

type('abc') // String

Tuy nhiên, nó sẽ trả về Objectcho tất cả các loại do người dùng xác định.


Hãy cẩn thận cho tất cả ...

Tất cả những điều này phải chịu một vấn đề tiềm ẩn, và đó là câu hỏi về cách đối tượng trong câu hỏi được xây dựng. Dưới đây là các cách khác nhau để xây dựng các đối tượng và các giá trị mà các phương thức kiểm tra loại khác nhau sẽ trả về:

// 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

Mặc dù không phải tất cả các hoán vị đều có trong tập hợp các ví dụ này, hy vọng có đủ để cung cấp cho bạn ý tưởng về cách mọi thứ lộn xộn có thể nhận được tùy thuộc vào nhu cầu của bạn. Đừng giả sử bất cứ điều gì, nếu bạn không hiểu chính xác những gì bạn đang theo đuổi, bạn có thể sẽ bị phá mã, nơi bạn không mong đợi điều đó vì thiếu suy nghĩ về sự tinh tế.

GHI CHÚ:

Thảo luận về typeoftoán tử có thể là một thiếu sót rõ ràng, nhưng nó thực sự không hữu ích trong việc giúp xác định xem một loại có phải objectlà một loại nhất định hay không, vì nó rất đơn giản. Hiểu nơi nào typeofhữu ích là điều quan trọng, nhưng hiện tại tôi không cảm thấy rằng nó có liên quan khủng khiếp đến cuộc thảo luận này. Tâm trí của tôi là mở để thay đổi mặc dù. :)


58
Chà, tôi nghĩ rằng tôi cũng có thể - quan điểm của Stack Overflow là hơi giống với wiki, và điều này phù hợp hơn nhiều với ý định đó, tôi nghĩ vậy. Bất kể, tôi chỉ muốn được phần nào kỹ lưỡng.
Jason Bunting

Lặp lại một câu trả lời bên dưới --- phần mở rộng của bạn cho nguyên mẫu Object không hoạt động trong IE8 - có ai biết cái gì sẽ hoạt động trong IE8 không?
Adam

5
Nó sẽ hoạt động nếu bạn làm nó như hàm này a () {this.a = 1;} hàm b () {this.b = 2; } b.prototype = new a (); // b kế thừa từ một b.prototype.constructor = b; // Cách chính xác của thừa kế nguyên mẫu var f = new b (); // tạo đối tượng mới với hàm tạo b (f.constructor == b); // TRUE (f.constructor == a); // SAI
Boris Hamanov

9
Bây giờ, đây là cách hầu hết các câu trả lời nên có trên StackOverflow. (không lấy độ dài của câu trả lời làm tham số xác định, nhưng tính toàn diện)
kumarharsh

44
Điều quan trọng cần lưu ý là mọi kỹ thuật kiểm tra constructorphương thức của đối tượng (có .toString()hoặc .name) sẽ không hoạt động nếu Javascript của bạn đã được thu nhỏ bằng một công cụ như uglify hoặc đường dẫn tài sản Rails. Việc thu nhỏ đổi tên hàm tạo, vì vậy bạn sẽ kết thúc với tên lớp không chính xác như thế nào n. Nếu bạn đang ở trong kịch bản này, bạn có thể chỉ muốn xác định thủ công một thuộc classNametính trên các đối tượng của mình và sử dụng thay thế đó.
Gabe Martin-Dempesy

126

Câu trả lời của Jason Bunting đã cho tôi đủ manh mối để tìm ra thứ tôi cần:

<<Object instance>>.constructor.name

Vì vậy, ví dụ, trong đoạn mã sau:

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

myInstance.constructor.namesẽ quay trở lại "MyObject".


22
Để đầy đủ, có thể đáng nói đến việc sử dụng constructor.name chỉ hoạt động nếu bạn đã sử dụng một hàm được đặt tên là hàm tạo thay vì một hàm ẩn danh được gán cho một biến.
Matthew Crumley

20
Để đầy đủ, có thể đáng nói là nó không hoạt động trong trình duyệt IE --- chúng không hỗ trợ thuộc tính "name" trên các hàm.
Eugene Lazutkin

2
@Eugene - Tôi quên mất điều đó ... Tôi đoán tôi đã dành quá nhiều thời gian để làm javascript bên ngoài trình duyệt.
Matthew Crumley

2
function getType(o) { return o && o.constructor && o.constructor.name }
justin.m.chase

Đây là SO toàn diện.
ibic

26

Một mẹo nhỏ tôi sử dụng:

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

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

11
Tôi không đặc biệt thích điều này. Đó là một loại mánh khóe bẩn thỉu hơn. Mặt khác, nếu bạn không có quá nhiều nhà xây dựng, nó có thể hoạt động tốt.
pimvdb

13
@pimvdb: Tôi nghĩ rằng nó sạch hơn là sửa đổi nguyên mẫu của đối tượng, đó là câu trả lời được chấp nhận.
Daniel Szabo

4
@DanielSzabo nếu một thuộc tính nên có cùng giá trị giữa tất cả các phiên bản của một nguyên mẫu, tôi chắc chắn thích chỉ đưa nó vào nguyên mẫu - đặt nó trên mỗi phiên bản là siêu dự phòng và siêu dữ liệu bị thiếu từ chính nguyên mẫu. Điều đó nói rằng, giải pháp khôn ngoan nhất đã được áp dụng trong ES6: nếu bạn có class Square, tên là Square.name/ MySquare.constructor.namechứ không phải Square.prototype.name; bằng cách đưa namevào hàm xây dựng, nó không gây ô nhiễm nguyên mẫu hoặc bất kỳ trường hợp nào, nhưng có thể truy cập được từ một trong hai.
Andy

17

Cập nhật

Nói chính xác, tôi nghĩ OP đã yêu cầu một hàm lấy tên hàm tạo cho một đối tượng cụ thể. Về mặt Javascript, objectkhông có một loại mà là một loại và bản thân nó . Tuy nhiên, các đối tượng khác nhau có thể có các nhà xây dựng khác nhau .

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"

 


Lưu ý: ví dụ dưới đây không được dùng nữa.

Một bài đăng trên blog được liên kết bởi Christian Sciberras chứa một ví dụ hay về cách thực hiện. Cụ thể, bằng cách mở rộng nguyên mẫu 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

2
Thật tuyệt, nhưng chúng ta lại đặt tên một lần nữa: JS không có lớp.
mikemaccana

@nailer - Tôi khuyên bạn nên sử dụng chức năng cập nhật, chức năng cũ hơn được giữ vì lý do lịch sử.
Saul

Điều này hoạt động nhưng cần lưu ý rằng nó có thể được thực hiện mà không cần sửa đổi Object.prototype, bằng cách tạo một hàm lấy đối tượng làm đối số đầu tiên và sử dụng thay vì 'this' bên trong hàm.
Matt Browne

2
@Matt - Chắc chắn rồi. Nó chỉ là rằng có một phương pháp đối tượng là ngắn gọn hơn: test.getClassName()vs getClassName.apply(test).
Saul

12

Sử dụng Object.prototype.toString

Hóa ra, vì chi tiết bài đăng này, bạn có thể sử dụng Object.prototype.toString - mức độ thấp và triển khai chung của toString - để lấy loại cho tất cả các loại tích hợp

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

Người ta có thể viết một hàm trợ giúp ngắn như

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

6
Bạn không cần sử dụng regex để phân tích tên đối tượng. Chỉ cần sử dụng .slice():Object.prototype.toString.call(obj).slice( 8, -1 );
bobobobo

9

Đây là một giải pháp mà tôi đã đưa ra để giải quyết những thiếu sót của thể hiện. Nó có thể kiểm tra các loại đối tượng từ các cửa sổ chéo và khung chéo và không gặp vấn đề với các kiểu nguyên thủy.

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 yêu cầu hai tham số: một đối tượng và một loại. Bí quyết thực sự về cách thức hoạt động của nó là kiểm tra xem đối tượng có ở cùng một cửa sổ không và nếu không có cửa sổ của đối tượng.

Ví dụ:

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

Đối số kiểu cũng có thể là hàm gọi lại trả về hàm tạo. Hàm gọi lại sẽ nhận được một tham số là cửa sổ của đối tượng được cung cấp.

Ví dụ:

//"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

Một lưu ý là IE <9 không cung cấp hàm tạo trên tất cả các đối tượng nên thử nghiệm trên cho NodeList sẽ trả về false và cũng là isInstance (cảnh báo, "Hàm") sẽ trả về false.


8

Tôi đã thực sự tìm kiếm một điều tương tự và đã gặp câu hỏi này. Đây là cách tôi có được các loại: 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);
}

7

Bạn nên sử dụng somevar.constructor.namenhư một:

    
    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'


6

Sử dụng constructor.namekhi bạn có thể, và chức năng regex khi tôi không thể.

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

6

Hàm kind () từ Agave.JS sẽ trả về:

  • nguyên mẫu gần nhất trong cây thừa kế
  • đối với các loại luôn luôn nguyên thủy như 'null' và 'không xác định', tên nguyên thủy.

Nó hoạt động trên tất cả các đối tượng và nguyên thủy của JS, bất kể chúng được tạo như thế nào và không có bất kỳ sự ngạc nhiên nào. Ví dụ:

Số

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'

Dây

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

Booleans

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

Mảng

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

Các đối tượng

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

ngày

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

Chức năng

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

chưa xác định

kind(undefined) === 'undefined'

vô giá trị

kind(null) === 'null'

5

Bạn có thể sử dụng instanceoftoán tử để xem nếu một đối tượng là một thể hiện của một đối tượng khác, nhưng vì không có lớp nào, bạn không thể có được một tên lớp.


Mặc dù đúng là JavaScript không có các lớp như ngôn ngữ xây dựng, nhưng quy ước chung vẫn là một loại đối tượng được gọi là một lớp ..
Saul

2
@greg Chắc chắn nhưng instanceofchỉ kiểm tra xem một đối tượng có kế thừa từ các đối tượng khác hay không. Ví dụ, một []kế thừa đơn giản từ Array, nhưng Array cũng thừa hưởng từ Object. Vì hầu hết các đối tượng có nhiều cấp độ kế thừa, việc tìm ra nguyên mẫu gần nhất là một kỹ thuật tốt hơn. Xem câu trả lời của tôi để làm thế nào.
mikemaccana

4

Đây là một triển khai dựa trên câu trả lời được chấp nhận :

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

Chúng tôi chỉ sử dụng thuộc tính constructor khi chúng tôi không có lựa chọn nào khác.


3

Bạn có thể sử dụng toán tử "instanceof" để xác định xem một đối tượng có phải là một thể hiện của một lớp nhất định hay không. Nếu bạn không biết tên của loại đối tượng, bạn có thể sử dụng thuộc tính hàm tạo của nó. Thuộc tính constructor của các đối tượng, là một tham chiếu đến hàm được sử dụng để khởi tạo chúng. Thí dụ:

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

Bây giờ c1.constructor là một tham chiếu đến Circle()hàm. Bạn có thể sử dụng typeoftoán tử, nhưng typeoftoán tử hiển thị thông tin hạn chế. Một giải pháp là sử dụng toString()phương thức của đối tượng toàn cầu Object. Ví dụ: nếu bạn có một đối tượng, giả sử myObject, bạn có thể sử dụng toString()phương thức của Đối tượng toàn cầu để xác định loại lớp của myObject. Dùng cái này:

Object.prototype.toString.apply(myObject);

3

Nói rằng bạn có var obj;

Nếu bạn chỉ muốn tên của loại obj, như "Đối tượng", "Mảng" hoặc "Chuỗi", bạn có thể sử dụng tên này:

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

2

Gần nhất bạn có thể nhận được typeof, nhưng nó chỉ trả về "đối tượng" cho bất kỳ loại tùy chỉnh nào. Đối với những người, xem Jason Bunting .

Chỉnh sửa, Jason đã xóa bài đăng của mình vì một số lý do, vì vậy chỉ cần sử dụng constructortài sản của Object .


Vâng, xin lỗi - tôi đã xóa nó bởi vì tôi nghĩ instanceof () là một cách tốt hơn để làm mọi thứ, nhưng tôi chỉ xóa bỏ nó để nó có thể phục vụ như một tài liệu tham khảo.
Jason Bunting

2
Câu trả lời ít hơn hoàn hảo vẫn hữu ích, nếu chỉ cho người khác đến câu hỏi sau vì họ có một vấn đề tương tự. Vì vậy, bạn thực sự không nên xóa chúng. Lưu xóa cho câu trả lời sai.
sblundy

2
Vâng, tôi biết - bạn đang giảng cho dàn hợp xướng, tôi đã nói chính xác điều tương tự với người khác. Sống những điều mà chúng ta biết là đúng thường khó hơn vẻ ngoài của nó. :)
Jason Bunting

0

Nếu bất cứ ai đang tìm kiếm một giải pháp đang hoạt động với jQuery, thì đây là mã wiki được điều chỉnh (bản gốc phá vỡ 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] : "";
    }
});

Vâng, jQuery không thực hiện kiểm tra 'hasOwnProperty' và vì vậy liệt kê getNamevà rơi xuống.
nicodemus13

0

Lodash có nhiều isMethods vì vậy nếu bạn đang sử dụng Lodash, có thể một mixin như thế này có thể hữu ích:

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

Nó thêm một phương thức vào lodash gọi là "xác định" hoạt động như sau:

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

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


0

Ok, mọi người, tôi đã dần dần xây dựng một phương pháp bắt tất cả cho việc này trong vài năm qua lol! Bí quyết là:

  1. Có cơ chế tạo lớp.
  2. Có một cơ chế để kiểm tra tất cả các lớp, nguyên thủy và giá trị do người dùng tạo / tạo bởi các hàm tạo riêng.
  3. Có một cơ chế để mở rộng các lớp do người dùng tạo thành các lớp mới để chức năng trên thấm qua mã / ứng dụng / thư viện / vv của bạn.

Để biết ví dụ (hoặc để xem cách tôi xử lý vấn đề), hãy xem đoạn mã sau trên github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js và tìm kiếm:

classOf =, classOfIs =và hoặc defineSubClass =(không có backticks (`)).

Như bạn có thể thấy tôi có một số cơ chế bắt buộc classOfphải luôn cung cấp cho tôi tên loại lớp / hàm tạo bất kể đó là lớp nguyên thủy, lớp do người dùng định nghĩa, giá trị được tạo bằng hàm tạo gốc, Null, NaN, v.v. Đối với mỗi giá trị javascript duy nhất tôi sẽ nhận được tên loại duy nhất từ classOfhàm. Ngoài ra, tôi có thể chuyển các hàm tạo thực tế vàosjl.classOfIs để kiểm tra loại giá trị ngoài việc có thể chuyển cả tên loại của nó! Ví dụ:

`` `// Xin vui lòng tha thứ cho không gian tên dài! Tôi không có ý tưởng về tác động cho đến khi sử dụng chúng một thời gian (họ hút 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`!

`` `

Nếu bạn muốn đọc thêm về cách tôi sử dụng thiết lập được đề cập ở trên, hãy xem repo: https://github.com/elycruz/sjljs

Ngoài ra các cuốn sách có nội dung về chủ đề: - "Các mẫu JavaScript" của Stoyan Stefanov. - "Javascript - Hướng dẫn dứt khoát." của David Flanagan. - và nhiều người khác .. (tìm kiếm trang web).

Ngoài ra, bạn có thể nhanh chóng kiểm tra các tính năng tôi đang nói ở đây: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (cũng là đường dẫn 0,5,18 trong url có các nguồn từ github trên đó trừ đi node_modules và như vậy).

Chúc mừng mã hóa!


0

Khá đơn giản!

  • Phương thức yêu thích của tôi để có được loại bất cứ thứ gì trong JS
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • phương pháp yêu thích của tôi để kiểm tra loại bất cứ thứ gì trong JS
function checkType(entity, type){
    return getType(entity) === type
}

-1

Sử dụng class.name. Điều này cũng làm việc với function.name.

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

function TestB() {}
console.log(TestB.name); // "TestB"

Câu hỏi nói rõ ràng classvà không ví dụ.
qwertzguy
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.