2008-09-23 68 views
27

Tôi đang xem qua sốcủa John Resig và tôi không hiểu rõ sự khác biệt giữa các cuộc gọi sau đây: (xin lưu ý rằng 'đối số' là từ được xây dựng trong javascript và là không chính xác một mảng do đó hack với Array.slice thay vì chỉ đơn giản gọi arguments.slice)Sự khác biệt giữa Array.slice và Array() slice

>>> arguments 
[3, 1, 2, 3] 
>>> Array.slice.call(arguments) 
3,1,2,3 0=3 1=1 2=2 3=3 
>>> Array.slice.call(arguments, 1) 
[] 
>>> Array().slice.call(arguments) 
3,1,2,3 0=3 1=1 2=2 3=3 
>>> Array().slice.call(arguments, 1) 
1,2,3 0=1 1=2 2=3 

về cơ bản sự hiểu lầm của tôi nắm chênh lệch giữa Array.slice và array(). lát. Chính xác là sự khác biệt giữa hai cái này và tại sao Array.slice.call không hoạt động như mong đợi? (đó là trả lại tất cả trừ phần tử đầu tiên của danh sách đối số).

Trả lời

38

Không hẳn.

Xem những gì sẽ xảy ra khi bạn gọi String.substring.call ("foo", 1) và String substring.call() ("foo", 2):.

>>> String.substring.call("foo", 1) 
"1" 

>>> String().substring.call("foo", 1) 
"oo" 

Array.slice là không phải tham chiếu đúng chức năng lát được đính kèm với nguyên mẫu Array cũng như hàm slice được gắn với bất kỳ cá thể Array đã được khởi tạo nào (chẳng hạn như Array() hoặc []).

Thực tế là Array.slice thậm chí không vô dụng ở tất cả là việc triển khai sai chính xác đối tượng (/ hàm/hàm tạo). Thử chạy mã tương đương trong IE và bạn sẽ gặp lỗi Array.slice là null.

Đây là lý do tại sao Array.slice không hoạt động chính xác (cũng không String.substring).

Proof (sau đây là một cái gì đó ta không bao giờ nên mong đợi dựa trên định nghĩa của lát() ... giống như substring() ở trên):

>>> Array.slice.call([1,2], [3,4]) 
3,4 

Bây giờ, nếu bạn đúng cách gọi lát() trên hoặc là một đối tượng khởi tạo hoặc Array nguyên mẫu, bạn sẽ có được những gì bạn mong đợi:

>>> Array.prototype.slice.call([4,5], 1) 
[5] 
>>> Array().slice.call([4,5], 1) 
[5] 

Nhiều bằng chứng ...

>>> Array.prototype.slice == Array().slice 
true 
>>> Array.slice == Array().slice 
false 
+0

Tôi không biết nó hoạt động như thế nào trong trình duyệt '08, nhưng vào đầu năm 2013, 'String.substring.call' ném TypeError trong Chrome (vì hàm tạo' String' không có thuộc tính 'chuỗi con') . – bfavaretto

+0

@bfavaretto, Firefox (một mình) triển khai 'Array.slice' và' String.substring'. Người hỏi chắc chắn đã sử dụng Firefox khi anh ta đang thử việc này. –

+0

Cảm ơn thông tin, @NathanWall. Đó là khá lạ của Firefox, có lẽ một cái gì đó họ thêm vào như là một phím tắt để 'String.prototype.substring' et al. cho khả năng tương thích ngược ... và dường như nó được gắn bó trong một thời gian. – bfavaretto

6

Mảng chỉ là một hàm, mặc dù là một hàm đặc biệt (được sử dụng để khởi tạo mảng). Array.slice là một tham chiếu đến hàm slice() trong nguyên mẫu Array. Nó chỉ có thể được gọi trên một đối tượng mảng chứ không phải trên Constructor (ví dụ: Array). Mảng dường như hành xử đặc biệt mặc dù, như Array() trả về một mảng trống. Điều này dường như không hoạt động đối với các hàm Constructor không xây dựng (ở đó bạn phải sử dụng mới). Vì vậy,

Array().slice.call 

cũng giống như

[].slice.call 
-1

Đoán của tôi là Array là một nguyên mẫu trong khi Array() là một đối tượng mảng thực. Tùy thuộc vào việc giải thích JavaScript, trực tiếp gọi phương thức nguyên mẫu của kiểu đối tượng dựng sẵn có thể hoạt động hoặc có thể không. Tôi không tin rằng spec nói rằng nó phải làm việc, chỉ cần gọi nó trên một đối tượng instantiated hoạt động.

0

Tôi tin rằng Mảng là loại và Mảng() là hàm tạo.

Messing xung quanh trong FireBug:

>>> Array === Array() 
false 

>>> Array.constructor 
Function() 

>>> Array().constructor 
Array() 
1

Mọi cuộc gọi tới slice.call() hoạt động như thế nào trong các ví dụ được cung cấp vì tham số ngữ cảnh không được cung cấp? Liệu slice có thực hiện phương thức gọi riêng của nó, do đó sẽ ghi đè phương thức gọi của JavaScript không? Cuộc gọi và áp dụng các phương thức lấy làm tham số đầu tiên một đối tượng để xác định đối tượng ngữ cảnh (this) này để áp dụng cho lời gọi.

Các vấn đề liên quan