2012-03-04 34 views
8

Bên John Resig của "kỹ thuật Javascript Pro" ông mô tả một cách để tạo ra phương pháp đối tượng năng động với mã dưới đây:"này" bên trong một chức năng ẩn danh? Cuốn sách

// Create a new user object that accepts an object of properties 
function User(properties) { 
    // Iterate through the properties of the object, and make sure 
    // that it's properly scoped (as discussed previously) 
    for (var i in properties) { 
     (function() { 
      // Create a new getter for the property 
      this["get" + i] = function() { 
       return properties[i]; 
      }; 
      // Create a new setter for the property 
      this["set" + i] = function(val) { 
       properties[i] = val; 
      }; 
     })(); 
    } 
} 

Vấn đề là khi tôi cố gắng instantiating đối tượng trên, các phương pháp năng động đang được gắn vào đối tượng cửa sổ thay vì đối tượng được khởi tạo. Nó có vẻ như "này" là đề cập đến cửa sổ.

// Create a new user object instance and pass in an object of 
// properties to seed it with 
var user = new User({ 
name: "Bob", 
age: 44 
}); 

alert(user.getname()); 

Chạy mã trên sẽ ném lỗi này "user.getname không phải là hàm".

Cách chính xác để tạo các chức năng động cho từng đối tượng được khởi tạo là gì?

+7

Tôi chắc chắn John Resig đã sử dụng thụt đầu dòng thích hợp. –

+1

Điều này có vẻ không đúng. Bên trong hàm ẩn danh, 'this' là' window'. –

+0

Câu trả lời là * không * thụt lề, nhưng nó ** là thụt đầu dòng **. Bàn luận. –

Trả lời

11

Mã này có phải là từ sách không? Tôi có cuốn sách, nhưng tôi chưa đọc qua nó.

Đó là lỗi trong sách. Kiểm tra errata: http://www.apress.com/9781590597279

Bên trong chức năng ẩn danh, this là toàn cầu window.

Bạn có thể làm cho nó hoạt động bằng cách thêm .call(this, i) sau nó.

function User(properties) { 
    // Iterate through the properties of the object, and make sure 
    // that it's properly scoped (as discussed previously) 
    for (var i in properties) { 
     (function(i) { 
      // Create a new getter for the property 
      this["get" + i] = function() { 
       return properties[i]; 
      }; 
      // Create a new setter for the property 
      this["set" + i] = function(val) { 
       properties[i] = val; 
      }; 
     }).call(this, i); 
    } 
} 
+2

* Tôi có cuốn sách, nhưng tôi chưa đọc nó. * Vậy thì ** có ** bạn đã làm gì với nó? Bookstop? Nguồn sợi gỗ? Hình nền? –

+2

+1 để khắc phục sự cố với 'i' được ghi lại. – ruakh

+0

@JaredFarrish: Nó được sử dụng để giữ các cuốn sách trên kệ của tôi đối xứng. Không, nhưng nghiêm túc, tôi chỉ cần một chút thời gian để thực sự đọc nó :-P –

3

this trong chức năng tự thực hiện bên trong không giống như chức năng này ở bên ngoài chức năng User. Như bạn thấy, nó đề cập đến toàn cầu window.

Sự cố được khắc phục nếu bạn sửa đổi một chút mã bằng cách thêm biến đề cập đến bên ngoài this.

function User(properties) { 
    var self = this; 
    for (var i in properties) { 
    (function() { 
     self["get" + i] = function() { /* ... */ }; 
     self["set" + i] = function() { /* ... */ }; 
    })(); 
    } 
} 

Điều đó nói rằng, tôi không chắc chắn lý do tại sao chức năng tự thực hiện nặc danh được thậm chí cần thiết ở đây, vì vậy bạn có tùy chọn đơn giản chỉ để lại nó ra hoàn toàn, như thế này:

function User(properties) { 
    for (var i in properties) { 
     this["get" + i] = function() { /* ... */ }; 
     this["set" + i] = function() { /* ... */ }; 
    } 
} 
1

Đây là cách thực hiện. Bạn cần phải lưu ngữ cảnh vào một biến khác. Các tùy chọn khác không phải là để làm chức năng bên trong này mà bạn đang làm trong vòng lặp for.

// Create a new user object that accepts an object of properties 
function User(properties) { 
    // Iterate through the properties of the object, and make sure 
    // that it's properly scoped (as discussed previously) 
    var that = this; 
    for (var i in properties) { (function(){ 
     // Create a new getter for the property 
     that[ "get" + i ] = function() { 
      return properties[i]; 
     }; 
     // Create a new setter for the property 
     that[ "set" + i ] = function(val) { 
      properties[i] = val; 
     }; 
    })(); } 
} 

Phương án 2:

// Create a new user object that accepts an object of properties 
function User(properties) { 
    // Iterate through the properties of the object, and make sure 
    // that it's properly scoped (as discussed previously) 
    for (var i in properties) { 
     // Create a new getter for the property 
     this[ "get" + i ] = function() { 
      return properties[i]; 
     }; 
     // Create a new setter for the property 
     this[ "set" + i ] = function(val) { 
      properties[i] = val; 
     }; 
    } 
} 
+0

Cả hai tùy chọn này đều không hoạt động khi chúng sử dụng phiên bản đã bắt của 'i' thay đổi khi vòng lặp đang được thực thi và để 'i' làm tên thuộc tính cuối cùng. Một phần của ví dụ của John là cách tránh vấn đề này. Tùy chọn 1 có thể dễ dàng được sửa, tuy nhiên, bằng cách chuyển 'i' làm tham số. Để khắc phục Tùy chọn 2, bạn sẽ biến nó thành phiên bản cố định của Tùy chọn 1. – chuckj

1

Bạn luôn có thể buộc this khác cho bất kỳ cuộc gọi chức năng, sử dụng phương pháp apply.

(function() { 
    // Create a new getter for the property 
    this["get" + i] = function() { 
     return properties[i]; 
    }; 
    // Create a new setter for the property 
    this["set" + i] = function(val) { 
     properties[i] = val; 
    }; 
}).apply(this); 
Các vấn đề liên quan