2013-05-24 45 views
7

Xác định đối tượng nào là is complicated trong JavaScript và tìm ra đối tượng nào là mảng có thứ gì đó trong số hacky solution. May mắn thay, nó quản lý để làm việc trong cả hai trường hợp sau đây:Có thể xác định xem một đối tượng được tạo với Object.create kế thừa từ Array trong JavaScript không?

Object.prototype.toString.call([]);   // [object Array] 
Object.prototype.toString.call(new Array()); // [object Array] 

Tuyệt vời, không [object Object] trong tầm nhìn! Đáng buồn thay, phương pháp này vẫn quản lý để thất bại với điều này:

var arr = Object.create(Array.prototype); 
Object.prototype.toString.call(arr);   // [object Object] 

Điều này là bực bội, vì vậy hãy nói ít nhất. Đối tượng arr của tôi có tất cả các phương thức của một mảng, nó hoạt động như một mảng và cho tất cả các mục đích, nó một mảng. Tuy nhiên, JavaScript không cung cấp các công cụ để xác định nó như vậy.

Có cách nào để tìm hiểu xem một đối tượng có được kế thừa từ một mẫu thử nghiệm cụ thể không? Tôi cho rằng bạn có thể lặp qua các nguyên mẫu như vậy:

function inherits(obj, proto) { 
    while (obj != null) { 
     if (obj == proto) return true; 
     obj = Object.getPrototypeOf(obj); 
    } 
    return false; 
} 

inherits(Object.create(Array.prototype), Array.prototype); // true 

Nhưng nó cảm thấy một chút tẻ nhạt. Có cách tiếp cận nào sạch hơn không?

+0

Tôi chỉ tò mò: tại sao bạn lại tạo một mảng như thế này? 'Object.create (Array.prototyp);' và kiểm tra nó thông qua 'Object.prototype.toString.call (arr);' – Zim84

+0

@ Zim84: Tôi nghĩ đây chỉ là một ví dụ. Trong các ứng dụng thực tế, chúng ta không bao giờ nên làm điều này. Trong các ứng dụng thực tế, Object.create (Array.prototype) có thể được gọi ở một nơi khác và truyền đối tượng đã tạo tới một hàm khác –

+0

Vấn đề là bạn không thực sự có một mảng thực (ví dụ nó không có phép thuật ' length' tài sản, chỉ là một trong đó trông giống như nó ở cái nhìn đầu tiên). Những gì bạn có là một mảng giống như chỉ xảy ra để có tất cả các phương thức của một mảng thực. Nếu bạn muốn kiểm tra các mảng thích, bạn nên tìm hiểu xem nó có thuộc tính 'length' và không phải là một chuỗi hay không. Đó là IMO tốt nhất. Nếu bạn muốn kiểm tra các mảng thực, hãy tiếp tục sử dụng 'Object.prototype.toString.call' hoặc' Array.isArray' và biết rằng một đối tượng có nguyên mẫu 'Array.prototype' không nhất thiết là một mảng đúng. –

Trả lời

2

Làm thế nào về một nhà điều hành instanceof? Nó trả true cho tất cả các trường hợp của bạn:

[] instanceof Array //true 
new Array() instanceof Array //true 
Object.create(Array.prototype) instanceof Array //true 

Tuy nhiên:

Object.create(Array.prototype) instanceof Object //also true 

Vì vậy, hãy cẩn thận.

+0

instanceof Array không cung cấp một cách đáng tin cậy để kiểm tra khi chúng ta truyền mảng qua lại giữa các frame vì mỗi frame có một constructor Array riêng của nó –

+0

Đây là một giải pháp hợp lý cho môi trường single-frame hoặc Node. Chỉ cần ghi nhớ vấn đề đa khung hình. –

2

ECMAScript 5 đã giới thiệu Array.isArray() vào javascript cung cấp một cách đáng tin cậy để kiểm tra. Đối với các trình duyệt cũ, chúng ta khắc phục điều đó bằng cách (trích dẫn từ book này)

function isArray(value) { 
    if (typeof Array.isArray === "function") { 
     return Array.isArray(value); 
    } else { 
     return Object.prototype.toString.call(value) === "[object Array]"; 
    } 
} 

Nhưng tôi vừa phát hiện ra được xây dựng trong chức năng Array.isArray không hoạt động đúng khi chúng ta sử dụng Object.create (thử nghiệm trong chrome). Tôi đã đưa ra một phương pháp mà làm việc:

function isArray(value) { 
    if (typeof value === "undefined" || value === null) { 
      return false; 
    } 
    do { 
      if (Object.prototype.toString.call(value) === "[object Array]") { 
       return true; 
      } 
      value= Object.getPrototypeOf(value); 
    } while (value); 

    return false; 
} 

Sử dụng nó:

var arr = Object.create(Array.prototype); 
var arr1 = Object.create(Object.create(Array.prototype)); 
var arr2 = new Array(); 
var arr3 = []; 
isArray(arr); 
isArray(arr1); 
isArray(arr2); 
isArray(arr3); 
+1

'Array.isArray' giống hệt' Object.prototype.toString.call (arr) == '[đối tượng mảng]' '. Giải pháp này sẽ không hoạt động nếu nguyên mẫu của đối tượng là một đối tượng có một mẫu thử nghiệm là một mảng. 'var arr = Object.create (Object.create (Array.prototype));' –

+0

@NathanWall: hãy xem [cuốn sách này] (http://books.google.com.vn/books?id=J5RCV8yM7sEC&pg= PA88 & LPG = PA88 & dq = bảo trì + javascript + phát hiện + mảng & source = bl & OTS = TDZEDzhWJm & sig = I92iJt7mAz8rEdHteDFAmCSqLzI & hl = vi & sa = X & ei = XHShUZnkLY6diAerxICgCg & ved = 0CDEQ6AEwAQ # v = onepage & q = duy trì% 20javascript% 20detecting% 20array & f = false) –

+0

@NathanWall: kiểm tra câu trả lời được cập nhật. Cảm ơn. –

0

Làm thế nào về việc kiểm tra các nhà xây dựng?

function inherits(obj, proto) { 
    return obj.constructor === proto.constructor; 
} 

inherits(Object.create(Array.prototype), Array.prototype); // true 
2

Xem http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/ để giải thích dứt khoát các vấn đề trong kế thừa từ mảng.

Dù sao, trong trường hợp đơn giản nhất, nơi bạn đang làm

var sort_of_an_array = Object.create(Array.prototype); 

bạn có thể kiểm tra bằng isPrototypeOf:

Array.prototype.isPrototypeOf(sort_of_an_array) 

Xem https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf.

0

nó hoạt động như một mảng, và cho tất cả các mục đích, nó là một mảng

số Nó không có tính năng tự động cập nhật tài sản length. Xem this article lý do tại sao hoàn toàn không thể phân loại được Array.

Có cách nào để tìm hiểu xem một đối tượng có được kế thừa từ một mẫu thử nghiệm cụ thể không? Tôi cho rằng bạn có thể lặp lại thông qua các nguyên mẫu, nhưng nó cảm thấy một tad hack.

Đó chỉ là cách thực hiện. Cách tiếp cận rõ ràng hơn chức năng tự viết sẽ là sử dụng instanceof operator:

arr instanceof Array; // true 
Các vấn đề liên quan