รับชื่อประเภทของวัตถุ


1193

มีJavaScriptเทียบเท่าJava 's class.getName()?


คำถามนี้ทำให้เรารู้ว่า class.getName () ของ Java ทำอะไร เนื่องจากฉันไม่แน่ใจว่าคำตอบจะช่วยฉันได้หรือไม่
user34660

2
@ user34660 ฉันคิดว่าเราสามารถสรุปได้อย่างปลอดภัยว่าสิ่งใดที่ทำให้ชื่อของวัตถุเป็นประเภท
Stack Underflow

1
@StackUnderflow: ยกเว้นจริง ๆ แล้วมันไม่ได้ จะได้รับชื่อของวัตถุนั้นชั้นซึ่งเป็นไม่ได้เช่นเดียวกับวัตถุชนิด
Jörg W Mittag

1
@ JörgWMittag Ah ใช่แน่นอน คุณเห็นสิ่งที่เกิดขึ้นเมื่อคุณไปรอบ ๆ อย่างปลอดภัยสมมติว่าสิ่งต่าง ๆ ?
Stack Underflow

คำตอบ:


1540

มีจาวาสคริปต์ที่เทียบเท่ากับ Java class.getName()หรือไม่?

ไม่

ES2015 ปรับปรุง : ชื่อของclass Foo {}Foo.nameมี ชื่อของthingคลาสไม่ว่าจะthingเป็นประเภทใดthing.constructor.nameก็ตาม ตัวสร้าง Builtin ในสภาพแวดล้อม ES2015 มีnameคุณสมบัติที่ถูกต้อง ตัวอย่างคือ(2).constructor.name"Number"


แต่นี่คือแฮ็กต่างๆที่ทุกอย่างตกลงไปในทางเดียว:

นี่คือแฮ็คที่จะทำสิ่งที่คุณต้องการโปรดระวังว่ามันดัดแปลงต้นแบบของ Object สิ่งที่ผู้คนขมวดคิ้ว (โดยปกติจะมีเหตุผลที่ดี)

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

ตอนนี้วัตถุทั้งหมดของคุณจะมีฟังก์ชั่นgetName()ซึ่งจะส่งกลับชื่อของตัวสร้างเป็นสตริง ฉันได้ทดสอบสิ่งนี้FF3แล้วและIE7ฉันไม่สามารถพูดถึงการปรับใช้อื่น ๆ ได้

หากคุณไม่ต้องการทำเช่นนี้ต่อไปนี้เป็นการอภิปรายเกี่ยวกับวิธีกำหนดประเภทต่างๆใน JavaScript ...


ฉันเพิ่งอัปเดตสิ่งนี้ให้ละเอียดขึ้นเล็กน้อยแม้ว่าจะแทบจะไม่ก็ตาม ยินดีต้อนรับการแก้ไข ...

กำลังใช้constructorคุณสมบัติ ...

ทุกคนobjectมีค่าสำหรับconstructorคุณสมบัติของมันแต่ขึ้นอยู่กับวิธีที่objectสร้างขึ้นรวมถึงสิ่งที่คุณต้องการจะทำกับค่านั้นมันอาจจะมีประโยชน์หรือไม่ก็ได้

โดยทั่วไปคุณสามารถใช้constructorคุณสมบัติเพื่อทดสอบชนิดของวัตถุดังนี้:

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

ดังนั้นจึงทำงานได้ดีพอสำหรับความต้องการส่วนใหญ่ ที่กล่าวว่า ...

คำเตือน

จะไม่ทำงานที่ทั้งหมดในหลายกรณี

รูปแบบนี้แม้ว่าจะแตกเป็นเรื่องธรรมดา:

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

Objectsสร้างผ่านnew Thingyจะมีconstructorคุณสมบัติที่ชี้ไปไม่ได้Object Thingyดังนั้นเราจึงล้มลงตั้งแต่เริ่มแรก คุณไม่สามารถไว้วางใจconstructorใน codebase ที่คุณไม่สามารถควบคุมได้

หลายมรดก

ตัวอย่างที่ไม่ชัดเจนว่าใช้หลายมรดก:

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

ตอนนี้สิ่งต่าง ๆ ไม่ทำงานอย่างที่คุณคาดหวัง:

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

