"это" внутри анонимной функции?

Внутри книги Джона Ресига "Техники Pro Javascript" он описывает способ генерации методов динамического объекта с помощью приведенного ниже кода:

// 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;
            };
        })();
    }
}

Проблема в том, что когда я пытаюсь создать экземпляр вышеупомянутого объекта, динамические методы присоединяются к объекту окна, а не к объекту. Кажется, что "это" относится к окну.

// 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() );

Запуск приведенного выше кода выдает эту ошибку "user.getname не является функцией".

Как правильно генерировать динамические функции для каждого экземпляра объекта?

5 ответов

Решение

Это код из книги? У меня есть книга, но я не прочитал ее.

Это ошибка в книге. Проверьте исправления: http://www.apress.com/9781590597279

Внутри анонимной функции, this это глобальный window,

Вы можете сделать это, добавив .call(this, i) после этого.

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);
    }
} 

this во внутренней самоисполняющейся функции не совпадает с этим во внешней User функция. Как вы заметили, это относится к глобальному window,

Проблема исправлена, если вы немного измените код, добавив переменную, которая ссылается на внешний this,

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

Тем не менее, я не уверен, зачем здесь нужна анонимная самовыполняющаяся функция, поэтому у вас есть более простой вариант - полностью ее исключить, например:

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

Вот как это сделать. Вам нужно сохранить контекст в другую переменную. Другой вариант - не выполнять эту внутреннюю функцию, которую вы выполняете в цикле 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;
       };
    })(); }
}

Вариант 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;
       };
    }
}

Вы всегда можете заставить другого this для любого вызова функции, используя 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);

Вы также можете создать новую функцию, которая использует определенныйthisс.bindметод.

      function getaloadofthis() {return this}

Если вы сделаетеgetaloadofthis()он просто возвращаетсяwindowно если ты сделаешьgetaloadofthis.bind(3)()он возвращается3.

Таким образом, вы могли бы также иметь

      const getaloadofthis3 = getaloadofthis.bind(3)
getaloadofthis3() // 3

Это также работает с анонимными функциями

      (function() {return this}).bind(3)() // 3
Другие вопросы по тегам