Làm cách nào để có được lớp của đối tượng JavaScript?


728

Tôi đã tạo một đối tượng JavaScript, nhưng làm thế nào tôi có thể xác định lớp của đối tượng đó?

Tôi muốn một cái gì đó tương tự như .getClass()phương thức của Java .


6
ví dụ: tôi tạo một Người như thế này: var p = new Person (); Tôi có một Đối tượng Người gọi là "p", làm cách nào tôi có thể sử dụng "p" để lấy lại tên Lớp: "Người".
DNB5brims


Cập nhật: Kể từ ECMAScript 6, JavaScript vẫn không có classloại. Nó không có một classtừ khóa và classcú pháp để tạo nguyên mẫu, trong đó phương pháp có thể dễ dàng hơn truy cập super.
james_womack

Thế còn Object.groupName thì sao?
Paul Basenko

@ Paul-Basenko: "className" sẽ không cho bạn biết lớp của đối tượng, nhưng sẽ trả về nội dung của thuộc tính "class" của phần tử HTML, đề cập đến các lớp CSS. Bạn cũng muốn sử dụng "classList" để quản lý chúng dễ dàng, nhưng nó không liên quan đến câu hỏi của OP.
Obsidian

Câu trả lời:


1009

Không có đối tác chính xác với Java getClass()trong JavaScript. Chủ yếu là do JavaScript là ngôn ngữ dựa trên nguyên mẫu , trái ngược với Java là ngôn ngữ dựa trên lớp .

Tùy thuộc vào những gì bạn cần getClass(), có một số tùy chọn trong JavaScript:

Một vài ví dụ:

function Foo() {}
var foo = new Foo();

typeof Foo;             // == "function"
typeof foo;             // == "object"

foo instanceof Foo;     // == true
foo.constructor.name;   // == "Foo"
Foo.name                // == "Foo"    

Foo.prototype.isPrototypeOf(foo);   // == true

Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21);            // == 42

Lưu ý: nếu bạn đang biên dịch mã của mình với Uglify, nó sẽ thay đổi tên lớp không toàn cầu. Để ngăn chặn điều này, Uglify có một thông số --manglemà bạn có thể đặt thành false là sử dụng gulp hoặc grunt .


6
Điều đó có thể là func.prototype(có, các hàm là các đối tượng, nhưng thuộc prototypetính chỉ liên quan đến các đối tượng hàm).
Miles

5
bạn cũng có thể muốn đề cập đến instanceof/ isPrototypeOf()và không chuẩn__proto__
Christoph

9
ES5 có quảng cáoObject.getPrototypeOf()
Christoph

22
Cảnh báo : không dựa vào constructor.namenếu mã của bạn đang bị thu nhỏ. Tên hàm sẽ thay đổi tùy ý.
igorsantos07

3
@ igorsantos07, ít nhất là vào năm 2019; 5-10 kết quả google hàng đầu cho "công cụ khai thác javascript trực tuyến" nhận ra construction.namelà mã thông báo bị bỏ qua / không thu nhỏ. Bên cạnh đó hầu hết (nếu không phải tất cả) phần mềm khai thác cung cấp các quy tắc ngoại lệ.
quạ Vulcan

296
obj.constructor.name

là một phương pháp đáng tin cậy trong các trình duyệt hiện đại. Function.nameđã chính thức được thêm vào tiêu chuẩn trong ES6, làm cho điều này trở thành một phương tiện tuân thủ tiêu chuẩn để lấy "lớp" của một đối tượng JavaScript dưới dạng một chuỗi. Nếu đối tượng được khởi tạo cùng var obj = new MyClass(), nó sẽ trả về "MyClass".

Nó sẽ trả về "Số" cho các số, "Mảng" cho các mảng và "Hàm" cho các hàm, v.v ... Nó thường hoạt động như mong đợi. Các trường hợp duy nhất thất bại là nếu một đối tượng được tạo mà không có nguyên mẫu, thông qua Object.create( null )hoặc đối tượng được khởi tạo từ một hàm được định nghĩa ẩn danh (không tên).

