Tiền tố gạch dưới cho tên thuộc tính và phương thức trong JavaScript


240

Có phải tiền tố gạch dưới trong JavaScript chỉ là một quy ước, ví dụ như trong các phương thức lớp riêng của Python là?

Từ tài liệu 2.7 Python:

Các biến đối tượng của riêng tư không thể truy cập được, ngoại trừ trong một đối tượng không tồn tại trong Python. Tuy nhiên, có một quy ước được tuân theo bởi hầu hết mã Python: tên có tiền tố gạch dưới (ví dụ _spam) phải được coi là một phần không công khai của API (cho dù đó là hàm, phương thức hay thành viên dữ liệu) .

Điều này cũng áp dụng cho JavaScript?

Lấy ví dụ mã JavaScript này:

function AltTabPopup() {
    this._init();
}

AltTabPopup.prototype = {
    _init : function() {
        ...
    }
}

Ngoài ra, các biến tiền tố gạch dưới được sử dụng.

    ...
    this._currentApp = 0;
    this._currentWindow = -1;
    this._thumbnailTimeoutId = 0;
    this._motionTimeoutId = 0;
    ...

Chỉ quy ước? Hoặc có nhiều hơn đằng sau tiền tố gạch dưới?


Tôi thừa nhận câu hỏi của tôi khá giống với câu hỏi này , nhưng nó không làm cho người ta thông minh hơn về tầm quan trọng của tiền tố gạch dưới trong JavaScript.


Câu trả lời:


33

Chào mừng đến năm 2019!

Nó xuất hiện một đề xuất mở rộng cú pháp lớp để cho phép #biến tiền tố là riêng tư được chấp nhận. Chrome 74 tàu với sự hỗ trợ này.

_ tên biến tiền tố được coi là riêng tư theo quy ước nhưng vẫn công khai.

Cú pháp này cố gắng vừa ngắn gọn vừa trực quan, mặc dù nó khá khác so với các ngôn ngữ lập trình khác.

Tại sao sigil # được chọn, trong số tất cả các điểm mã Unicode?

  • @ là yêu thích ban đầu, nhưng nó đã được trang trí bởi. TC39 đã xem xét việc hoán đổi trang trí và sigils nhà nước tư nhân, nhưng ủy ban đã quyết định trì hoãn việc sử dụng hiện tại của người dùng transpiler.
  • _ sẽ gây ra sự cố tương thích với mã JavaScript hiện tại, điều này đã cho phép _ khi bắt đầu một mã định danh hoặc tên thuộc tính (công khai) trong một thời gian dài.

Đề xuất này đạt đến Giai đoạn 3 vào tháng 7 năm 2017. Kể từ thời điểm đó, đã có nhiều suy nghĩ và thảo luận dài về các phương án khác nhau. Cuối cùng, quá trình suy nghĩ này và tiếp tục tham gia của cộng đồng đã dẫn đến sự đồng thuận mới về đề xuất trong kho lưu trữ này. Dựa trên sự đồng thuận đó, việc triển khai đang tiến tới đề xuất này.

Xem https://caniuse.com/#feat=mdn-javascript_groupes_private_group_fields


257

Đó chỉ là một quy ước. Ngôn ngữ Javascript không mang lại bất kỳ ý nghĩa đặc biệt nào cho các định danh bắt đầu bằng các ký tự gạch dưới.

Điều đó nói rằng, đó là một quy ước khá hữu ích cho một ngôn ngữ không hỗ trợ đóng gói ngoài hộp. Mặc dù không có cách nào để ngăn ai đó lạm dụng việc triển khai các lớp của bạn, nhưng ít nhất nó cũng làm rõ ý định của bạn và ghi lại hành vi như vậy là sai ngay từ đầu.


4
Vâng Ngay cả khi ngôn ngữ không "hỗ trợ" nó, đó vẫn là một quy ước thực sự tiện dụng.
Juho Vepsäläinen

Thăm dò nghiêm trọng. jsfiddle.net/VmFSR Như bạn có thể thấy, tên được tạo giá trị chỉ có thể truy cập bằng cách thêm tiền tố vào giá trị mới, được tạo, sử dụng _tôi rất muốn biết chuyện gì đang xảy ra!? Tại sao nó không this.namethay thế?
Muhammad Umer

1
@Muhammad Umer, tôi không chắc là tôi hiểu bình luận của bạn. console.log(someone._name = "Jean Dupont");hoạt động tốt như console.log(someone.name);, và nó vừa gán và đánh giá thành viên có tiền tố gạch dưới đằng sau tài sản. Như bạn có thể thấy , không có sự đóng gói được đảm bảo thông qua các dấu gạch dưới :)
Frédéric Hamidi

