Подтвердить что ты не робот

Как объявить частные переменные и частные методы в классе es6

в es5 мы используем функцию конструктора

function Person(name,gender){

    var initial ="";    // we use var key word to make variable private

    function getNameWithInitial(){ // this is the private method to get name with initial
        console.log(this);
        initial = this.gender ==="male"?"Mr. ":"Mrs. ";
        return initial + this.name;
    }


    this.name = name;
    this.gender = gender;
    this.getName = function(){
        return getNameWithInitial.call(this);
    }


}


var manas = new Person("Manas","male");

console.log(manas.getName());

Мой вопрос заключается в том, как объявить приватную переменную и частный метод в классе es6

4b9b3361

Ответ 1

Одним из способов достижения этой цели является использование еще одной функции ES2015, известной как модули.

Возможно, вы уже знакомы с модулями AMD или commonJS (используется Nodejs). Ну ES6/ES2015 приносит стандарт для JS - мы будем называть их модулями ES6, но теперь они являются частью языка JS. Когда у вас есть модули, у вас есть возможность скрывать информацию как для частных, так и для переменных объекта. Имейте в виду, что только то, что вы "экспортируете", видимо для кода вызова клиента.

Позволяет работать с вашим примером кода. Вот первый разрез:

person.js

 const getNameWithInitial = function () {
      let initial = this._gender === 'male' ?
      'Mr. ' :
      'Mrs. ';
      return initial + this._name;
    }

  export class Person {

    constructor(name, gender) {
        this._name = name;
        this._gender = gender;
      }

      get name() {
          return getNameWithInitial.call(this);
        }
    }
  }

client.js

import {Person} from './person';
const manas = new Person('Manas', 'male');
console.log(manas.name);  // this calls what was your getName function

Теперь функция getNameWithInitial фактически закрыта, так как она не экспортируется, поэтому client.js не может ее видеть.

Однако у нас все еще есть проблема для класса Person, поскольку он экспортируется. На данный момент вы можете просто подойти к объекту manas и сделать:

manas._name = 'Joe'

С такими свойствами, как _name, мы можем комбинировать модули и символы. Это мощный, но легкий способ скрытия информации, доступный с ES6 +/ES2015.

Символ - это новый встроенный тип. Каждое новое значение Symbol уникально. Следовательно, он может использоваться как ключ для объекта.

Если код вызова клиента не знает символ, используемый для доступа к этому ключу, они не могут его удержать, поскольку символ не экспортируется.

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

person.js

const s_name = Symbol();
const s_gender = Symbol();

const getNameWithInitial = function () {
  let initial = this[s_gender] === 'male' ?
    'Mr. ' :
    'Mrs. ';
  return initial + this[s_name];
}

export class Person {

  constructor(name, gender) {
    this[s_name] = name;
    this[s_gender] = gender;
  }

  get name() {
    return getNameWithInitial.call(this);
  }
}

Итак, теперь клиент не может просто делать:

 manas._name = 'Joe' 

поскольку _name не используется в качестве ключа для значения имени.

Однако символы отображаются через функции отражения, такие как Object.getOwnPropertySymbols, поэтому имейте в виду, что они не являются "полностью" частными, используя эту технику.

import {Person} from './person';
const manas = new Person('Manas', 'male');
const vals = Object.getOwnPropertySymbols(manas);
manas[vals[0]] = 'Joanne';
manas[vals[1]] = 'female';

Отправка сообщения - Модули в целом - отличный способ скрыть что-то, потому что если они не экспортируются, то недоступны для использования вне модуля и используются с секретными хранимыми символами, чтобы действовать как клавиши, то атрибуты класса тоже могут стать скрытыми (но не строго частный). Использование модулей сегодня доступно с помощью инструментов сборки, например. webpack/browsify и babel.

Ответ 2

Если вам нужен аналог решения ES5, это довольно просто; constructor просто становится тем, что содержит замыкание, и вы добавляете какие-либо методы/объекты, которые должны помнить частное состояние там. Прототипированные методы не имеют доступа к закрытию исходного конструктора без использования некоторых привилегированных геттеров:

class Person {

  constructor ({ name, age, deepDarkSecret }) {
    const bribe = () => console.log(`Give me money, or everybody will know about ${ redactRandom(deepDarkSecret) }`);

    Object.assign(this, { name, age }); // assigning publicly accessible values
    Object.assign(this, { bribe }); // assign "privileged" methods (functions with closure-reference to initial values)
  }

  recallSecret () {
    console.log("I'm just a prototyped method, so I know nothing about any secret, unless I use a privileged function...");
    this.bribe();
  }
}

Если вы посмотрите, что это у вас, вы заметите, что это действительно не сильно отличается от вашего примера (просто используя "чистые" колокола и свистки, особенно при добавлении прототипов/статических методов). Он все еще прототип внизу.

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

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

Используйте this как свой ключ. Вместо того, чтобы делать привилегированные функции, которые имеют закрытие доступа, теперь все методы прототипа имеют закрывающий доступ к слабой карте...
... недостатком является то, что в любое время, когда вам нужны частные переменные, вы должны искать их в WeakMap, а не вынимать их из /t this.

const personalBaggage = new WeakMap();

class Person {
  constructor ({ name, age, darkestMoment }) {
    const privates = { name, age, darkestMoment };
    personalBaggage.add(this, privates);
  }

  recallDarkestHour () {
    const { darkestMoment } = personalBaggage.get(this);
    console.log(darkestMoment);
  }
}

export default Person;

Пока вы не теряете ссылку внутри this, это должно просто работать.
В отличие от использования Symbol, вы не можете получить ссылку на частный объект, как бы вы ни старались.
Если вы знаете символы на объекте, вы можете искать свойства с помощью символов.
И получение списка символов на любом объекте - это просто вызов функции. Symbol заключается не в том, чтобы держать вещи частными; это о том, чтобы держать вещи в безопасности от именования столкновений и определять общие символы, которые могут быть использованы на любом объекте/функции, но не будут зацикливаться на циклах, не будут вызваны или перезаписаны случайно и т.д.

Сохранение частного мешка данных в слабом карте с помощью this в качестве ключа дает вам доступ к полностью скрытому набору данных, который полностью недоступен вне этого модуля.
Что лучше, ключ/значение в слабых картах не мешают GC очищать их.
Обычно, если они остались в массиве, они останутся там. Если последнее место, где используется объект, является ключом в слабой карте, тогда оно собирается, а значение слабой карты стирается автоматически (в исходном ES6, бонусы памяти не могут быть заполнены, но объект может).

Ответ 3

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

вот код прямо со своего сидения.

var Person = (function() {
    var nameSymbol = Symbol('name');

    function Person(name) {
        this[nameSymbol] = name;
    }

    Person.prototype.getName = function() {
        return this[nameSymbol];
    };

    return Person;
}());

var p = new Person('John');

Частные свойства в JavaScript

Ответ 4

Вы можете выполнить его, используя Symbol.

const _name = Symbol();

class Person {
  constructor(name) {
    this[_name] = name;
  } 
}

const person = new Person('John');

alert(person.name);
// => undefined