Cũng lưu ý rằng nếu bạn đang thu nhỏ mã của mình, sẽ không an toàn khi so sánh với các chuỗi loại được mã hóa cứng. Ví dụ thay vì kiểm tra nếu obj.constructor.name == "MyType", thay vì kiểm tra obj.constructor.name == MyType.name. Hoặc chỉ so sánh chính các hàm tạo, tuy nhiên, điều này sẽ không hoạt động trên các ranh giới DOM vì có các phiên bản khác nhau của hàm tạo trên mỗi DOM, do đó thực hiện so sánh đối tượng trên các hàm tạo của chúng sẽ không hoạt động.


11
Function.namekhông phải (chưa) là một phần của tiêu chuẩn JavaScript. Nó hiện được hỗ trợ trong Chrome và Firefox, nhưng không có trong IE (10).
Halcyon

13
obj.constructor.namechỉ hoạt động cho các chức năng được đặt tên . Tức là, nếu tôi xác định var Foo = function() {}, sau đó var foo = new Foo(), foo.constructor.namesẽ cung cấp cho bạn chuỗi rỗng.
KFL

29
Cảnh báo : không dựa vào constructor.namenếu mã của bạn đang bị thu nhỏ. Tên hàm sẽ thay đổi tùy ý.
igorsantos07

1
Function.name là một phần của ES6, xem developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Janus Troelsen

1
@adalbertpl Nó phải được thực hiện với các nguyên mẫu xích bằng tay, trước ES6. Thật tốt khi biết constructor.namehành vi như mong đợi với sự hỗ trợ lớp mới trong ES6.
devios1

29

Hàm này trả về "Undefined"các giá trị không xác định và "Null"cho null.
Đối với tất cả các giá trị khác, CLASSNAME-part được trích xuất từ [object CLASSNAME], đó là kết quả của việc sử dụng Object.prototype.toString.call(value).

function getClass(obj) {
  if (typeof obj === "undefined") return "Undefined";
  if (obj === null) return "Null";
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}

getClass("")   === "String";
getClass(true) === "Boolean";
getClass(0)    === "Number";
getClass([])   === "Array";
getClass({})   === "Object";
getClass(null) === "Null";
// etc...

Object.prototype.getClass = function () {sử dụng 'this' thay vì obj sẽ rất tuyệt
SparK

2
tất nhiên sau đó là null và không xác định sẽ không thể kiểm soát được vì chỉ có Object mới có phương thức getClass
SparK

8
Điều này chỉ hoạt động trên các đối tượng bản địa. Nếu bạn có một số loại thừa kế, bạn sẽ luôn luôn nhận được "Object".
Halcyon

Vâng, dòng cuối cùng của chức năng nên là return obj.constructor.name. Điều đó cho kết quả tương tự, cộng với xử lý các đối tượng không phải là bản địa.
Steve Bennett

18

Để có được "lớp giả", bạn có thể lấy hàm tạo

obj.constructor

giả sử constructorđược đặt chính xác khi bạn thực hiện kế thừa - nghĩa là:

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

và hai dòng này, cùng với:

var woofie = new Dog()

sẽ làm cho woofie.constructorđiểm Dog. Lưu ý rằng đó Doglà một hàm tạo, và là một Functionđối tượng. Nhưng bạn có thể làm được if (woofie.constructor === Dog) { ... }.

Nếu bạn muốn lấy tên lớp dưới dạng chuỗi, tôi thấy các mục sau hoạt động tốt:

http://blog.magnetiq.com/post/514962277/finding-out- class-name-of-javascript-objects

function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2) {
            return arr[1];
        }
    }

    return undefined;
}

Nó nhận được hàm xây dựng, chuyển đổi nó thành chuỗi và trích xuất tên của hàm xây dựng.