ดังนั้นคุณอาจได้รับผลที่ไม่คาดคิดถ้าobjectการทดสอบของคุณมีที่แตกต่างกันชุดเป็นของตนobject prototypeมีวิธีแก้ไขปัญหานี้นอกขอบเขตของการสนทนานี้

มีการใช้งานอื่น ๆ สำหรับconstructorคุณสมบัติบางอย่างน่าสนใจอื่น ๆ ไม่มาก สำหรับตอนนี้เราจะไม่เจาะลึกการใช้เหล่านั้นเนื่องจากไม่เกี่ยวข้องกับการสนทนานี้

จะไม่ทำงานข้ามเฟรมและข้ามหน้าต่าง

การใช้.constructorสำหรับการตรวจสอบชนิดจะแตกเมื่อคุณต้องการตรวจสอบประเภทของวัตถุที่มาจากwindowวัตถุต่างๆ ให้พูดว่า iframe หรือหน้าต่างป๊อปอัป นี่เป็นเพราะมีคอร์แต่ละชนิดที่แตกต่างกันconstructorใน `หน้าต่าง 'แต่ละอันกล่าวคือ

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

กำลังใช้instanceofโอเปอเรเตอร์ ...

instanceofผู้ประกอบการเป็นวิธีการทำความสะอาดของการทดสอบobjectประเภทเช่นกัน แต่มีปัญหาที่อาจเกิดของตัวเองเช่นเดียวกับconstructorสถานที่ให้บริการ

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

แต่instanceofล้มเหลวในการทำงานกับค่าตัวอักษร (เพราะตัวอักษรไม่ได้Objects)

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

ตัวอักษรจะต้องห่อObjectในเพื่อที่instanceofจะทำงานเช่น

new Number(3) instanceof Number // true

การ.constructorตรวจสอบใช้งานได้ดีสำหรับตัวอักษรเนื่องจาก.การเรียกใช้เมธอดจะล้อมตัวอักษรในประเภทออบเจกต์ที่เกี่ยวข้องโดยปริยาย

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

ทำไมสองจุดสำหรับ 3 เพราะ Javascript ตีความจุดแรกเป็นทศนิยม;)

จะไม่ทำงานข้ามเฟรมและข้ามหน้าต่าง

instanceofจะไม่ทำงานในหน้าต่างที่แตกต่างกันด้วยเหตุผลเดียวกับการconstructorตรวจสอบคุณสมบัติ


กำลังใช้nameคุณสมบัติของconstructorคุณสมบัติ ...

ไม่ได้ทำงานที่ทั้งหมดในหลายกรณี

อีกครั้งดูด้านบน; เป็นเรื่องปกติconstructorที่จะผิดและไร้ประโยชน์โดยสิ้นเชิง

ไม่ทำงานใน <IE9

การใช้myObjectInstance.constructor.nameจะให้สตริงที่มีชื่อของconstructorฟังก์ชั่นที่ใช้ แต่ขึ้นอยู่กับคำเตือนเกี่ยวกับconstructorคุณสมบัติที่กล่าวถึงก่อนหน้านี้

สำหรับ IE9 ขึ้นไปคุณสามารถสนับสนุนMonkey-patch ได้ :

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

รุ่นที่ปรับปรุงจากบทความที่เป็นปัญหา นี่ถูกเพิ่ม 3 เดือนหลังจากตีพิมพ์บทความนี่เป็นรุ่นที่แนะนำให้ใช้โดย Matthew Scharley ผู้เขียนบทความ การเปลี่ยนแปลงนี้ได้รับแรงบันดาลใจจากความคิดเห็นที่ชี้ให้เห็นถึงข้อผิดพลาดที่อาจเกิดขึ้นในรหัสก่อนหน้า

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

ใช้ Object.prototype.toString

ปรากฎเป็นรายละเอียดโพสต์นี้คุณสามารถใช้Object.prototype.toString- ระดับต่ำและการใช้งานทั่วไปtoString- เพื่อรับประเภทสำหรับทุกประเภทในตัว

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

สามารถเขียนฟังก์ชั่นตัวช่วยสั้น ๆ เช่น

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

เพื่อลบ cruft และรับเพียงชื่อประเภท

type('abc') // String

อย่างไรก็ตามมันจะกลับมาObjectสำหรับประเภทที่ผู้ใช้กำหนดเองทั้งหมด


คำเตือนสำหรับทุกคน ...

ทั้งหมดเหล่านี้ขึ้นอยู่กับปัญหาที่อาจเกิดขึ้นได้หนึ่งปัญหาและนั่นคือคำถามว่าจะสร้างวัตถุที่เป็นปัญหาได้อย่างไร ต่อไปนี้เป็นวิธีการสร้างวัตถุต่าง ๆ และค่าที่วิธีการตรวจสอบชนิดต่าง ๆ จะส่งคืน:

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

แม้ว่าการเรียงสับเปลี่ยนทั้งหมดจะไม่ปรากฏในชุดตัวอย่างนี้หวังว่าจะมีเพียงพอที่จะให้คุณมีความคิดเกี่ยวกับวิธีการสิ่งที่ยุ่งเหยิงอาจขึ้นอยู่กับความต้องการของคุณ อย่าคิดอะไรเลยถ้าคุณไม่เข้าใจสิ่งที่คุณเป็นอย่างแน่นอนคุณอาจพบกับการทำลายรหัสที่คุณไม่คาดหวังเพราะขาดการคร่ำครวญรายละเอียดย่อย

บันทึก:

การพูดคุยของtypeofโอเปอเรเตอร์อาจดูเหมือนเป็นการละเลยที่เห็นได้ แต่มันไม่มีประโยชน์ในการช่วยระบุว่าobjectเป็นประเภทที่กำหนดหรือไม่เพราะมันง่ายมาก การเข้าใจว่าtypeofสิ่งใดมีประโยชน์มีความสำคัญ แต่ฉันไม่รู้สึกว่ามันเกี่ยวข้องกับการสนทนานี้มากนัก ใจของฉันเปิดรับการเปลี่ยนแปลง :)


58
ฉันคิดว่าฉันอาจจะเป็นเช่นนั้น - จุดของการโอเวอร์โฟลว์คือการเป็นวิกิเล็กน้อยและนี่ก็สอดคล้องกับเจตนานั้นมากขึ้น ไม่ว่าฉันต้องการจะค่อนข้างละเอียด
Jason Bunting

ทำซ้ำคำตอบด้านล่าง --- ส่วนขยายของคุณไปยังต้นแบบต้นแบบไม่ทำงานใน IE8 - ไม่มีใครรู้ว่าสิ่งที่จะทำงานใน IE8?
อดัม

5
มันจะทำงานถ้าคุณทำเช่นนี้ฟังก์ชั่น a () {this.a = 1;} ฟังก์ชั่น b () {this.b = 2; } b.prototype = new a (); // b สืบทอดมาจาก b.prototype.constructor = b; // วิธีที่ถูกต้องของมรดกสืบทอดต้นแบบ f f = new b (); // สร้างวัตถุใหม่ด้วยตัวสร้างข (f.constructor == b); // TRUE (f.constructor == a); // FALSE
Boris Hamanov

9
ตอนนี้เป็นวิธีที่คำตอบส่วนใหญ่ควรอยู่ใน StackOverflow (ไม่ต้องใช้ความยาวของคำตอบเป็นพารามิเตอร์ที่กำหนด แต่ความครอบคลุม)
kumarharsh

44
เป็นสิ่งสำคัญที่จะต้องทราบว่าเทคนิคใด ๆ ที่ตรวจสอบconstructorวิธีการของวัตถุ(ไม่ว่าจะด้วย.toString()หรือ.name) จะไม่สามารถทำงานได้หาก Javascript ของคุณถูกย่อด้วยเครื่องมือเช่น uglify หรือไปป์ไลน์ Rails minification nเปลี่ยนชื่อคอนสตรัคเพื่อให้คุณจะจบลงด้วยชื่อชั้นที่ไม่ถูกต้องเช่น หากคุณอยู่ในสถานการณ์นี้คุณอาจต้องการกำหนดคุณสมบัติบนวัตถุของคุณด้วยตนเองclassNameและใช้สิ่งนั้นแทน
Gabe Martin-Dempesy

126

คำตอบของ Jason Bunting ให้เบาะแสพอที่จะค้นหาสิ่งที่ฉันต้องการ:

<<Object instance>>.constructor.name

ตัวอย่างเช่นในโค้ดต่อไปนี้:

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

myInstance.constructor.name"MyObject"จะกลับมา


22
เพื่อความสมบูรณ์มันอาจคุ้มค่าที่จะกล่าวถึงว่าการใช้ constructor.name จะทำงานได้ก็ต่อเมื่อคุณใช้ฟังก์ชั่นที่มีชื่อเป็นตัวสร้างซึ่งตรงข้ามกับฟังก์ชั่นที่ไม่ระบุชื่อที่กำหนดให้กับตัวแปร
Matthew Crumley

20
เพื่อความสมบูรณ์อาจคุ้มค่าที่จะกล่าวถึงว่าใช้งานไม่ได้ในเบราว์เซอร์ IE --- พวกเขาไม่สนับสนุนคุณลักษณะ "ชื่อ" ในฟังก์ชั่น
Eugene Lazutkin

2
@Eugene - ฉันลืมไปแล้ว ... ฉันเดาว่าฉันใช้เวลามากเกินไปในการทำจาวาสคริปต์นอกเบราว์เซอร์
Matthew Crumley

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

นี่คือดังนั้นที่ครอบคลุม
ibic

26

เคล็ดลับเล็กน้อยที่ฉันใช้:

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

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

11
ฉันไม่ชอบสิ่งนี้โดยเฉพาะ มันเป็นกลอุบายที่สกปรกมากขึ้น ในทางกลับกันถ้าคุณไม่มีคอนสตรัคเตอร์มากเกินไปมันอาจใช้ได้ดี
pimvdb

13
@pvdvdb: ฉันคิดว่ามันสะอาดกว่าการดัดแปลงต้นแบบของวัตถุซึ่งเป็นคำตอบที่ยอมรับได้
Daniel Szabo

4
@DanielSzabo ถ้าคุณสมบัติควรมีค่าเท่ากันระหว่างอินสแตนซ์ทั้งหมดของต้นแบบฉันต้องการเลือกวางบนต้นแบบอย่างแน่นอน - การใส่ลงในแต่ละอินสแตนซ์นั้นมีความซ้ำซ้อนสูงและเมตาดาต้าหายไปจากต้นแบบเอง ที่กล่าวว่าวิธีการแก้ปัญหาที่ชาญฉลาดได้รับการยอมรับใน ES6: ถ้าคุณมีclass Squareชื่อSquare.name/ MySquare.constructor.nameมากกว่าSquare.prototype.name; โดยการใส่nameฟังก์ชั่นคอนสตรัคเตอร์มันจะไม่สร้างความเสียหายให้กับต้นแบบหรือตัวอย่างใด ๆ
แอนดี้

17

ปรับปรุง

เพื่อความแม่นยำฉันคิดว่า OP ขอฟังก์ชั่นที่เรียกชื่อตัวสร้างสำหรับวัตถุเฉพาะ ในแง่ของจาวาสคริปต์objectไม่ได้มีชนิด แต่เป็นชนิดและในตัวเอง แต่วัตถุที่แตกต่างกันสามารถที่แตกต่างกันมีการก่อสร้าง

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"

 


หมายเหตุ:ตัวอย่างด้านล่างเลิกใช้แล้ว

โพสต์บล็อกการเชื่อมโยงโดยคริสเตียน Sciberrasมีตัวอย่างที่ดีในการที่จะทำมัน กล่าวคือโดยการขยายต้นแบบวัตถุ:

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
เยี่ยมมาก แต่เราจะตั้งชื่ออีกครั้ง: JS ยังไม่ได้เรียน
mikemaccana

@ thumbnailer - ฉันแนะนำให้ใช้ฟังก์ชั่นที่อัปเดตตัวเก่าจะถูกเก็บไว้ด้วยเหตุผลทางประวัติศาสตร์เท่านั้น
Saul

ใช้งานได้ แต่ควรสังเกตว่าสามารถทำได้โดยไม่ต้องแก้ไข Object.prototype โดยการสร้างฟังก์ชั่นที่ใช้วัตถุเป็นอาร์กิวเมนต์แรกและใช้แทนฟังก์ชัน 'this' ในฟังก์ชัน
Matt Browne

2
@ แมท - แน่นอน มันเป็นเพียงแค่ว่ามีวิธีวัตถุคือสั้นเพิ่มเติมได้ที่: VStest.getClassName() getClassName.apply(test)
ซาอูล

12

ใช้ Object.prototype.toString

ปรากฎเป็นรายละเอียดการโพสต์นี้คุณสามารถใช้ Object.prototype.toString - ระดับต่ำและการใช้งานทั่วไปของ toString - เพื่อรับชนิดสำหรับชนิดในตัวทั้งหมด

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

สามารถเขียนฟังก์ชั่นตัวช่วยสั้น ๆ เช่น

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
คุณไม่จำเป็นต้องใช้ regex ในการแยกวิเคราะห์ชื่อวัตถุ เพียงใช้.slice():Object.prototype.toString.call(obj).slice( 8, -1 );
bobobobo

9

นี่เป็นวิธีแก้ปัญหาที่ฉันคิดขึ้นมาเพื่อแก้ไขข้อบกพร่องของอินสแตนซ์ มันสามารถตรวจสอบประเภทของวัตถุจาก cross-windows และ cross-frames และไม่มีปัญหากับชนิดดั้งเดิม

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 ต้องใช้พารามิเตอร์สองตัว: วัตถุและประเภท เคล็ดลับที่แท้จริงในการทำงานคือตรวจสอบว่าวัตถุนั้นมาจากหน้าต่างเดียวกันหรือไม่และไม่ได้รับหน้าต่างของวัตถุนั้น

ตัวอย่าง:

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

อาร์กิวเมนต์ type สามารถเป็นฟังก์ชันการเรียกกลับซึ่งส่งคืน Constructor ได้ ฟังก์ชั่นการโทรกลับจะได้รับหนึ่งพารามิเตอร์ซึ่งเป็นหน้าต่างของวัตถุที่ให้ไว้

ตัวอย่าง:

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

สิ่งหนึ่งที่ต้องจำไว้คือ IE <9 ไม่ได้จัดทำคอนสตรัคเตอร์บนวัตถุทั้งหมดดังนั้นการทดสอบข้างต้นสำหรับ NodeList จะส่งคืนค่าเท็จและ aInstance (alert, "Function") จะส่งคืนค่าเท็จ


8

จริง ๆ แล้วฉันกำลังมองหาสิ่งที่คล้ายกันและเจอคำถามนี้ นี่คือวิธีที่ฉันได้รับประเภท: 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

คุณควรใช้somevar.constructor.nameเช่น:

    
    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

ใช้constructor.nameเมื่อคุณสามารถและฟังก์ชั่น regex เมื่อฉันไม่สามารถ

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

6

ฟังก์ชันkind ()จากAgave.JSจะส่งคืน:

  • ต้นแบบที่ใกล้เคียงที่สุดในแผนผังการสืบทอด
  • สำหรับประเภทที่ล้าสมัยเสมอเช่น 'null' และ 'undefined' ชื่อดั้งเดิม

มันทำงานได้กับวัตถุและวัตถุพื้นฐานทั้งหมดของ JS ไม่ว่าพวกเขาจะสร้างอย่างไรและไม่มีความประหลาดใจใด ๆ ตัวอย่าง:

เบอร์

kind(37) === 'Number'
kind(3.14) === 'Number'
kind(Math.LN2) === 'Number'
kind(Infinity) === 'Number'
kind(Number(1)) === 'Number'
kind(new Number(1)) === 'Number'

น่าน

kind(NaN) === 'NaN'

เงื่อนไข

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'

อาร์เรย์

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

วัตถุ

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

วันที่

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

ฟังก์ชั่น

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

ไม่ได้กำหนด

kind(undefined) === 'undefined'

โมฆะ

kind(null) === 'null'

5

คุณสามารถใช้instanceofโอเปอเรเตอร์เพื่อดูว่าวัตถุเป็นอินสแตนซ์ของอีกวัตถุหนึ่งหรือไม่ แต่เนื่องจากไม่มีคลาสคุณจึงไม่สามารถรับชื่อคลาสได้


ในขณะที่มันเป็นความจริงที่จาวาสคริปต์ไม่ได้เรียนเป็นภาษาสร้างการประชุมทั่วไปยังคงเป็นว่าประเภทของวัตถุที่เรียกว่าชั้นเรียน ..
ซาอูล

2
@ รวมแน่นอน แต่instanceofเพียงตรวจสอบว่าวัตถุสืบทอดจากวัตถุอื่นหรือไม่ เช่นการ[]สืบทอดง่ายๆจาก Array แต่ Array ยังสืบทอดจาก Object เนื่องจากวัตถุส่วนใหญ่มีการสืบทอดหลายระดับการค้นหาต้นแบบที่ใกล้เคียงที่สุดจึงเป็นเทคนิคที่ดีกว่า ดูคำตอบของฉันสำหรับวิธี
mikemaccana

4

นี่คือการดำเนินการตามคำตอบที่ยอมรับ :

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

เราจะใช้คุณสมบัติคอนสตรัคเตอร์เมื่อเราไม่มีทางเลือกอื่นเท่านั้น


3

คุณสามารถใช้ตัวดำเนินการ "instanceof" เพื่อตรวจสอบว่าวัตถุเป็นอินสแตนซ์ของคลาสที่แน่นอนหรือไม่ หากคุณไม่ทราบชื่อประเภทของวัตถุคุณสามารถใช้คุณสมบัติ Constructor ได้ คุณสมบัติตัวสร้างของวัตถุคือการอ้างอิงถึงฟังก์ชั่นที่ใช้ในการเริ่มต้นพวกเขา ตัวอย่าง:

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

ตอนนี้ c1.constructor เป็นการอ้างอิงถึงCircle()ฟังก์ชัน คุณสามารถใช้typeofโอเปอเรเตอร์ได้ แต่typeofผู้ประกอบการจะแสดงข้อมูลที่ จำกัด ทางออกหนึ่งคือการใช้toString()วิธีการของวัตถุทั่วโลกวัตถุ ตัวอย่างเช่นถ้าคุณมีวัตถุพูด myObject คุณสามารถใช้toString()วิธีการของวัตถุทั่วโลกเพื่อกำหนดประเภทของชั้นเรียนของ myObject ใช้สิ่งนี้:

Object.prototype.toString.apply(myObject);

3

สมมติว่าคุณมี var obj;

หากคุณต้องการชื่อประเภทของ obj เช่น "Object", "Array" หรือ "String" คุณสามารถใช้สิ่งนี้:

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

2

สิ่งที่ใกล้เคียงที่สุดที่คุณจะได้รับคือtypeofแต่จะส่งกลับเฉพาะ "วัตถุ" สำหรับประเภทที่กำหนดเองใด ๆ สำหรับผู้ที่ดูเจสันตอม่อ

แก้ไข Jason's ลบโพสต์ของเขาด้วยเหตุผลบางอย่างดังนั้นเพียงใช้constructorคุณสมบัติของ Object


ใช่ขอโทษ - ฉันลบเพราะฉันคิดอินสแตนซ์ของ () เป็นวิธีที่ดีกว่าในการทำสิ่งต่าง ๆ แต่ฉันเพิ่งยกเลิกการลบมันเพื่อให้สามารถใช้เป็นข้อมูลอ้างอิงได้
Jason Bunting

2
คำตอบที่สมบูรณ์แบบน้อยกว่านั้นยังคงมีประโยชน์ถ้าเพียงเพื่อคนอื่นมาที่คำถามในภายหลังเพราะพวกเขามีปัญหาที่คล้ายกัน ดังนั้นคุณไม่ควรลบ บันทึกการลบสำหรับคำตอบที่ผิด
sblundy

2
ใช่ฉันรู้ - คุณกำลังเทศนาให้กับคณะนักร้องประสานเสียงฉันพูดในสิ่งเดียวกันกับคนอื่น ๆ การดำเนินชีวิตในสิ่งที่เรารู้ว่าเป็นความจริงมักจะยากกว่าที่คิด :)
Jason Bunting

0

หากใครกำลังมองหาวิธีแก้ปัญหาที่ทำงานกับ jQuery นี่คือรหัส wiki ที่ปรับแล้ว (ตัวแบ่ง 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] : "";
    }
});

ใช่ jQuery ล้มเหลวในการตรวจสอบ 'hasOwnProperty' และระบุgetNameและตกลง
nicodemus13

0

Lodash มีหลายวิธีดังนั้นหากคุณใช้ Lodash อาจเป็นมิกซ์อินแบบนี้มีประโยชน์:

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

มันเพิ่มวิธีการบ้านพักที่เรียกว่า "ระบุ" ซึ่งทำงานดังนี้:

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

เสียงแตก: http://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN


0

ตกลงคนที่ฉันได้ช้าสร้างวิธีการทั้งหมดนี้กว่าปี lol! เคล็ดลับคือ:

  1. มีกลไกในการสร้างคลาส
  2. มีกลไกสำหรับการตรวจสอบคลาสที่ผู้ใช้สร้างขึ้น, ดั้งเดิมและค่าที่สร้าง / สร้างโดยตัวสร้างดั้งเดิม
  3. มีกลไกในการขยายคลาสที่ผู้ใช้สร้างขึ้นเป็นคลาสใหม่เพื่อให้ฟังก์ชันการทำงานข้างต้นแทรกซึมผ่านโค้ด / แอปพลิเคชัน / ไลบรารี / ฯลฯ ของคุณ

ตัวอย่างเช่น (หรือเพื่อดูว่าฉันจัดการกับปัญหา) ดูที่รหัสต่อไปนี้ใน github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.jsและค้นหา:

classOf =, classOfIs =และหรือ defineSubClass =(โดยไม่มี backticks (`))

