Tận dụng tính kế thừa nguyên mẫu của JavaScript


7

JavaScript có một hệ thống đối tượng không có lớp trong đó các đối tượng kế thừa các thuộc tính trực tiếp từ các đối tượng khác. Điều này thực sự mạnh mẽ, nhưng nó còn xa lạ với các lập trình viên được đào tạo bài bản. Nếu bạn cố gắng áp dụng các mẫu thiết kế cổ điển trực tiếp vào JavaScript, bạn sẽ thất vọng. Nhưng nếu bạn học cách làm việc với bản chất nguyên mẫu của JavaScript, những nỗ lực của bạn sẽ được đền đáp.
...
Đó là Lisp trong trang phục của C.

- Douglas Crockford

Điều này có ý nghĩa gì với một nhà phát triển trò chơi làm việc với canvas và HTML5? Tôi đã xem qua câu hỏi này về các mẫu thiết kế hữu ích trong chơi game, nhưng thừa kế nguyên mẫu rất khác so với thừa kế cổ điển, và chắc chắn có những khác biệt trong cách tốt nhất để áp dụng một số mẫu phổ biến này.

Ví dụ, thừa kế cổ điển cho phép chúng ta tạo ra một moveableEntitylớp, và mở rộng điều đó với bất kỳ lớp học rằng động thái trên thế giới trò chơi của chúng tôi ( player, monster, bullet, vv). Chắc chắn, bạn có thể mạnh mẽ để JavaScript hoạt động theo cách đó, nhưng khi làm như vậy, bạn là loại chiến đấu chống lại bản chất của nó. Có cách tiếp cận nào tốt hơn cho loại vấn đề này khi chúng ta có quyền thừa kế nguyên mẫu trong tầm tay?

Câu trả lời:


8

Để có được hiệu năng tốt từ JavaScript với các công cụ JS hiện đại, người ta cần viết mã phản ánh các kiểu gõ cấu trúc phổ biến hoặc kiểu gõ vịt. Kiểu gõ cấu trúc mạnh hơn việc cung cấp các kiểu chỉ bằng cách thừa kế nhưng không thực sự thay đổi các mẫu thiết kế được sử dụng bởi các trò chơi.

Ví dụ, trong C ++ hoặc Java, trong đó người ta thường gõ theo kế thừa, người ta thường có hệ thống phân cấp kiểu sâu với một số giao diện / lớp ảo để thực hiện MVC. Nhưng các trò chơi đã tránh xa kiểu mẫu thiết kế này vì nó không thực sự giúp mô hình hóa các loại trò chơi dữ liệu.

Các mẫu mà người ta thấy hữu ích nhất trong thiết kế trò chơi, như các đối tượng bối cảnh, các thành phần, trọng lượng hoặc chiến lược, không có xu hướng sử dụng hệ thống phân cấp thừa kế phức tạp ngay từ đầu, ngay cả khi được triển khai bằng các ngôn ngữ như C ++. Các thành phần liên quan đến một lớp ảo duy nhất (nhiều nhất). Flykg thường sử dụng kiểu gõ cấu trúc (vụng về) của C ++ thông qua các mẫu. Chiến lược thường sử dụng một số hình thức xóa kiểu cho hiệu suất hoặc sự tỉnh táo của lập trình viên.

Một ngoại lệ cho điều này là bản thân mẫu thử nghiệm, thường được tìm thấy ở một số dạng trong các trò chơi, đặc biệt là đối với dữ liệu do nhà thiết kế điều khiển. Sử dụng JavaScript làm cho mô hình này trở nên tầm thường. Nhưng nó không phải là một mô hình đặc biệt khó thực hiện, ít nhất là kém, trong bất kỳ ngôn ngữ nào hỗ trợ các cấu trúc dữ liệu liên kết. Sử dụng JS sẽ cho phép bạn sử dụng nó nhiều hơn vì bạn có thể tận dụng trình tối ưu hóa của công cụ cơ bản. Nhưng tôi không chắc liệu điều đó có thực sự thay đổi cách một chương trình hay không - một mẫu nguyên mẫu ngây thơ đã có rất nhiều nơi trong nhiều trò chơi mặc dù hiệu năng thường kém.


3
Tôi nhận được một upvote chưa đầy một phút sau khi đăng bài này, điều mà tôi từ chối tin là đủ thời gian để đọc nó và quyết định xem đó có phải là một câu trả lời tốt hay không. Tôi đã thấy một số dấu hiệu cho thấy một số người chỉ đơn giản nêu lên những câu trả lời dài và được viết mà không có ngữ pháp khủng khiếp. Xin đừng làm vậy.

Câu trả lời đặc biệt này chỉ đúng với bất kỳ nhà phát triển có kinh nghiệm. Tôi cũng ủng hộ nó gần như ngay lập tức, bởi vì khi tôi đọc nó, tôi giống như "Vâng, vâng, nó luôn hoạt động như thế này".
Không bao giờ bắt đầu

nói hay lắm! Tôi luôn cảm thấy rằng JS rất phù hợp với kiểu tiếp cận dựa trên dữ liệu và thành phần rất phổ biến trong các trò chơi nhưng không thể nói rõ bản thân mình :)
oberhamsi

6

Nếu bạn thực sự nghiên cứu về ngữ nghĩa, bạn sẽ thấy rằng JavaScript thực sự gần với hầu hết các ngôn ngữ dựa trên lớp hơn là một ngôn ngữ nguyên mẫu "thực" như Tự. Cách thức newhoạt động, bạn hầu như luôn tạo một đối tượng có chứa trạng thái trong các trường và phương thức riêng của nó trong các trường của nguyên mẫu. Nheo mắt lại và đó là một lớp học.

Để thực sự là nguyên mẫu, sẽ không có new. Bạn đang nhân bản các đối tượng và thực hiện kế thừa khác biệt.

Vì vậy, đừng thực sự lo lắng quá nhiều về bản chất nửa nguyên mẫu của JavaScript. Chỉ cần hiểu ba phần:

  1. Hầu hết thời gian, các đối tượng của bạn về cơ bản sẽ là các thể hiện của một "lớp" trong đó hàm tạo xác định các trường của nó và các hàm trên các hàm tạo prototypexác định phương thức.

  2. Nếu bạn muốn thừa kế đơn kiểu Java / C # quen thuộc, bạn có thể có được điều đó bằng cách xâu chuỗi các nguyên mẫu. Hầu hết các khung công tác JS ngoài kia (Đóng cửa, võ đường, v.v.) có một số phương thức trợ giúp tốt để kết nối nó.

  3. Bạn có thể thêm các phương thức vào bất kỳ "lớp" bất cứ lúc nào. Hãy thoải mái kết hợp các chức năng mà trên đó các nguyên mẫu cần chúng. Bạn không cần phải luôn thiết lập chuỗi thừa kế và phân cấp phức tạp. Nếu bạn có mười lớp cần cùng một phương thức, bạn luôn có thể thêm nó vào mười lớp đó.


Tôi thích cách làm thứ ba. Ví dụ: bạn có thể có một hàm "có thể phá hủy" để thêm thuộc tính sức khỏe và phương thức damage (). Sau đó, bạn có thể nhập mã mã khác của mình dựa trên sự hiện diện của dữ liệu / phương thức thực thay vì các giá trị kiểu "có thể thay đổi".
drhayes

1
Chính xác. Có một loạt các khung công tác JS cung cấp "mixins" thực hiện khá nhiều thứ đó: thêm một loạt các hàm vào một nguyên mẫu nhất định.
munificent
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.