Lưu ý rằng obj.constructor.namecó thể đã hoạt động tốt, nhưng nó không phải là tiêu chuẩn. Nó có trên Chrome và Firefox, nhưng không có trên IE, bao gồm IE 9 hoặc IE 10 RTM.


13

Bạn có thể lấy tham chiếu đến hàm constructor đã tạo đối tượng bằng cách sử dụng thuộc tính constructor :

function MyObject(){
}

var obj = new MyObject();
obj.constructor; // MyObject

Nếu bạn cần xác nhận loại đối tượng trong thời gian chạy, bạn có thể sử dụng toán tử instanceof :

obj instanceof MyObject // true

Nó không trả về hàm constructor, như, bạn có thể gọi lại nó và tạo một đối tượng mới kiểu đó không?
SparK

1
@SparK Có, mặc dù bạn vẫn có thể sử dụng điều này để so sánh miễn là bạn ở trên cùng một DOM (bạn đang so sánh các đối tượng hàm). Tuy nhiên, cách tốt hơn là biến hàm tạo thành một chuỗi và so sánh điều đó, đặc biệt bởi vì nó hoạt động trên các ranh giới DOM khi sử dụng iframe.
devios1

Câu trả lời này trả về "lớp" (hoặc ít nhất là xử lý đối tượng có thể được sử dụng để tạo một thể hiện của lớp - giống như "lớp"). Các câu trả lời ở trên tất cả các chuỗi trả về không giống như "đối tượng lớp" (như nó là).
Mike P.

8

Để giữ bản ghi không bị gián đoạn về khả năng tương thích ngược, ECMAScript 6, JavaScript vẫn không có classloại (mặc dù không phải ai cũng hiểu điều này). Nó không có một classtừ khóa như là một phần của nó classcú pháp để tạo nguyên mẫu-nhưng vẫn có những điều được gọi là lớp . JavaScript không phải bây giờ và chưa bao giờ là ngôn ngữ OOP cổ điển . Nói về JS về mặt lớp học chỉ là sai lệch hoặc là một dấu hiệu của việc thừa kế nguyên mẫu chưa được tìm kiếm (chỉ giữ cho nó thực sự).

Điều đó có nghĩa this.constructorvẫn là một cách tuyệt vời để có được một tham chiếu đến constructorhàm. Và this.constructor.prototypelà cách để truy cập vào nguyên mẫu. Vì đây không phải là Java, nên nó không phải là một lớp. Đó là đối tượng nguyên mẫu mà cá thể của bạn được khởi tạo từ. Dưới đây là một ví dụ sử dụng đường cú pháp ES6 để tạo chuỗi nguyên mẫu:

class Foo {
  get foo () {
    console.info(this.constructor, this.constructor.name)
    return 'foo'
  }
}

class Bar extends Foo {
  get foo () {
    console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
    console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))

    return `${super.foo} + bar`
  }
}

const bar = new Bar()
console.dir(bar.foo)

Đây là những gì đầu ra sử dụng babel-node:

> $ babel-node ./foo.js                                                                                                                    6.2.0 master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'

Có bạn có nó! Trong năm 2016, có một classtừ khóa trong JavaScript, nhưng vẫn không có loại lớp. this.constructorlà cách tốt nhất để có được hàm xây dựng, this.constructor.prototypecách tốt nhất để có quyền truy cập vào chính nguyên mẫu.


7

tôi đã có một tình huống để làm việc chung bây giờ và sử dụng điều này:

class Test {
  // your class definition
}

nameByType = function(type){
  return type.prototype["constructor"]["name"];
};

console.log(nameByType(Test));

đó là cách duy nhất tôi tìm thấy để lấy tên lớp theo kiểu nhập nếu bạn không có thể hiện của một đối tượng.

(viết bằng ES2017)

ký hiệu chấm cũng hoạt động tốt

console.log(Test.prototype.constructor.name); // returns "Test" 

