2014-01-22 4 views
0

(пример из книги, но я, кажется, не понял)Привилегированные методы - как получить значения свойств, которые передаются функции?

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 метод. Как я могу использовать привилегированный метод?

+0

Возможно, позже они объяснят, что в этом плохого и что нужно изменить. – rid

ответ

1

Это потому, что вы использовали сразу же вызывается функция

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, и когда вы их используете, стандартно следовать шаблону, аналогичному тому, что делает knockout.

+2

Не будет ли это связывать 'i' внутри функций с последним' i'? – rid

+0

@rid это не так, потому что в то время, когда вы вызываете его, 'i' является« текущим »значением, то он выполняет итерацию. –

+1

Вы можете проверить результат. 'setname' будет существовать, но он вернет' 35'. – rid

-1

Проблема заключается в ключевом слове "this".

Поскольку вы используете его внутри сразу вызываемой функции, он указывает на глобальную область.

попробовать это:

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 
+0

Thanks rid, changed –

+0

Отсутствует! спасибо –

+0

Следует отметить, что вы также можете сделать '.call (this, i)', а не '(this, i)' и сохранить 'this [" get "+ ....' stuff. Я предпочитаю это так, как вы его написали. –

3

Вы нужны как 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 
2

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.

Смежные вопросы