อย่างที่คุณเห็นฉันมีกลไกบางอย่างที่จะบังคับclassOfให้ชื่อคลาส / ตัวสร้างของฉันเสมอโดยไม่คำนึงว่าเป็นแบบดั้งเดิมคลาสที่ผู้ใช้กำหนดเองค่าที่สร้างขึ้นโดยใช้ตัวสร้างแบบดั้งเดิม Null, NaN ฯลฯ สำหรับค่าจาวาสคริปต์ทุกครั้งฉันจะได้รับชื่อประเภทที่ไม่ซ้ำกันจากclassOfฟังก์ชั่น นอกจากนี้ฉันสามารถส่งผ่านคอนสตรัคเตอร์จริงsjl.classOfIsเพื่อตรวจสอบประเภทของค่านอกจากนี้ยังสามารถส่งผ่านชื่อประเภทได้เช่นกัน! ตัวอย่างเช่น:

`` `// // โปรดอภัยเนมสเปซที่ยาว! ฉันไม่มีความคิดเกี่ยวกับผลกระทบจนกระทั่งหลังจากใช้ไประยะหนึ่ง (พวกเขาดูดฮ่าฮ่า)

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`!

`` `

หากคุณสนใจที่จะอ่านเพิ่มเติมเกี่ยวกับวิธีใช้การตั้งค่าที่กล่าวถึงข้างต้นลองดูที่ repo: https://github.com/elycruz/sjljs

หนังสือที่มีเนื้อหาเกี่ยวกับเรื่อง: - "รูปแบบ JavaScript" โดย Stoyan Stefanov - "Javascript - คู่มือที่ชัดเจน" โดย David Flanagan - และอื่น ๆ อีกมากมาย .. (ค้นหาไฟล์จากเว็บ)

นอกจากนี้คุณสามารถทดสอบคุณสมบัติที่ฉันกำลังพูดถึงได้อย่างรวดเร็วที่นี่: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (เช่นเส้นทาง 0.5.18 ใน url มีแหล่งที่มาจาก GitHub ที่นั่นลบ node_modules และเช่นนั้น)

Happy Coding!


0

ค่อนข้างง่าย!

  • วิธีที่ฉันชอบเพื่อรับประเภทของอะไรใน JS
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • วิธีที่ชื่นชอบในการตรวจสอบประเภทของอะไรก็ได้ใน JS
function checkType(entity, type){
    return getType(entity) === type
}

-1

class.nameใช้ function.nameนี้ยังทำงานร่วมกับ

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

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

คำถามชัดเจนclassและไม่ใช่ตัวอย่าง
qwertzguy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.