Ah đây là những gì tôi đang tìm kiếm. Nếu nó không được khởi tạo, bạn phải sử dụng 'nguyên mẫu' để lấy tên lớp. Cảm ơn rất nhiều!
Artokun

4

Đối với các lớp Javascript trong ES6, bạn có thể sử dụng object.constructor. Trong lớp ví dụ bên dưới, getClass()phương thức trả về lớp ES6 như bạn mong đợi:

var Cat = class {

    meow() {

        console.log("meow!");

    }

    getClass() {

        return this.constructor;

    }

}

var fluffy = new Cat();

...

var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();

ruffles.meow();    // "meow!"

Nếu bạn khởi tạo lớp từ getClassphương thức, hãy đảm bảo bạn bọc nó trong ngoặc, vdruffles = new ( fluffy.getClass() )( args... );


3

Tôi tìm thấy sự object.constructor.toString()trở lại [object objectClass]trong IE, thay vì function objectClass () {}trở lại trong chome. Vì vậy, tôi nghĩ rằng mã trong http://blog.magnetiq.com/post/514962277/finding-out-group-names-of-javascript-objects có thể không hoạt động tốt trong IE. Và tôi đã sửa mã như sau:

mã:

var getObjectClass = function (obj) {
        if (obj && obj.constructor && obj.constructor.toString()) {

                /*
                 *  for browsers which have name property in the constructor
                 *  of the object,such as chrome 
                 */
                if(obj.constructor.name) {
                    return obj.constructor.name;
                }
                var str = obj.constructor.toString();
                /*
                 * executed if the return of object.constructor.toString() is 
                 * "[object objectClass]"
                 */

                if(str.charAt(0) == '[')
                {
                        var arr = str.match(/\[\w+\s*(\w+)\]/);
                } else {
                        /*
                         * executed if the return of object.constructor.toString() is 
                         * "function objectClass () {}"
                         * for IE Firefox
                         */
                        var arr = str.match(/function\s*(\w+)/);
                }
                if (arr && arr.length == 2) {
                            return arr[1];
                        }
          }
          return undefined; 
    };

2

Trong javascript, không có lớp, nhưng tôi nghĩ rằng bạn muốn tên của hàm tạo và obj.constructor.toString()sẽ cho bạn biết những gì bạn cần.


1
Điều này sẽ trả về toàn bộ định nghĩa của hàm xây dựng dưới dạng một chuỗi. Những gì bạn thực sự muốn là .name.
devios1

4
nhưng .namekhông được xác định ngay cả trên IE 9
phân cực

1

Đồng ý với dfa, đó là lý do tại sao tôi coi prototye là lớp khi không tìm thấy lớp có tên

Đây là một chức năng được nâng cấp của cái được đăng bởi Eli Gray, để phù hợp với suy nghĩ của tôi

function what(obj){
    if(typeof(obj)==="undefined")return "undefined";
    if(obj===null)return "Null";
    var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
    if(res==="Object"){
        res = obj.constructor.name;
        if(typeof(res)!='string' || res.length==0){
            if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
            if(obj instanceof Array)return "Array";// Array prototype is very sneaky
            return "Object";
        }
    }
    return res;
}

1

Nếu bạn không chỉ NHẬN lớp mà còn TUYỆT ĐỐI không chỉ có một thể hiện, hãy viết:

hãy có

 class A{ 
   constructor(name){ 
     this.name = name
   }
 };

 const a1 = new A('hello a1');

vì vậy để mở rộng A có thể hiện chỉ sử dụng:

const a2 = new ((Object.getPrototypeOf(a)).constructor())('hello a2')
// the analog of const a2 = new A()

console.log(a2.name)//'hello a2'

0

Tôi đề nghị sử dụng Object.prototype.constructor.name:

Object.defineProperty(Object.prototype, "getClass", {
    value: function() {
      return this.constructor.name;
    }
});

var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'

var y = new Error("");
console.log(y.getClass()); // `Error'

0

Đây là một thực hiện getClass()getInstance()

