2012-09-07 8 views
11

Trong Javascript, có vẻ như việc sử dụng các trình truy cập thuộc tính không phải là tất cả những gì phổ biến (không giống như các ngôn ngữ OO khác chẳng hạn như Java chẳng hạn).javascript property accessors

Nếu tôi có một đối tượng Person với một cái tên, định nghĩa là

function Person(name) { 
    this.name = name; 
} 

tên của một người sẽ không thay đổi, nhưng tôi muốn để có thể truy cập vào nó khi cần thiết, vì vậy tôi có thể làm điều gì đó như:

function Person(name) { 
    var name = name; 
    this.getName = function() { 
     return name; 
    } 
} 

Ngay cả trong một ngôn ngữ năng động, tôi nghĩ rằng các nguyên tắc của việc sử dụng getter và setter áp dụng giống như cách họ làm để tĩnh gõ ngôn ngữ OO (ví dụ như đóng gói, thêm xác nhận, hạn chế truy cập, vv)

Câu hỏi này có thể bị đóng là chủ quan, nhưng tôi tò mò là tại sao hành vi này không xuất hiện thường xuyên hơn (ví dụ: Các nhà phát triển Java sẽ phát điên nếu mọi thứ đều được công khai).

Có cách nào "chuẩn" để thực hiện việc này trong javascript không? Tôi đã thấy Object.defineProperty, nhưng không phải tất cả các trình duyệt đều hỗ trợ điều đó.

+0

Tôi cho rằng nó có thể liên quan một phần đến mong muốn giảm tải băng thông. Đánh dấu bổ sung nghĩa là các bit phụ trên dây. Trong trường hợp của một ví dụ nhỏ như thế này, nó có thể không có vẻ liên quan, trong một ứng dụng mạnh mẽ bao trùm hàng chục nghìn dòng, nó có thể trở nên quan trọng. – Shmiddty

+0

Định nghĩa bổ sung cũng có nghĩa là sử dụng bộ nhớ bổ sung trên máy khách, dọc theo các dòng giống như nhận xét trước của tôi. – Shmiddty

+0

Tôi nghĩ rằng các câu trả lời đã được đưa ra cho thấy rằng đây không phải là một câu hỏi hay cho SO vì nó dễ bị câu trả lời dựa trên ý kiến. – madth3

Trả lời

15

Javascript có accessors tài sản đánh chặn-thể:

http://ejohn.org/blog/javascript-getters-and-setters/

IMHO này là một giải pháp tốt hơn để thực thi các nguyên tắc truy cập Uniform hơn getters rõ ràng nghiêm ngặt hơn của Java, nhưng điều đó cũng là một phần của sự đơn giản và tính không linh hoạt của ngôn ngữ đó (ví dụ như Groovy cho phép đánh chặn tương tự).

+0

trong thực tế, điều này được nhìn thấy rất nhiều? Hoặc thông thường bạn có thấy quyền truy cập thuộc tính trực tiếp không? –

+0

Bạn muốn sử dụng quyền truy cập thuộc tính trực tiếp trừ khi bạn cần sửa đổi logic truy cập: sau đó bạn sẽ sử dụng tính năng chặn. Bạn có thể cần phải tự hỏi mình _why_ bạn sử dụng getters và setters trong Java nếu họ không làm bất cứ điều gì: lý do thực tế thực tế đằng sau giáo lý đóng gói là gì. –

+0

Thỉnh thoảng tôi tự hỏi tại sao, đặc biệt là các thuộc tính đơn giản. Về mặt lý thuyết, ý tưởng là nếu bạn muốn thêm một số hành vi khác trong getter hoặc setter (ví dụ: ghi nhật ký, xác thực, v.v.). Nhưng trong thực tế, điều đó không xảy ra thường xuyên trên các thuộc tính đơn giản, do đó, nó là một quy ước Java (tôi thích cách thức mà nó không khai thác rõ ràng các getters và setters nhưng chúng được tạo ra và tự động được gọi, nhưng cho phép bạn viết cú pháp truy cập thuộc tính thẳng). –

3

Tôi nghĩ câu trả lời là các lớp mô phỏng trong javascript không phải là thực tế phổ biến, bởi vì ngôn ngữ thực sự là nguyên mẫu.

Mặc dù có thể tạo lớp như cấu trúc (như trong ví dụ của bạn), chúng không thực sự giống như các lớp java, và là một lập trình viên, bạn sẽ phải chiến đấu với các sắc thái.

Nếu tuy nhiên, bạn nắm lấy bản chất nguyên mẫu của javascript, bạn được thưởng bằng một cấu trúc khác, nhưng gắn kết và đơn giản cho ngôn ngữ. Không cần thiết phải sử dụng getters và setters với cấu trúc nguyên mẫu, vì bạn có thể chỉ cần thiết lập một đối tượng bằng cách, tốt, thiết lập nó thành một giá trị, và làm cho nó bằng cách, gọi nó như là một giá trị.

Javascript không bắt buộc bạn phải viết mã có cấu trúc và không ngăn bạn làm như vậy. Tôi nghĩ rằng văn hóa đã phát triển xung quanh javascript đã phát triển một phong cách mã hóa tốt, đó là hoàn toàn hợp lệ, và khác với bất kỳ ngôn ngữ khác tôi sử dụng.

Tôi biết câu trả lời này là không dứt khoát, và kết luận, nhưng hy vọng có một số ý tưởng trong đó giúp bạn tìm anser bạn đang tìm kiếm.

+1

