Вызов функции внутри функции - PullRequest
1 голос
/ 05 декабря 2011

Когда я кодирую вещи, я пытаюсь разделить все вещи на функции (методы, если хотите).Функция X выполняет вещи X, Y делает туф Y, а не , как метод X делает вещи X, Y & Z!Это дает мне более многократно используемый код.Мне это нравится.:)

Давайте посмотрим на этот код:

var user = {
  users: [],
  userCount: 0,
  addUser: function(user) {
    (this.users).push(user);
  },
  incrementCount: function() {
    ++this.userCount;
  }
}

var user = { // 2nd example.
  users: [],
  userCount: 0,
  addUser: function(user) {
    (this.users).push(user);
    ++this.userCount;
  }
}

(Это на JavaScript, но язык здесь не является обязательным.)

На мой взгляд, второйПример будет проще и безопаснее для использования, скажем, для пользователя API.Легко забыть позвонить user.incrementCount().Как вы думаете?Второй пример делает это автоматически.

Так как найти баланс?Какие-либо передовые практики по вызову функций внутри функций?

Спасибо за прочтение этого.

Редактировать :

Это пришло мне на ум только сейчас:

var user = {
  users: [],
  userCount: 0,
  addUser: function(user) {
    (this.users).push(user);
    this.incrementCount();
  },
  incrementCount: function() {
    ++this.userCount;
  }
}

Ответы [ 4 ]

5 голосов
/ 05 декабря 2011

В JS все немного по-другому, поскольку при использовании буквальной нотации объекта нет способа сделать функции действительно закрытыми, , но ...

Все дело в API, который вы хотите, чтобы ваши объекты представляли своим потребителям. Хотите ли вы, чтобы потребители вашего API могли увеличивать количество отдельно от добавления пользователя? Если так:

{ addUser: /* snip */, incrementCount: /* snip */ }

В противном случае:

{ addUser: /* snip */, _incrementCount: /* snip */ }
// or just
{ addUser: /* snip */ }

В этом конкретном случае я настоятельно рекомендую вообще не хранить какой-либо отдельный счетчик, поскольку массив users уже делает это для вас.

var user = {
  _users: [],
  addUser: function(user) {
      this._users.push(user);
  },
  getUserCount: function () {
      return this._users.length;
  }
  // and if you need to expose the users array directly,
  , getUsers: function () {
      return this._users;
  }
}
3 голосов
/ 05 декабря 2011

Лично я не думаю, что вы должны даже выставлять эти вещи через API.Кроме того, было бы проще и (по крайней мере, в JavaScript) более интуитивно, просто использовать users.length.

В конечном счете, я думаю, что поддерживать ваш интерфейс действительно простым - это, как правило, хорошая вещь.Абстракция это хорошая вещь.Если бы я использовал чужую библиотеку, я был бы очень разочарован, узнав, что я должен был вручную увеличить это значение.

Обновление:

Еще одна вещь, которую яДумаю, стоит упомянуть:

Благодаря тому, что ваш код поддерживает внутреннее состояние и поддерживает API простым, вы не только облегчаете жизнь пользователя, но и защищаете от неправильного использования (насколько это возможно).Легко представить сценарий, в котором кто-то неправильно использует этот метод приращения, и в результате он сломается.

1 голос
/ 05 декабря 2011

Я знаю, что вы просто хотели, чтобы пример кода был простым примером, но с чем-то вроде переменной count или length я не могу придумать причину, по которой я бы хотел, чтобы это значение было установлено независимо отфункции, которые добавляют или удаляют элементы.При использовании объекта вам не нужно вызывать add() и increment() метод каждый раз, когда вы добавляете, и вы действительно не хотите иметь возможностьсделать одно без другого, или ваш объект окажется в недопустимом состоянии.

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

Лучше сделать переменную count частной и разрешить ее получение только через функциюи устанавливается через функции добавления / удаления (хотя вам даже не нужна переменная count, когда вы можете просто вернуть users.length).Следующий шаблон с немедленно выполняемой анонимной функцией позволяет вам иметь закрытые переменные и функции, и вы только возвращаете объект, содержащий публичные функции.Публичные функции могут по-прежнему иметь доступ к закрытым переменным / функциям, но к закрытым вещам нельзя получить доступ извне.

var user = (function() {
   var users = [],    // private variables
       private1,
       private2;

   function privateFunction1() { /* do something */ }

   return {
      getUserCount : function() {
                       return users.length;
                     },
      addUser:       function(user) {
                       users.push(user);
                       // return index of new user
                       return users.length - 1;
                     },
      getUser :      function(userIndex) {
                       return users[userIndex];
                     },
      someFunc :     function(someParam) {
                       return someParam + privateFunction1();
                     }
   }
})();

user.addUser("Fred");
user.addUser("Mary");
console.log(user.getUserCount()); // 2
console.log(user.getUser(1));     // Mary
1 голос
/ 05 декабря 2011

Вы правы, говоря: «Функция A делает A-Stuff».НО: функция, которая работает с данными, которые скрыты (более или менее) извне, должна делать то, что вам нужно, с данными (например, добавить пользователя) и уверять, что данные все еще верны (например, еслиу вас есть список пользователей, увеличьте Usercounter, чтобы убедиться, что он всегда корректен).Если вы не хотите, чтобы пользователь вашего API делал это для вас, это не очень удобно.

Представьте себе, вы добавляете больше функциональности в свой список пользователей (например, сообщаете пользователю, что он был добавлен в список, сохраняете пользователей в двоичном дереве и т. Д.), И вам нужно сделатьвсе организационные вещи за пределами вашей функции, где преимущества этого ??

...