Các đối tượng JavaScript và Phần tốt của Crockford


8

Gần đây tôi đã suy nghĩ khá nhiều về cách thực hiện OOP trong JS, đặc biệt là khi nói đến việc đóng gói và kế thừa, gần đây.

Theo Crockford, cổ điển có hại vì mới () và cả nguyên mẫu và cổ điển đều bị hạn chế do việc sử dụng constructor.prototype của chúng có nghĩa là bạn không thể sử dụng các bao đóng để đóng gói.

Gần đây, tôi đã xem xét một vài điểm sau đây về đóng gói:

  1. Đóng gói giết chết hiệu suất . Nó làm cho bạn thêm các hàm vào MACHI đối tượng thành viên thay vì vào nguyên mẫu, bởi vì các phương thức của mỗi đối tượng có các cách đóng khác nhau (mỗi đối tượng có các thành viên riêng khác nhau).

  2. Encapsulation buộc cách giải quyết "var that = this" xấu xí này, để có được các hàm trợ giúp riêng có quyền truy cập vào thể hiện mà chúng được đính kèm. Hoặc là hoặc chắc chắn rằng bạn gọi chúng bằng privateFunction.apply (cái này) mọi lúc.

Có cách giải quyết cho một trong hai vấn đề tôi đã đề cập không? Nếu không, bạn vẫn coi đóng gói là xứng đáng?

Sidenote: Mẫu chức năng mà Crockford mô tả thậm chí không cho phép bạn thêm các phương thức công khai chỉ chạm vào các thành viên công cộng, vì nó hoàn toàn bỏ qua việc sử dụng new () và constructor.prototype. Sẽ không phải là một cách tiếp cận hỗn hợp trong đó bạn sử dụng kế thừa cổ điển và new (), mà còn gọi Super.apply (điều này, đối số) để khởi tạo các thành viên riêng và phương thức đặc quyền, có vượt trội không?


Tôi nghĩ rằng có một số thư viện JavaScript cung cấp tất cả điều này, ví dụ Dojo . Ngoài ra còn có TypeScript .
MarkJ

Hệ thống lớp của @MarkJ Dojo dường như giống hệt với các thư viện thừa kế giả cổ điển, và không cung cấp bất cứ điều gì liên quan đến đóng gói.
Jonathan

Btw, bài viết đó đang hạ thấp việc sử dụng bộ nhớ. Nó hoàn toàn không xem xét việc sử dụng bộ nhớ tăng theo số lượng phương thức .. ví dụ: nếu anh ta có 20 phương thức trên "lớp", mẫu chức năng sẽ mất 3000 mb với các số của anh ta nhưng nguyên mẫu vẫn sẽ mất 150mb bất kể số lượng phương pháp. Nó giống như so sánh O(1)với O(n)với n = 2...
Esailija

Câu trả lời:


2

Đóng gói là thực sự khó khăn và có lẽ không đáng để nỗ lực trong JavaScript. Một phương thức hoạt động và thực hiện mọi thứ bạn muốn (trường riêng, truy cập vào siêu lớp và phương thức riêng) sẽ là giải pháp (có thể rất xấu và dễ ứng dụng):

function SomeClass() {

    var parent = SomeSuperClass(),
        somePrivateVar;

    return Object.create(parent, {
        somePrivateVar: {
            get: function() {
                return somePrivateVar;
            },
            set: function(value) {
                somePrivateVar = value;
            }
        },
        doSomething: {
            value: function(data) {
                someHelperFunction.call(this, data);
            }
        }
    });
}

function someHelperFunction(data) {
    this.someMethod(data);
}

Loại công việc này, cho phép bạn có các trường riêng và phương thức và kế thừa như người ta mong đợi. Tuy nhiên, tôi không thích nó - nhưng tôi thích nó nhất trong tất cả các khả năng bạn có trong JavaScript thuần túy.

Nếu tôi phải bắt đầu một dự án mới với rất nhiều JavaScript, có lẽ tôi sẽ xem xét kỹ hơn về TypeScript . Nó cải thiện JavaScript khi cần thiết (IMHO), cung cấp cho bạn kiểu gõ tĩnh, kế thừa, đóng gói và mọi thứ .. Nhưng cuối cùng chỉ là JavaScript.


Bây giờ, nó có đáng không? Tôi nghĩ có hai điều quan trọng cần xem xét. Đóng gói có thể giúp bạn trong thời gian phát triển, nhưng chắc chắn không có trong thời gian chạy. Tôi nghĩ bạn phải quyết định; Không đóng gói và hiệu suất tốt hơn, hoặc đóng gói, mã không đẹp, có thể là một thiết kế tốt hơn nhưng một số chi phí trong thời gian chạy.


Tôi biết về mẫu này: đó là cái mà Crockford gọi là chức năng, với một chút khác biệt mà bạn đặt cha mẹ làm nguyên mẫu của con. Câu hỏi chính xác là: việc đóng gói có xứng đáng với chi phí được đề cập trong OP của tôi (và hiện trong mã của bạn) không? Có cách nào để có được xung quanh nói trên không? TypeScript có vẻ thú vị bởi vì việc kiểm tra đóng gói được thực hiện vào thời gian biên dịch, điều đó có nghĩa là không có chi phí nào trong JS được biên dịch, nhưng hiện tại, tôi vẫn gắn bó với JS thô. Để thống nhất, mã của bạn có thể nên đọc var Parent = someSuperClass (), không có mới.
Jonathan

@Jonathan: Tôi đã thêm một số thông tin về câu hỏi "đáng giá".
Bruno Schäpper
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.