cảm ơn. Bạn có thể làm cùng một giá trị get/set trực tiếp trong java (ví dụ, nếu bạn đã tạo ra những thứ công khai), nhưng điều đó dường như bị cau mày. Tôi đoán rất nhiều việc phải làm với những gì thành ngữ của ngôn ngữ đã trở thành. –

+1

Một vấn đề lớn trong Java là bạn không muốn phải thay đổi giao diện của lớp của bạn sau này. Là một ngôn ngữ được biên dịch được thiết kế để bảo trì mã dài hạn, các ưu tiên khác với JS, một ngôn ngữ dựa trên nguồn được triển khai trong một môi trường web thay đổi nhanh chóng. –

7

Tôi biết suy nghĩ của mình về chủ đề này.

Getters and setters is evil.

Đợi đã! Có thật không! Hãy chịu đựng tôi một chút và để tôi giải thích.

Chỉ cần sử dụng phương pháp để lấy và đặt giá trị là .. tốt .. kinda vô nghĩa. Nó không bảo vệ, không thực sự, và những gì bạn đưa vào là những gì bạn nhận ra.

Mặt khác, tôi thích các phương pháp đưa thông tin vào, sau đó lấy lại thông tin. NHƯNG ở đây là phần ma thuật! Nó không phải là thông tin tương tự. Không trực tiếp.

function Person(name) { 
    this.getFullName = function() {return this.firstName + " " + this.lastName;}; 
    this.setBirthday = function(date) { this.birthday = date; }; 

    this.getAge = function() { /* Return age based on the birthday */ }; 
    this.isOfLegalDrinkingAge function() { /* do your math here too */ }; 
} 

Nhưng hầu hết thời gian tôi chỉ đẩy dữ liệu tĩnh vào và lấy dữ liệu tĩnh. Điểm ẩn đằng sau getters và setters là gì?

Là lý do phụ, xử lý DOM và hầu hết các đối tượng lưu trữ, bạn đặt thuộc tính. Bạn không chơi với getters và setters. Không sử dụng chúng phù hợp với phần còn lại của 'hương vị' của những gì mà các lập trình viên JS làm.

+0

@BillyMoon - Kỳ quan nếu anh ta có thể thay đổi tên người dùng của mình thành "Người thuyết giảng Javascript" –

+0

Cảm ơn bạn đã giải thích. Tôi nghĩ rằng nó không phải là "hương vị" javascript thực sự là những gì tôi đã nhận được sau khi ở đây. –

+0

Vấn đề của tôi với điều này là tự hỏi liệu mọi thứ là các hàm hay thuộc tính. Đôi khi nó có vẻ có vẻ tùy ý. Person.firstName hoạt động, nhưng Person.firstName() không trong khi trái tôi cần phải sử dụng Person.fullName() thay vì Person.fullName ... – CuddleBunny

0

Tôi xin lỗi nếu tôi không hiểu câu hỏi một cách chính xác, nhưng chức năng tự thực hiện là một trong những cách để làm cho các thành viên public/private

var Person = function(){ 
    var _name = "Roger", 
     self = { getName : function(){ return _name; }}; 
    return self; 
}() 

Sau đó bạn có thể truy cập person.getName() từ bất cứ nơi nào, nhưng không được thiết lập _name .

+1

Tôi biết bạn có thể làm điều này, có vẻ như nó không thực sự phổ biến ... –

1

Đây là những gì tôi đã sử dụng cho các lĩnh vực địa phương:

TYPE_DEFAULT_VALUE= { 
    number: 0, 
    string: "", 
    array: [], 
    object: {}, 
}; 

typeOf = function (object) { 
    if (typeof object === "number" && isNaN(object)) 
     return NaN; 
    try { 
     return Object.prototype.toString.call(object).slice(8, -1).toLowerCase(); 
    } 
    catch(ex) { 
     return "N/A"; 
    }; 
}; 

getAccessor = function(obj, key, type, defaultValue) { 
    if (defaultValue === undefined) 
     defaultValue = TYPE_DEFAULT_VALUE[type] === undefined ? null : TYPE_DEFAULT_VALUE[type]; 
    return { 
     enumerable: true, 
     configurable: true, 
     get: function() { 
      if (obj[key] === undefined) 
       obj[key] = defaultValue; 
      return obj[key]; 
     }, 
     set: function (value) { 
      if (typeOf(value) === type) 
       obj[key] = value; 
     }, 
    }; 
} 

LocalFields = function (fields, object) { 
    /** 
    * field properties 
    * { 
    * type: [ required ] (number | string | array | object | ...), 
    * defaultValue: [ optional ] 
    * } 
    */ 
    if (! fields) 
     throw "Too few parameters ..."; 
    if (! object) 
     object = this; 

    var obj = this; 
    var fieldsAccessor = {}; 
    for(key in fields){ 
     field = fields[key]; 
     fieldHandler = key[0].toUpperCase() + key.substr(1); 
     if(! field.type) 
      throw "Type not set for field: " + key; 

     fieldsAccessor[fieldHandler] = getAccessor(obj, fieldHandler, field.type, field.defaultValue) 
    } 
    Object.defineProperties(object, fieldsAccessor); 
} 

Bây giờ cho mỗi lớp tôi chỉ có thể gọi một cái gì đó như:

Person = function(){ 
    new LocalFields({ 
     id:  { type: "number" }, 
     name: { type: "string" }, 
    }, this); 
} 

Và rồi như VS getter và setter bạn sẽ gọi:

var alex = new Person(); 
alex.Name = "Alex Ramsi"; 
console.clear(); 
console.info(alex.Name);