3
Theo mặc định, Visual Studio cố gắng giúp bạn tôn trọng điều này. Công cụ IntelliSense javascript hiển thị cho bạn các thuộc tính "riêng tư", từ bên trong đối tượng, khi sử dụng biến "này". Nhưng, khi được gọi từ bên ngoài, nó ẩn tất cả các thuộc tính thiếu.
foxontherock

1
@Karuhanga anh ấy đã trả lời điều này vào năm 2010 - tất nhiên mọi thứ đã thay đổi sau 10 năm
Kenny Meyer

99

JavaScript thực sự hỗ trợ đóng gói, thông qua một phương thức liên quan đến việc ẩn các thành viên trong các bao đóng (Crockford). Điều đó nói rằng, đôi khi nó cồng kềnh, và quy ước gạch dưới là một quy ước khá tốt để sử dụng cho những thứ riêng tư, nhưng bạn thực sự không cần phải che giấu.


19
Bỏ phiếu để làm rõ làm thế nào để đạt được sự đóng cửa, bỏ phiếu cho nói rằng dấu gạch dưới là quy ước tốt. Vì vậy, tôi sẽ không bỏ phiếu nào cả :)
Jason

3
Việc giấu các thành viên trong việc đóng cửa đôi khi có thể cản trở khả năng kiểm tra. Xem bài viết này: adequatelygood.com/2010/7/Writing-Testable-JavaScript
Zach Lysobey

4
@Jason - Chỉ tò mò, tại sao bạn coi gạch dưới là một quy ước tồi?
Tamás Pap

5
@TamasPap - Một vài lý do, nhưng chỉ là tùy chọn của tôi: 1) Một cái nạng để buộc JS thành một kiểu ngôn ngữ khác 2) Nếu có thể truy cập được, nó sẽ được sử dụng. Dấu gạch dưới có thể xả rác và làm rối mã bên ngoài. 3) Nhầm lẫn với các lập trình viên JS mới.
Jason

9
Ngay cả khi đóng cửa, về mặt kỹ thuật vẫn có thể có quyền truy cập vào biến được gọi là biến "riêng tư". _Convent ít nhất cho phép các nhà phát triển biết làm điều đó có nguy cơ của riêng họ (hoặc một cái gì đó tương tự).
sarink

14

JSDoc 3 cho phép bạn chú thích các chức năng của bạn với @access private(trước đây là @privatethẻ) cũng hữu ích để truyền đạt ý định của bạn tới các nhà phát triển khác - http://usejsdoc.org/tags-access.html


10

"Chỉ quy ước? Hay là có nhiều hơn đằng sau tiền tố gạch dưới?"

Ngoài các quy ước về quyền riêng tư, tôi cũng muốn giúp mang lại nhận thức rằng tiền tố gạch dưới cũng được sử dụng cho các đối số phụ thuộc vào các đối số độc lập, cụ thể trong các bản đồ neo URI. Các khóa phụ thuộc luôn trỏ đến một bản đồ.

Ví dụ (từ https://github.com/mmikowski/urianchor ):

$.uriAnchor.setAnchor({
  page   : 'profile',
  _page  : {
    uname   : 'wendy',
    online  : 'today'
  }
});

Neo URI trên trường tìm kiếm của trình duyệt được thay đổi thành:

\#!page=profile:uname,wendy|online,today

Đây là quy ước được sử dụng để điều khiển trạng thái ứng dụng dựa trên các thay đổi băm.


8

import/exporthiện đang thực hiện công việc với ES6. Tôi vẫn có xu hướng tiền tố không xuất các hàm với _nếu hầu hết các hàm của tôi được xuất.

Nếu bạn chỉ xuất một lớp (như trong các dự án góc cạnh), thì hoàn toàn không cần thiết.

export class MyOpenClass{

    open(){
         doStuff()
         this._privateStuff()
         return close();
    }

    _privateStuff() { /* _ only as a convention */} 

}

function close(){ /*... this is really private... */ }

Tôi không nghĩ rằng nhập / xuất cung cấp hỗ trợ cho các phương thức lớp riêng theo bất kỳ cách nào. Ý tôi là, nó hỗ trợ một chức năng tương tự ở cấp độ lớp, nhưng nó không cung cấp ẩn các phương thức được chứa. (tức là tất cả các phương thức được chứa luôn ở chế độ công khai)
bvdb

Bạn xuất lớp và hàm bên trong gọi hàm ngoài. Các chức năng này là tư nhân.
Nicolas Zozol
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.