если прототипы не могут получить доступ к закрытым переменным, каков наилучший способ «очистить» код?

#javascript #prototype #scoping

#javascript #прототип #определение области

Вопрос:

Эй, ребята, что у меня сейчас есть, это:

 var Human=function(){
  this._a=Math.random();
};
(function() {
  var before_get = function(human) {
  };
  var before_set = function(human, v) {
  };
  Human.prototype={
    get A(){
      before_get(this);
      return this._a;
    },
    set A(v){
      before_set(this, v);
      this._a=v;
    }
  };
})();
alert(new Human().A); // test
alert(new Human().A); // test
  

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

Ответ №1:

В JavaScript нет такого понятия, как private, поэтому это недостижимо. В общем, у нас нет общих свойств или установщиков / геттеров, как у других C # / Java.

Шаблон, который можно использовать, — это замыкания вместо прототипов.

 var Human = function() {
    var a = Math.random();
    var o = {};
    Object.defineProperties(o, {
        "A": {
             "get": function() {
                 return a;
             }, 
             "set": function(val) {
                 a = val;
             }
        }
    });
    return o;
}
  

В общем, хотя вы не должны записывать свойства в прототип. Прототип должен содержать методы.

Единственный способ очистки this._a заключается в следующем

 var Human = (function() {
  var Human=function(){
    this._a=Math.random();
  };
  var before_get = function(human) {
  };
  var before_set = function(human, v) {
  };
  Human.prototype={
    getA(){
      before_get(this);
      return this._a;
    },
    setA(v){
      before_set(this, v);
      this._a=v;
    }
  };
  return function(args) {
     var h = new Human(args);
     return {
       getA: h.getA.bind(h),
       setA: h.setA.bind(h)
     }
  }
})();
  

Комментарии:

1. но проблема с этим методом в том, что если у меня 9999 пользователей, я в конечном итоге создаю 9999 методов получения и 9999 установщиков..

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

3. @Raynos в моем примере (выше) у каждого пользователя есть своя переменная, и все пользователи совместно используют функцию со ссылкой на эту переменную (прелесть переменной «this»). Однако проблема, с которой я столкнулся, заключается в том, что я не смог найти способ предоставлять переменные только прототипу и ничему другому .. и, таким образом, у меня получаются эти уродливые «частные» переменные, которые не являются такими уж частными.. итак, я искал решение для этого..

4. @Pacerier то, о чем вы просите, невозможно . Лучшее, что вы можете сделать, это вернуть прокси, который не экспортирует публично this._a

5. @Raynos heys что вы подразумеваете под прокси, может быть, это то, что я хочу!

Ответ №2:

Вот как вы создаете подобные частные / статические переменные, используя прототипное «наследование». Хитрость заключается в том, чтобы определить методы прототипа в конструкторе (один раз). Цена — это методы получения / установки, которые вы должны выполнить. Преимущество заключается в простоте и истинном прототипном решении (которое, в конце концов, является реальной природой зверя). И, кстати, здесь вы создаете свой ‘getter / setter’ только один раз, и он присутствует для всех 999 экземпляров, которые вы создаете на его основе.

 function Human() {
    var  a = 'We are all Human',
         o = {}
         proto = Human.prototype;
    if (!proto.A) {
       //uncomment and create a few instances to see
       //this is only executed once
       //console.log('adding prototypes');
       proto.A = function() {return a;};
       proto.set = function(val) {a = val || a;};
       proto.setName = function(val) {this.name = val || ''};
       proto.getName = function(){
           if (!this.name) {this.setName('no name yet');}
           return this.name;};
    }
}

var Pete = new Human,
    Jean = new Human;

console.log(Pete.A() ':' Jean.A()); 
      //|=> We are all Human:We are all Human
Pete.set(Pete.A() ' except Jean'));
console.log(Pete.A() ':' Jean.A()); 
      //|=> We are all Human except Jean:We are all Human except Jean
Pete.setName('Hi, I am Pete. ' Pete.A());
Jean.setName('Hi, I am Jean. '  Jean.A()  '. Damn! thats me!');
console.log(Pete.name); 
      //|=> Hi, I am Pete. We are all Human except Jean
console.log(Jean.name); 
      //|=> Hi, I am Jean. We are all Human except Jean. Damn! thats me!
  

Вы должны понимать, что любой может решить назначить что-то другое Human.prototype.A . Но если они делают это вне конструктора, закрытие, и, следовательно a , больше не доступно.

Комментарии:

1. То, что у вас есть, является статическим и закрытым. определение его в конструкторе также сопряжено с трудностями. Просто используйте замыкание, чтобы скрыть a . Но у вас нет private для объекта, который у вас локальный для прототипа.

2. 1. Я думаю, что здесь используется замыкание. 2. Это не более болезненно, чем все шаблоны, которые я видел проходящими. 3. это шаблон прототипа создать один раз, использовать много раз , который должен быть довольно эффективным, если кто-то хочет создать, скажем, 9999 экземпляров. И 4 (бонус!), это работает во всех браузерах.

3. @Raynos: Что у вас там есть — статическое и закрытое . Теперь, как насчет того, что в JavaScript нет такого понятия, как private, так что это недостижимо ? Это, по крайней мере, напоминает противоречивость. Не могли бы вы объяснить?

4. привет, это круто, однако переменная _a не должна быть статической. есть ли способ обойти это? (единственное, что я хочу «статического», это средства получения / установки, а не само значение)

5. @Kooilnc ему нужны свойства экземпляра, которые не являются общедоступными. локальные переменные для каждого экземпляра, которые все еще доступны прототипу