Привилегированные методы - как получить значения свойств, которые передаются в функцию?
(пример из книги, но я, кажется, не понимаю)
function User (properties){
for( var i in properties){
(function(){
this["get"+i] = function () { return properties[i];};
this["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) ();
}// END for
}// END User
var userOne = new User ({ name: "Billy", age: 35 });
userOne.getname();
Когда я запускаю это, пользователь не имеет getname
метод. Как сделать так, чтобы привилегированный метод работал?
4 ответа
Это потому, что вы использовали немедленно вызванную функцию
for( var i in properties){
(function(){ //<--- This
this["get"+i] = function () { return properties[i];};
this["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) ();
}
Удалите его, и он все равно не будет работать, но ваши методы будут там. Чтобы он работал полностью, вы должны сохранить i
for( var i in properties){
(function(i){ //<--- This
this["get"+i] = function () { return properties[i];};
this["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) (i); //<--- and this
}
Последний вопрос не так интересен (хотя и связан с) первым.
Javascript имеет только то, что известно как "область действия функции", что означает, что единственное, что ограничивает область действия функции - это... ну... функция. Таким образом, обычным делом является использование IIFE, подобных этому, внутри циклов for или во многих местах, где вы не хотите, чтобы переменные вытекли.
Тем не менее this
Параметр в JavaScript странный. Поймите следующее, и это сэкономит вам массу хлопот: this
в javascript ничем не отличается от любого другого параметра.
Позволь мне объяснить.
Есть четыре способа вызвать функцию в JavaScript.
myFn.call("this param", "param 1", "param 2"); //this is "this param"
myFn.apply("this param", ["param 1", "param 2"]); //this is "this param"
myFn("param 1", "param 2");
//javascript takes a guess at what `this` should be -
//usually it is set to the global `window`.
new myFn("param 1", "param 2");
//`this` is a new function with its' prototype set to myFn.prototype
Если бы вы всегда использовали .call
форма двусмысленности исчезнет, и вы можете видеть, что this
точно так же, как любой другой параметр. Однако это дополнительный синтаксис, и люди предпочитают использовать более простую форму, что означает, что вы должны учитывать правила для того, что является "этим".
Поэтому то, что вы делаете в своем примере, это размещение геттеров и сеттеров на глобальном уровне. window
объект.
Здесь я сделаю заявление, что ваша книга, вероятно, не согласна с этим, но я извлек его из многолетнего обучения, работы и преподавания javascript:
Не используйте new
а также this
ключевые слова.
Эти два ключевых слова вводят в JS массу концепций, которые сбивают с толку и действительно - если вы не делаете что-то очень чувствительное к производительности (вы не знаете, я так думаю, но это не так) - не обязательно. Вместо этого создайте новые объекты просто так:
var user = { name: "Billy", age: 35 };
если вам абсолютно необходимы геттеры и сеттеры, это сделает это:
function createObjectWithProps (properties){
var obj = {};
var state = {}[
for( var k in properties){
(function(key) {
obj["get"+key] = function () { return state[key];};
obj["set"+key] = function (valueOne) { state[key] = valueOne; };
})(k)
}
return obj;
}
var userOne = createObjectWithProps ({ name: "Billy", age: 35 });
userOne.getname();
Хотя я пойду еще дальше, чтобы заявить, что геттеры и сеттеры не очень полезны в js, и когда вы их используете, стандартно следовать шаблону, подобному тому, что делает нокаут.
Вам нужны оба this
а также i
захвачено в закрытии:
function User (properties){
for( var i in properties){
(function(t, i){
t["get"+i] = function () { return properties[i];};
t["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) (this, i);
}// END for
}// END User
this
это не то, что вы думаете, это. Так как вы вызвали IIFE ни на что, this
будет глобальной областью действия, поэтому окно получит методы getname
и т. д., что не то, что вы ожидали.
Чтобы исправить это, если вы хотите сохранить IIFE, вам нужно вызвать его в правильном контексте:
function User (properties){
for( var i in properties){
(function(key){
this["get"+key] = function () { return properties[key];};
this["set"+key] = function (valueOne) { properties[key] = valueOne; };
}).call(this, i);
}// END for
}// END User
var userOne = new User ({ name: "Billy", age: 35 });
userOne.getname();
Обратите внимание, что вы также забыли передать i
аргумент функции и интерпретировать его как параметр. В противном случае все функции будут привязаны к одному и тому же ключу, таким образом, userOne.getname
вернется 35.
Проблема заключается в ключевом слове "это".
Поскольку вы используете его внутри немедленно вызванной функции, он указывает на глобальную область.
попробуй это:
function User (properties){
for( var i in properties){
(function(self,i){
self["get"+i] = function () { return properties[i];};
self["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) (this,i);
}// END for
}// END User