2010-04-11 30 views
6

Tôi đang cố gắng tạo đối tượng UserDon và cố gắng tạo phương thức get và set theo lập trình (dựa trên cuốn sách Javascript của John Resig trang 37) và thử nghiệm trên Firefox 3.5Tạo phương pháp get/set động trong javascript

Vấn đề là: trong hàm UserDon, "this" dùng để chỉ đối tượng cửa sổ thay vì đối tượng UserDon.

Vì vậy, sau khi gọi var userdon = new UserDon (...), tôi đã thiết lập các phương thức setname và getname được tạo trên đối tượng cửa sổ (cũng là setage và getage).

Làm cách nào để khắc phục sự cố này?

function UserDon(properties) { 
    for(var i in properties) { 
    (function(){ 
     this[ "get" + i ] = function() { 
     return properties[i]; 
     }; 

     this[ "set" + i ] = function(val) { 
     properties[i] = val; 
     }; 
     })(); 
    } 
} 

var userdon = new UserDon({ 
    name: "Bob", 
    age: 44 
}); 
+1

Tốt câu hỏi nếu điều này là một bài tập.Nếu không, nếu bạn không thực hiện bất kỳ thao tác bổ sung nào trong getters/setters, bạn hy vọng chỉ cần sử dụng các thuộc tính công khai và từ bỏ phương thức overhead. :) – deceze

Trả lời

7

Các this giá trị mà bạn đang sử dụng thuộc về các biểu hiện chức năng tự động gọi bạn có bên trong vòng lặp, và khi bạn gọi một hàm theo cách này, this sẽ luôn tham khảo các đối tượng toàn cầu.

Edit: tôi đã bỏ lỡ một thực tế rằng các biểu hiện chức năng là cố gắng để chụp biến để xử lý việc tạo ra getter/setter bên trong vòng lặp, nhưng vòng lặp biến i, cần phải được thông qua như là một đối số theo thứ tự để làm điều đó và kể từ khi biểu hiện chức năng là có, bối cảnh (bên ngoài this) cần được bảo tồn:

function UserDon(properties) { 
    var instance = this; // <-- store reference to instance 

    for(var i in properties) { 
    (function (i) { // <-- capture looping variable 
     instance[ "get" + i ] = function() { 
     return properties[i]; 
     }; 

     instance[ "set" + i ] = function(val) { 
     properties[i] = val; 
     }; 
    })(i); // <-- pass the variable 
    } 
} 

var userdon = new UserDon({ 
    name: "Bob", 
    age: 44 
}); 

userdon.getname(); // "Bob" 
userdon.getage(); // 44 

Bạn cũng có thể sử dụng phương pháp call để gọi biểu hiện chức năng, giữ gìn bối cảnh (giá trị của this) và introdu cing biến đi vòng qua các phạm vi mới trong một bước duy nhất:

function UserDon(properties) { 
    for(var i in properties) { 
    (function (i) { // <-- looping variable introduced 
     this[ "get" + i ] = function() { 
     return properties[i]; 
     }; 

     this[ "set" + i ] = function(val) { 
     properties[i] = val; 
     }; 
    }).call(this, i); // <-- preserve context and capture variable 
    } 
} 

Tôi cũng muốn giới thiệu để sử dụng một if (properties.hasOwnProperty(i)) { ... } bên trong for...in vòng lặp để tránh iterating qua sử dụng mở rộng tài sản thừa kế từ Object.prototype.

+1

Nếu không có chức năng tự động gọi, cả getname() và getage() sẽ trả về 44, vì đóng tham chiếu giá trị cuối cùng của mảng, là độ tuổi, hãy tham khảo trang 29 của cuốn sách. – portoalet

+0

@ portoalet: Bạn đúng Tôi đã bỏ lỡ điểm đó, nhưng điều đó là không đủ, biến 'i' phải được chuyển như một đối số cho hàm đó, còn giá trị' này' phải được giữ nguyên, xem phần chỉnh sửa của tôi. – CMS

+0

Cảm ơn, nó bây giờ hoạt động hoàn hảo. – portoalet

0

Có thể là một ý tưởng tốt hơn để có được một hàm chung với 2 tham số: tên của thuộc tính và giá trị (hoặc chỉ có tên cho trình lấy). Và chức năng này sẽ kiểm tra sự hiện diện của một hàm speial cho thuộc tính này và nếu không có bất kỳ, nó sẽ thay đổi giá trị của thuộc tính (hoặc trả về giá trị của nó cho getter).

0

Sau đây là cách tôi sẽ mã nó: -

function UserDon(properties) { 
    var self = this; 
    for(var i in properties) { 
    (function(prop){ 
     self[ "get" + prop ] = function() { 
     return properties[prop]; 
     }; 

     self[ "set" + prop ] = function(val) { 
     properties[prop] = val; 
     }; 
     })(i); 
    } 
} 
1

Bạn cũng có thể sử dụng ít được biết đến
__defineGetter__("varName", function(){});
__defineSetter__("varName", function(val){});

Mặc dù họ không chuẩn [như x-html-thay thế loại nội dung] chúng được hỗ trợ bởi phần lớn các trình duyệt không có nghĩa là ở đó [chrome, firefox]

Cú pháp sẽ là:

benjamin = new object(); 
benjamin.__defineGetter__("age", function(){ 
    return 21; 
}); 

Hoặc bạn có thể tiếp cận với mẫu

benjamin = { 
    get age() 
    { 
    return 21; 
    } 
} 
+0

chưa bao giờ thấy điều này trước đây. Bạn có tự mình sử dụng nó không? – portoalet

+1

Tôi chỉ sử dụng nó để gỡ lỗi trong đó một biến đang được lấy/set-ed. Bạn defineSetter ("variableName", outputStackTrace); và nó cũng hoạt động với các kiểu css. Ví dụ, bạn nói 'object.style .__ defineGetter __ (" left ", outputStackTraceFunction);' Vì một số lý do mọi người không biết về hàm này. Có lẽ vì không chuẩn? – Warty

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