"это" внутри анонимной функции?
Внутри книги Джона Ресига "Техники 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