Bạn có thể nhận được một tài liệu tham khảo cho lớp Object this.constructor.

Từ một bối cảnh ví dụ:

function A() {
  this.getClass = function() {
    return this.constructor;
  }

  this.getNewInstance = function() {
    return new this.constructor;
  }
}

var a = new A();
console.log(a.getClass());  //  function A { // etc... }

// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true

Từ bối cảnh tĩnh:

function A() {};

A.getClass = function() {
  return this;
}

A.getInstance() {
  return new this;
}

2
Tại sao không chỉ this.constructor?
Solomon Ucko

1
Tôi không biết, nhưng nếu nó tốt hơn, bạn chắc chắn có thể chỉnh sửa câu trả lời để cải thiện nó khi bạn thấy tốt hơn, sau tất cả, đây là một cộng đồng.
Bruno Finger

0

Bạn cũng có thể làm một cái gì đó như thế này

 class Hello {
     constructor(){
     }
    }
    
      function isClass (func) {
        return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
    }
    
   console.log(isClass(Hello))

Điều này sẽ cho bạn biết nếu đầu vào là lớp hay không


-2

Javascript là ngôn ngữ không có lớp: không có lớp nào định nghĩa hành vi của lớp một cách tĩnh như trong Java. JavaScript sử dụng các nguyên mẫu thay vì các lớp để xác định các thuộc tính đối tượng, bao gồm các phương thức và kế thừa. Có thể mô phỏng nhiều tính năng dựa trên lớp với các nguyên mẫu trong JavaScript.


12
Tôi thường nói rằng Javascript thiếu lớp :)
Steven

4
Cập nhật: Kể từ ECMAScript 6, JavaScript vẫn không có classloại. Nó không có một classtừ khóa và classcú pháp để tạo nguyên mẫu, trong đó phương pháp có thể dễ dàng hơn truy cập super.
james_womack

-3

Câu hỏi dường như đã được trả lời nhưng OP muốn truy cập vào lớp và đối tượng, giống như chúng ta làm trong Java và câu trả lời được chọn là không đủ (imho).

Với lời giải thích sau đây, chúng ta có thể có được một lớp của một đối tượng (nó thực sự được gọi là nguyên mẫu trong javascript).

var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');

Bạn có thể thêm một tài sản như thế này:

Object.defineProperty(arr,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue

Nhưng thuộc .lasttính sẽ chỉ khả dụng cho arrđối tượng '' được khởi tạo từ nguyên mẫu Array. Vì vậy, để có .lastsẵn thuộc tính cho tất cả các đối tượng được khởi tạo từ nguyên mẫu Array, chúng ta phải xác định thuộc .lasttính cho nguyên mẫu Array:

Object.defineProperty(Array.prototype,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Vấn đề ở đây là, bạn phải biết loại đối tượng (nguyên mẫu) mà các biến ' arr' và ' arr2' thuộc về! Nói cách khác, nếu bạn không biết loại lớp (nguyên mẫu) của arrđối tượng '', thì bạn sẽ không thể xác định một thuộc tính cho chúng. Trong ví dụ trên, chúng ta biết mảng là đối tượng của đối tượng Array, đó là lý do tại sao chúng ta sử dụng Array.prototype để định nghĩa một thuộc tính cho Array. Nhưng nếu chúng ta không biết lớp (nguyên mẫu) của ' arr' thì sao?

Object.defineProperty(arr.__proto__,'last2', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Như bạn có thể thấy, mà không biết rằng ' arr' là một Mảng, chúng ta có thể thêm một thuộc tính mới chỉ cần tham chiếu lớp của ' arr' bằng cách sử dụng ' arr.__proto__'.

Chúng tôi đã truy cập nguyên mẫu của ' arr' mà không biết rằng đó là phiên bản của Array và tôi nghĩ đó là những gì OP yêu cầu.


Tài __proto__sản bị phản đối, và hầu như không có lợi thế so với prototypetài sản.
Sapphire_Brick
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.