Приватні властивості в класах JavaScript ES6


444

Чи можливо створити приватні властивості в класах ES6?

Ось приклад. Як я можу запобігти доступ до нього instance.property?

class Something {
  constructor(){
    this.property = "test";
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"

5
Насправді є пропозиція щодо третьої стадії для цієї функції - tc39.github.io/proposed-class-fields github.com/tc39/proposed-class-fields
arty

@arty Я відповів на це на прикладах: stackoverflow.com/a/52237988/1432509
Alister

Відповіді:


165

Приватні поля (та методи) реалізуються в стандарті ECMA . Ви можете почати користуватися ними сьогодні з попередньо встановленими позначками 7 та 3.

class Something {
  #property;

  constructor(){
    this.#property = "test";
  }

  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
      return this.#privateMethod();
  }
}

const instance = new Something();
console.log(instance.property); //=> undefined
console.log(instance.privateMethod); //=> undefined
console.log(instance.getPrivateMessage()); //=> hello world

Мені цікаво, як можуть працювати ці класи класів. Наразі ви не можете використовувати thisв конструкторі, перш ніж дзвонити super(). І все ж дівочий ставить їх перед супер.
seeker_of_bacon

Як налаштувати ESLint для дозволу #privateCrapсинтаксису?
Марекі

6
А як щодо еслінт? Я отримав помилку синтаксичного аналізу при знаку рівності. Babel працює, просто eslint не може проаналізувати цей новий синтаксис js.
martonx

6
Ух, це дуже некрасиво. Хештег - дійсний символ. Майно насправді не приватне, чи? .. Я перевірив це в TypeScript. Приватні члени не збираються в приватних або лише для читання (ззовні). Просто оголошено як інше (публічне) майно. (ES5).
Домінік

2
Як ви пишете приватні методи з цим? Чи можу я це зробити #beep() {}:; а це async #bzzzt() {}:?
Константин Ван

277

Коротка відповідь, ні, немає вбудованої підтримки приватних ресурсів із класами ES6.

Але ви можете імітувати таку поведінку, не приєднуючи нові властивості до об'єкта, а зберігаючи їх всередині конструктора класів та використовуючи getters та setters для досягнення прихованих властивостей. Зауважте, що getters та setters переосмислюються в кожному новому екземплярі класу.

ES6

class Person {
    constructor(name) {
        var _name = name
        this.setName = function(name) { _name = name; }
        this.getName = function() { return _name; }
    }
}

ES5

function Person(name) {
    var _name = name
    this.setName = function(name) { _name = name; }
    this.getName = function() { return _name; }
}

1
Мені подобається це рішення найкраще. Я погоджуюсь, що його не слід використовувати для масштабування, але він ідеально підходить для занять, які зазвичай інстанціюються лише один раз на включення.
Блейк Регалія

2
Також ви переосмислюєте кожен компонент цього класу щоразу, коли створюється новий.
Квентін Рой

10
Це так дивно! У ES6 ви створюєте більше "пірамід закриття", ніж до ES6! Визначення функцій в конструкторі виглядає неприємніше, ніж це було зроблено у наведеному вище прикладі ES5.
Кокодоко

1
Оскільки ОП спеціально запитує про класи ES6, я особисто вважаю це поганим рішенням, навіть якщо це технічно працює. Основне обмеження полягає в тому, що тепер кожен метод класу, який використовує приватні змінні, повинен бути оголошений всередині конструктора, що сильно підриває переваги наявності classсинтаксису в першу чергу.
NanoWizard

10
Все це робить введення непрямості. Тепер , як ви зробите getNameі setNameвластивості приватного?
аїй

195

Щоб розгорнути відповідь на @ loganfsmyth:

Єдиними справді приватними даними у JavaScript все ще є змінні області. Ви не можете мати приватні властивості у розумінні властивостей, доступ до яких здійснюється внутрішньо так само, як до загальнодоступних ресурсів, але ви можете використовувати масштабовані змінні для зберігання приватних даних.

Обсяг змінних

Підхід тут полягає у використанні сфери функції конструктора, яка є приватною, для зберігання приватних даних. Щоб методи мали доступ до цих приватних даних, вони повинні бути створені і в конструкторі, тобто ви відтворюєте їх у кожному екземплярі. Це покарання за продуктивність та пам'ять, але деякі вважають, що покарання є прийнятним. Покарання можна уникнути за методи, які не потребують доступу до приватних даних, додавши їх до прототипу, як зазвичай.

Приклад:

function Person(name) {
  let age = 20; // this is private
  this.name = name; // this is public

  this.greet = function () {
    // here we can access both name and age
    console.log(`name: ${this.name}, age: ${age}`);
  };
}

let joe = new Person('Joe');
joe.greet();

// here we can access name but not age

Обсяг слабкої карти

Слабку карту можна використовувати, щоб уникнути продуктивності попереднього підходу та покарання пам’яті. WeakMaps пов'язує дані з Об'єктами (тут, екземпляри) таким чином, що до них можна отримати доступ лише за допомогою цього WeakMap. Отже, ми використовуємо метод масштабних змінних для створення приватного WeakMap, а потім використовуємо WeakMap для отримання приватних даних, пов’язаних із this. Це швидше, ніж метод масштабних змінних, оскільки всі ваші екземпляри можуть спільно використовувати один WeakMap, тому вам не потрібно відтворювати методи лише для того, щоб вони отримували доступ до своїх власних слабких карт.

Приклад:

let Person = (function () {
  let privateProps = new WeakMap();

  class Person {
    constructor(name) {
      this.name = name; // this is public
      privateProps.set(this, {age: 20}); // this is private
    }

    greet() {
      // Here we can access both name and age
      console.log(`name: ${this.name}, age: ${privateProps.get(this).age}`);
    }
  }

  return Person;
})();

let joe = new Person('Joe');
joe.greet();

// here we can access joe's name but not age

У цьому прикладі використовується Object для використання одного WeakMap для декількох приватних властивостей; ви також можете використовувати кілька слабких карт і використовувати їх на зразок age.set(this, 20), або написати невелику обгортку і використовувати її іншим способом, наприклад privateProps.set(this, 'age', 0).

Конфіденційність такого підходу теоретично може бути порушена підробкою глобальних WeakMap об'єкта. При цьому, всі JavaScript можуть бути зламані гнучкими глобалами. Наш код вже побудований на припущенні, що цього не відбувається.

(Цей метод також можна виконати Map, але WeakMapкраще, оскільки Mapвін створить витоки пам'яті, якщо ви не дуже обережні, і для цього обидва не відрізняються.)

Напіввідповідь: Діапазон символів

Символ - це тип примітивного значення, яке може слугувати іменем властивості. Ви можете скористатися методом масштабної змінної для створення приватного символу, а потім зберегти приватні дані наthis[mySymbol] .

Конфіденційність цього методу може бути порушена за допомогою Object.getOwnPropertySymbols , але це зробити дещо незручно.

Приклад:

let Person = (function () {
  let ageKey = Symbol();

  class Person {
    constructor(name) {
      this.name = name; // this is public
      this[ageKey] = 20; // this is intended to be private
    }

    greet() {
      // Here we can access both name and age
      console.log(`name: ${this.name}, age: ${this[ageKey]}`);
    }
  }

  return Person;
})();

let joe = new Person('Joe');
joe.greet();

// Here we can access joe's name and, with a little effort, age. ageKey is
// not in scope, but we can obtain it by listing all Symbol properties on
// joe with `Object.getOwnPropertySymbols(joe)`.

Напіввідповідь: Підкреслення

Старий за замовчуванням, просто використовуйте загальнодоступну власність з префіксом підкреслення. Ця конвенція, хоч і не є приватною власністю, є достатньо розповсюдженою, тому вона робить хорошу роботу, повідомляючи, що читачі повинні ставитися до власності як до приватної, яка часто робить цю роботу. В обмін на цей проміжок часу ми отримуємо простіший для читання, простіший набір та швидший підхід.

Приклад:

class Person {
  constructor(name) {
    this.name = name; // this is public
    this._age = 20; // this is intended to be private
  }

  greet() {
    // Here we can access both name and age
    console.log(`name: ${this.name}, age: ${this._age}`);
  }
}

let joe = new Person('Joe');
joe.greet();

// Here we can access both joe's name and age. But we know we aren't
// supposed to access his age, which just might stop us.

Висновок

Станом на ES2017, досі немає ідеального способу створення приватних об'єктів. У різних підходів є плюси і мінуси. Обчислені змінні дійсно є приватними; масштабні слабкі карти дуже приватні і практичніші, ніж масштабовані змінні; Символи в масштабі є досить приватними та досить практичними; Підкреслення часто є досить приватними та дуже практичними.


7
Перший фрагмент прикладу ("масштабовані змінні") є загальним антипаттерном - кожен повернутий об'єкт матиме інший клас. Не робіть цього. Якщо ви хочете привілейованих методів, створіть їх у конструкторі.
Бергі

1
Згортання класу всередині функції, здається, перешкоджає насамперед цілі використання класів. Якщо ви вже використовуєте функцію для створення екземпляра, ви можете також розмістити всі приватні / публічні члени всередині цієї функції, і забути про ключове слово всього класу.
Кокодоко

2
@Bergi @Kokodoko Я відредагував підхід щодо масштабних змінних, щоб бути трохи швидшим і не зламатись instanceof. Зізнаюся, я думав про такий підхід, як про включення лише заради повноти, і мав би більше подумати над тим, наскільки він насправді здатний.
тристан

1
Відмінне пояснення! Я все ще дивуюсь, що ES6 насправді ускладнив імітацію приватної змінної, де в ES5 ви могли просто використовувати var і це всередині функції, щоб імітувати приватне та публічне.
Кокодоко

2
@Kokodoko Якщо ви не обійдетеся з класом і просто введете все у функцію, вам також доведеться повернутися до реалізації успадкування за допомогою методу прототипу. Використовувати розширення для занять - це набагато чистіший підхід, тому використання класу всередині функції цілком прийнятно.
AndroidDev

117

Оновлення: пропозиція з приємнішим синтаксисом вже на шляху. Внески вітаються.


Так, Є - для масштабного доступу в об'єкти - ES6 вводить Symbols .

Символи унікальні, ви не можете отримати доступ до нього ззовні, окрім відображення (наприклад, приватних осіб у Java / C #), але кожен, хто має доступ до символу з внутрішньої сторони, може використовувати його для доступу до клавіш:

var property = Symbol();
class Something {
    constructor(){
        this[property] = "test";
    }
}

var instance = new Something();

console.log(instance.property); //=> undefined, can only access with access to the Symbol

6
Ви не можете використовувати Object.getOwnPropertySymbols? ;)
Qantas 94 Важкий

41
@BenjaminGruenbaum: Очевидно, символи більше не забезпечують справжню конфіденційність: stackoverflow.com/a/22280202/1282216
d13

28
@trusktr через три ключі? Ні. Через символи? Так. Дуже подобається, як ви можете використовувати відображення мовами на зразок C # та Java для доступу до приватних полів. Модифікатори доступу - це не безпека, а ясність намірів.
Бенджамін Грюнбаум

9
Схоже, що використання Symbols схоже на те, що робити const myPrivateMethod = Math.random(); Something.prototype[''+myPrivateMethod] = function () { ... } new Something()[''+myPrivateMethod]();. Це насправді не конфіденційність, це незрозумілість у розумінні традиційного JavaScript. Я вважаю, що "приватний" JavaScript означає використання закриття для інкапсуляції змінних. Отже, ці змінні недоступні через відображення.
trusktr

13
Крім того, я вважаю, що використання privateта protectedключових слів було б набагато чистішим Symbolчи ніж Name. Я віддаю перевагу крапковій нотації, а не дужковій нотації. Я хотів би продовжувати використовувати крапку для приватних речей. this.privateVar
trusktr

33

Відповідь - «Ні». Але ви можете створити приватний доступ до таких властивостей:

  • Використовуйте модулі. Все в модулі є приватним, якщо воно не оприлюднене за допомогою exportключового слова.
  • Всередині модулів використовуйте функцію закриття: http://www.kirupa.com/html5/closures_in_javascript.htm

(Припущення про те, що символи можуть бути використані для забезпечення конфіденційності, було правдивим у попередній версії специфікації ES6, але це вже не так: https://mail.mozilla.org/pipermail/es-discuss/2014-January/035604. html та https://stackoverflow.com/a/22280202/1282216 . Більш тривалу дискусію про символи та конфіденційність див: https://curiosity-driven.org/private-properties-in-javascript )


6
-1, це насправді не відповідає на ваше запитання. (Ви також можете використовувати закриття з IIFE у ES5). Приватні властивості перелічуються завдяки відображенню на більшості мов (Java, C # тощо). Сенс приватних властивостей полягає в тому, щоб передати наміри іншим програмістам і не застосовувати захист.
Бенджамін Груенбаум

1
@BenjaminGruenbaum, я знаю, я хотів би, щоб я мав кращу відповідь, і я цим не задоволений.
d13

Я думаю, що символи все ще є вагомим способом досягнення недоступних членів, перебуваючи в середовищі програмування. Так, їх все одно можна знайти, якщо ти дійсно хочеш, але це не в цьому справа? Ви не повинні зберігати в ньому конфіденційну інформацію, але все одно не слід робити це в коді клієнта. Але він працює з метою приховування властивості чи методу від зовнішнього класу.
Кокодоко

Використання змінних, розміщених на рівні модуля в якості заміни приватних властивостей у класі, призведе до того, що однотипне.поведінка або поведінка подібне до властивостей statitc.
Адріана Мойса

30

Єдиний спосіб отримати справжню конфіденційність в JS - це скопіювання, тому немає можливості мати властивість, членом thisякої буде доступна лише всередині компонента. Найкращий спосіб зберігати справді приватні дані в ES6 - це WeakMap.

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    privateProp1.set(this, "I am Private1");
    privateProp2.set(this, "I am Private2");

    this.publicVar = "I am public";
    this.publicMethod = () => {
      console.log(privateProp1.get(this), privateProp2.get(this))
    };        
  }

  printPrivate() {
    console.log(privateProp1.get(this));
  }
}

Очевидно, що це, мабуть, повільно, і, безумовно, негарно, але це забезпечує конфіденційність.

Майте на увазі, що ВСІМ ЦЕ НЕ ідеально, оскільки Javascript настільки динамічний. Хтось ще міг це зробити

var oldSet = WeakMap.prototype.set;
WeakMap.prototype.set = function(key, value){
    // Store 'this', 'key', and 'value'
    return oldSet.call(this, key, value);
};

ловити значення у міру їх збереження, тому, якщо ви хочете бути особливо обережними, вам потрібно буде зафіксувати локальну посилання .setта .getвикористовувати явно замість того, щоб покладатися на прототип прототипу.

const {set: WMSet, get: WMGet} = WeakMap.prototype;

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    WMSet.call(privateProp1, this, "I am Private1");
    WMSet.call(privateProp2, this, "I am Private2");

    this.publicVar = "I am public";
    this.publicMethod = () => {
      console.log(WMGet.call(privateProp1, this), WMGet.call(privateProp2, this))
    };        
  }

  printPrivate() {
    console.log(WMGet.call(privateProp1, this));
  }
}

3
Як пропозиція, ви можете уникнути використання однієї слабкої карти на властивість, використовуючи об'єкт як значення. Таким чином ви також можете зменшити кількість карт getдо одного за методом (наприклад const _ = privates.get(this); console.log(_.privateProp1);).
Квентін Рой

Так, це теж варіант. Я здебільшого пішов з цим, оскільки він відображає більш безпосередньо те, що написав би користувач при використанні реальних властивостей.
loganfsmyth

@loganfsmyth const myObj = new SomeClass(); console.log(privateProp1.get(myObj)) // "I am Private1"це означає, що ваша власність є приватною чи ні?
Barbu Barbu

2
Щоб це працювало, код, що звертається до власності, потребує доступу до об'єкта WeakMap, який, як правило, потрапляє всередину модуля і недоступний
loganfsmyth

22

Для подальшого посилання інших на глядачів я зараз чую, що рекомендується використовувати WeakMaps для зберігання приватних даних.

Ось більш чіткий, робочий приклад:

function storePrivateProperties(a, b, c, d) {
  let privateData = new WeakMap;
  // unique object as key, weak map can only accept object as key, when key is no longer referened, garbage collector claims the key-value 
  let keyA = {}, keyB = {}, keyC = {}, keyD = {};

  privateData.set(keyA, a);
  privateData.set(keyB, b);
  privateData.set(keyC, c);
  privateData.set(keyD, d);

  return {
    logPrivateKey(key) {
      switch(key) {
      case "a":
        console.log(privateData.get(keyA));
        break;
      case "b":
        console.log(privateData.get(keyB));
        break;
      case "c":
        console.log(privateData.get(keyC));
        break;
      case "d":
        console.log(privateData.set(keyD));
        break;
      default:
        console.log(`There is no value for ${key}`)
      }
    }
  }
}

20
Майте на увазі, що ці властивості є статичними.
Майкл Теріот

8
Я вас не оскаржував, але ваш приклад слабкої картини зовсім неправильний.
Бенджамін Грюенбаум

4
А саме - Ви обмінюєтесь даними між усіма екземплярами класу, а не з примірниками - я можу принаймні виправити це?
Бенджамін Грюнбаум

1
Дійсно, слабку карту потрібно прикласти до певного екземпляра. Для прикладу див. Fitzgeraldnick.com/weblog/53 .
розширився

2
Згідно з MDN, примітивні типи даних, такі як Symbols, не дозволені як ключ слабкого типу. Документація про слабку карту MDN
leepowell

12

Залежить від кого ви запитуєте :-)

Немає privateМодифікатор властивості не входять в мінімальних класах МАКСИМАЛЬНО пропозицію , яке , здається, зробив це в поточний проект .

Однак, можливо, буде підтримка приватних імен , що дозволяє приватні властивості - і вони, ймовірно, можуть бути використані і у визначеннях класів.


3
Це дуже малоймовірно , що приватні імена будуть робити це в ES6, хоча вони думають про тій чи іншій формі приватної речі для ES7.
Qantas 94 Важкий

@ Qantas94Heavy як приватні імена, так і унікальні значення рядків були замінені Symbols з того, що я розумію.
Бенджамін Груенбаум

Так, це, мабуть, стане Символами. Однак, afaik "символи", які зараз містяться у специфікації, використовуються лише для опису внутрішніх властивостей, таких як [[прототип]], і немає способу їх створення та використання в коді користувача. Чи знаєте ви деяких документів?
Бергі

Я щойно зрозумів, що модулі можна використовувати для встановлення конфіденційності. У поєднанні із символами, які могли б бути все, що вам коли-небудь знадобиться ...?
d13

1
@Cody: Ваш весь модульний код все одно має власну сферу застосування в ES6, IEFE не потребує. І так, символи призначені для унікальності (уникнення зіткнення), а не конфіденційності.
Бергі

10

Використання модулів ES6 (спочатку запропоновано @ d13) для мене добре працює. Це не імітує приватні властивості ідеально, але принаймні ви можете бути впевнені, що властивості, які мають бути приватними, не просочуються поза вашим класом. Ось приклад:

something.js

let _message = null;
const _greet = name => {
  console.log('Hello ' + name);
};

export default class Something {
  constructor(message) {
    _message = message;
  }

  say() {
    console.log(_message);
    _greet('Bob');
  }
};

Тоді споживний код може виглядати так:

import Something from './something.js';

const something = new Something('Sunny day!');
something.say();
something._message; // undefined
something._greet(); // exception

Оновлення (важливо):

Як @DanyalAytekin виклав у коментарях, ці приватні властивості є статичними, тому, за своїм масштабом, глобальними. Вони добре працюватимуть під час роботи з Singletons, але слід бути обережним щодо перехідних об'єктів. Розширення прикладу вище:

import Something from './something.js';
import Something2 from './something.js';

const a = new Something('a');
a.say(); // a

const b = new Something('b');
b.say(); // b

const c = new Something2('c');
c.say(); // c

a.say(); // c
b.say(); // c
c.say(); // c

4
Добре для private static.
Данял Айтекін

@DanyalAytekin: це дуже хороший момент. Ці приватні властивості є статичними настільки глобальними за обсягом. Я оновив свою відповідь, щоб це відобразити.
Джонні Ошика

Чим більше я дізнаюся про функціональне програмування (особливо Elm та Haskell), тим більше я вважаю, що програмісти JS виграють від модульного підходу до "модульності", а не від класу на базі OOP. Якщо ми розглядаємо модулі ES6 як основу для побудови додатків і повністю забули про класи, я вважаю, що ми можемо в цілому отримати набагато кращі програми. Чи може хтось із досвідчених користувачів Elm чи Haskell прокоментувати цей підхід?
d13

1
У оновленні a.say(); // aмає бути другийb.say(); // b
бурхливий

випробуваний let _message = nullспосіб, не такий крутий, коли конструктор викликів кілька разів, він псує.
Littlee

9

Завершення @ d13 та коментарі @ johnny-oshika та @DanyalAytekin:

Я припускаю, що у прикладі, наданому @ johnny-oshika, ми могли використовувати звичайні функції замість стрілочних функцій, а потім .bindїх із поточним об'єктом плюс _privatesоб'єктом як параметр curry:

something.js

function _greet(_privates) {
  return 'Hello ' + _privates.message;
}

function _updateMessage(_privates, newMessage) {
  _privates.message = newMessage;
}

export default class Something {
  constructor(message) {
    const _privates = {
      message
    };

    this.say = _greet.bind(this, _privates);
    this.updateMessage = _updateMessage.bind(this, _privates);
  }
}

main.js

import Something from './something.js';

const something = new Something('Sunny day!');

const message1 = something.say();
something.updateMessage('Cloudy day!');
const message2 = something.say();

console.log(message1 === 'Hello Sunny day!');  // true
console.log(message2 === 'Hello Cloudy day!');  // true

// the followings are not public
console.log(something._greet === undefined);  // true
console.log(something._privates === undefined);  // true
console.log(something._updateMessage === undefined);  // true

// another instance which doesn't share the _privates
const something2 = new Something('another Sunny day!');

const message3 = something2.say();

console.log(message3 === 'Hello another Sunny day!'); // true

Переваги, про які я можу придумати:

  • ми можемо мати приватні методи ( _greetі _updateMessageдіяти як приватні методи, поки ми не маємо exportпосилання)
  • хоча вони не в прототипі, вищезазначені методи заощаджують пам'ять, оскільки екземпляри створюються один раз, поза класом (на відміну від визначення їх у конструкторі)
  • ми не просочуємо жодних глобалів, оскільки ми всередині модуля
  • ми також можемо мати приватні властивості, використовуючи прив'язаний _privatesоб'єкт

Деякі недоліки, про які я можу придумати:

Зрізний фрагмент можна знайти тут: http://www.webpackbin.com/NJgI5J8lZ


8

Так - ви можете створити капсульоване властивість , але це не було зроблено з модифікаторами доступу (загальнодоступними | приватними), принаймні, не з ES6.

Ось простий приклад того, як це можна зробити за допомогою ES6:

1 Створіть клас за допомогою класу слово

2 Всередині конструктора оголосить змінну, що охоплюється блоком, використовуючи let OR const охоплює блок, зарезервовані слова -> оскільки вони є блок-сферою, до них не можна отримати доступ ззовні (інкапсульовано)

3 Щоб дозволити деякий контроль доступу (setters | getters) до цих змінних, ви можете оголосити метод екземпляра всередині його конструктора, використовуючи: this.methodName=function(){}синтаксис

"use strict";
    class Something{
        constructor(){
            //private property
            let property="test";
            //private final (immutable) property
            const property2="test2";
            //public getter
            this.getProperty2=function(){
                return property2;
            }
            //public getter
            this.getProperty=function(){
                return property;
            }
            //public setter
            this.setProperty=function(prop){
                property=prop;
            }
        }
    }

Тепер давайте перевіримо:

var s=new Something();
    console.log(typeof s.property);//undefined 
    s.setProperty("another");//set to encapsulated `property`
    console.log(s.getProperty());//get encapsulated `property` value
    console.log(s.getProperty2());//get encapsulated immutable `property2` value

1
Це (поки що) єдине рішення цієї проблеми, незважаючи на те, що всі методи, задекларовані в конструкторі, передекларуються для кожного примірника класу. Це досить погана ідея щодо продуктивності та використання пам'яті. Методи класу повинні бути оголошені за межами області конструктора.
Freezystem

@Freezystem По-перше: спочатку це методи екземпляра (а не Class). Другим питанням ОП було: _ Як я можу запобігти доступу до instance.property?_, і моя відповідь: приклад того, як ... Третє, якщо у вас є краща ідея - давайте почуємо це
Микита Куртин,

1
Я не казав, що ви помиляєтесь, я сказав, що ваше рішення - найкращий компроміс для досягнення приватної змінної, незважаючи на те, що копія методів кожного примірника створюється кожен раз, коли ви викликаєте, new Something();оскільки ваші методи оголошуються в конструкторі, щоб мати доступ до них приватні змінні. Це може спричинити велике споживання пам'яті, якщо ви створюєте багато екземплярів свого класу, тому проблеми з продуктивністю. Методи повинні були бути оголошені поза рамками конструктора. Мій коментар був скоріше поясненням недоліків вашого рішення, ніж критикою.
Freezystem

1
Але хіба погана практика не визначає весь клас у конструкторі? Хіба ми не просто "зламаємо" javascript зараз? Просто подивіться на будь-яку іншу мову програмування OOP, і ви побачите, що конструктор не призначений для визначення класу.
Кокодоко

1
Так, це я мав на увазі, і ваше рішення працює! Я просто кажу, що в цілому я здивований, що ES6 додав ключове слово "class", але усунув елегантне рішення роботи з var і цим, щоб досягти інкапсуляції.
Кокодоко

8

Інший підхід до "приватного"

Замість того, щоб боротися з тим, що приватна видимість наразі недоступна в ES6, я вирішив скористатись більш практичним підходом, який буде добре, якщо ваш IDE підтримує JSDoc (наприклад, Webstorm). Ідея полягає у використанні @privateтегу . Що стосується розвитку, IDE не дозволить вам отримати доступ до будь-якого приватного члена поза його класом. Для мене працює досить добре, і це було дуже корисно для приховування внутрішніх методів, тому функція автоматичного завершення показує мені саме те, що клас дійсно мав намір викрити. Ось приклад:

автоматично завершує показ лише загальнодоступних речей


1
Проблема полягає в тому, що ми не хочемо отримати доступ до приватних змінних через Редактор, ми не хочемо захищати приватні змінні зовні - І це те, що робить public / private. Якщо ваш код готовий, ви можете отримати доступ до цих змінних із-за класу (і що важливо вважає: перевизначити ). Ваш @privateкоментар не може цього запобігти, це лише функція для генерації документації та ваш IDE.
Адріан Преусс

Так, я це знаю. Просто цього мені достатньо і може бути достатньо для інших людей там. Я знаю, що це не дуже робить мої змінні приватними; це лише попереджає мене не намагатися отримати доступ до нього ззовні (лише, звичайно, якщо ми з моєю командою використовуємо IDE, який підтримує цю функцію). Javascript (та інші мови, як-от Python) не розроблявся з урахуванням рівнів доступу. Люди роблять всілякі речі, щоб якось реалізувати цю функціональність, але врешті-решт ми зрештою просто зламаємо мову, щоб досягти цього. Я вирішив піти з більш "природним" підходом, якщо хочете.
Лусіо Пайва

6

Слабка карта

  • підтримується в IE11 (символи відсутні)
  • жорсткий-приватний (реквізити, що використовують символи, з-за м'якого приватного зв’язку через Object.getOwnPropertySymbols)
  • може виглядати по-справжньому чисто (на відміну від закриття, яке вимагає всіх реквізитів і методів у конструкторі)

Спочатку визначте функцію, щоб обернути WeakMap:

function Private() {
  const map = new WeakMap();
  return obj => {
    let props = map.get(obj);
    if (!props) {
      props = {};
      map.set(obj, props);
    }
    return props;
  };
}

Потім побудуйте посилання поза вашим класом:

const p = new Private();

class Person {
  constructor(name, age) {
    this.name = name;
    p(this).age = age; // it's easy to set a private variable
  }

  getAge() {
    return p(this).age; // and get a private variable
  }
}

Примітка: клас IE11 не підтримується, але він виглядає більш чистим у прикладі.


6

О, стільки екзотичних рішень! Мені зазвичай не байдуже приватне життя, тому я використовую "псевдо конфіденційність", як тут сказано . Але якщо піклуватися (якщо для цього є якісь особливі вимоги), я використовую щось подібне в цьому прикладі:

class jobImpl{
  // public
  constructor(name){
    this.name = name;
  }
  // public
  do(time){
    console.log(`${this.name} started at ${time}`);
    this.prepare();
    this.execute();
  }
  //public
  stop(time){
    this.finish();
    console.log(`${this.name} finished at ${time}`);
  }
  // private
  prepare(){ console.log('prepare..'); }
  // private
  execute(){ console.log('execute..'); }
  // private
  finish(){ console.log('finish..'); }
}

function Job(name){
  var impl = new jobImpl(name);
  return {
    do: time => impl.do(time),
    stop: time => impl.stop(time)
  };
}

// Test:
// create class "Job"
var j = new Job("Digging a ditch");
// call public members..
j.do("08:00am");
j.stop("06:00pm");

// try to call private members or fields..
console.log(j.name); // undefined
j.execute(); // error

Інша можлива реалізація функції (конструктор) Job:

function Job(name){
  var impl = new jobImpl(name);
  this.do = time => impl.do(time),
  this.stop = time => impl.stop(time)
}

5

Особисто мені подобається пропозиція оператора зв'язування, :: і тоді я б поєднав її із згаданим рішенням @ d13, але поки що дотримуйтесь відповіді @ d13, де ви використовуєте exportключове слово для свого класу та розміщуєте приватні функції в модулі.

Є ще одне жорстке рішення, про яке тут не згадувалося, що далі є більш функціональним підходом і дозволить йому мати всі приватні реквізити / методи у класі.

Private.js

export const get = state => key => state[key];
export const set = state => (key,value) => { state[key] = value; }

Test.js

import { get, set } from './utils/Private'
export default class Test {
  constructor(initialState = {}) {
    const _set = this.set = set(initialState);
    const _get = this.get = get(initialState);

    this.set('privateMethod', () => _get('propValue'));
  }

  showProp() {
    return this.get('privateMethod')();
  }
}

let one = new Test({ propValue: 5});
let two = new Test({ propValue: 8});
two.showProp(); // 8
one.showProp(); // 5

коментарі до цього були б вдячні.


Взагалі мені подобається підхід. Зворотній зв'язок: 1. Для кожного класу вам знадобиться інший модуль private.js для запобігання зіткнення. 2. Мені не подобається потенціал зробити конструктор по-справжньому довгим шляхом, визначаючи вбудований кожен ваш приватний метод. 3. Було б добре, якби всі методи класу були в одному файлі.
Doug Coburn

5

Я натрапив на цю посаду, коли шукав найкращу практику "приватних даних для занять". Зазначалося, що у деяких з моделей виникнуть проблеми з ефективністю.

Я зібрав кілька тестів на jsperf на основі чотирьох основних зразків з онлайн-книги "Дослідження ES6":

http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes

Тести можна знайти тут:

https://jsperf.com/private-data-for-classes

У Chrome 63.0.3239 / Mac OS X 10.11.6 найкращими моделями були "Приватні дані через середовище конструктора" та "Приватні дані за допомогою імені". Для мене Safari виступив добре для WeakMap, але Chrome не дуже добре.

Я не знаю впливу пам’яті, але схема для «середовищ конструктора», про які дехто попереджав, що це буде проблема продуктивності, була дуже ефективною.

4 основні схеми:

Приватні дані через конструкторські середовища

class Countdown {
    constructor(counter, action) {
        Object.assign(this, {
            dec() {
                if (counter < 1) return;
                counter--;
                if (counter === 0) {
                    action();
                }
            }
        });
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

Приватні дані через конструкторські середовища 2

class Countdown {
    constructor(counter, action) {
        this.dec = function dec() {
            if (counter < 1) return;
            counter--;
            if (counter === 0) {
                action();
            }
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

Приватні дані через конвенцію про іменування

class Countdown {
    constructor(counter, action) {
        this._counter = counter;
        this._action = action;
    }
    dec() {
        if (this._counter < 1) return;
        this._counter--;
        if (this._counter === 0) {
            this._action();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

Приватні дані через WeakMaps

const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
    constructor(counter, action) {
        _counter.set(this, counter);
        _action.set(this, action);
    }
    dec() {
        let counter = _counter.get(this);
        if (counter < 1) return;
        counter--;
        _counter.set(this, counter);
        if (counter === 0) {
            _action.get(this)();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

Приватні дані через символи

const _counter = Symbol('counter');
const _action = Symbol('action');

class Countdown {
    constructor(counter, action) {
        this[_counter] = counter;
        this[_action] = action;
    }
    dec() {
        if (this[_counter] < 1) return;
        this[_counter]--;
        if (this[_counter] === 0) {
            this[_action]();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

4

Я вважаю, що можна досягти "найкращого з обох світів", використовуючи закриття всередині конструкторів. Є дві варіанти:

Усі учасники даних є приватними

function myFunc() {
   console.log('Value of x: ' + this.x);
   this.myPrivateFunc();
}

function myPrivateFunc() {
   console.log('Enhanced value of x: ' + (this.x + 1));
}

class Test {
   constructor() {

      let internal = {
         x : 2,
      };
      
      internal.myPrivateFunc = myPrivateFunc.bind(internal);
      
      this.myFunc = myFunc.bind(internal);
   }
};

Деякі члени є приватними

ПРИМІТКА: Це, правда, некрасиво. Якщо ви знаєте краще рішення, відредагуйте цю відповідь.

function myFunc(priv, pub) {
   pub.y = 3; // The Test object now gets a member 'y' with value 3.
   console.log('Value of x: ' + priv.x);
   this.myPrivateFunc();
}

function myPrivateFunc() {
   pub.z = 5; // The Test object now gets a member 'z' with value 3.
   console.log('Enhanced value of x: ' + (priv.x + 1));
}

class Test {
   constructor() {
      
      let self = this;

      let internal = {
         x : 2,
      };
      
      internal.myPrivateFunc = myPrivateFunc.bind(null, internal, self);
      
      this.myFunc = myFunc.bind(null, internal, self);
   }
};


4

Насправді це можливо за допомогою символів та проксі. Ви використовуєте символи в області класу і встановлюєте дві пастки в проксі: один для прототипу класу, щоб Reflect.ownKeys (екземпляр) або Object.getOwnPropertySymbols не передавав ваші символи, інший - для самого конструктора тому, коли new ClassName(attrs)викликається, повернений екземпляр буде перехоплений та заблоковані власні символи властивостей. Ось код:

const Human = (function() {
  const pet = Symbol();
  const greet = Symbol();

  const Human = privatizeSymbolsInFn(function(name) {
    this.name = name; // public
    this[pet] = 'dog'; // private 
  });

  Human.prototype = privatizeSymbolsInObj({
    [greet]() { // private
      return 'Hi there!';
    },
    revealSecrets() {
      console.log(this[greet]() + ` The pet is a ${this[pet]}`);
    }
  });

  return Human;
})();

const bob = new Human('Bob');

console.assert(bob instanceof Human);
console.assert(Reflect.ownKeys(bob).length === 1) // only ['name']
console.assert(Reflect.ownKeys(Human.prototype).length === 1 ) // only ['revealSecrets']


// Setting up the traps inside proxies:
function privatizeSymbolsInObj(target) { 
  return new Proxy(target, { ownKeys: Object.getOwnPropertyNames });
}

function privatizeSymbolsInFn(Class) {
  function construct(TargetClass, argsList) {
    const instance = new TargetClass(...argsList);
    return privatizeSymbolsInObj(instance);
  }
  return new Proxy(Class, { construct });
}

Reflect.ownKeys()працює так: Object.getOwnPropertyNames(myObj).concat(Object.getOwnPropertySymbols(myObj))саме тому нам потрібна пастка для цих об’єктів.


Дякую, я спробую символи :) З усіх вищенаведених відповідей видається найпростішим способом створити недоступний учасник класу :)
Кокодоко,

4

Навіть Typescript не може цього зробити. З їх документації :

Коли член позначений як приватний, до нього не можна отримати доступ за межами класу, що містить його. Наприклад:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // Error: 'name' is private;

Але перекладено на їхній майданчик це дає:

var Animal = (function () {
    function Animal(theName) {
        this.name = theName;
    }
    return Animal;
}());
console.log(new Animal("Cat").name);

Тож їх "приватне" ключове слово малоефективне.


2
Ну, вона все ще ефективна, оскільки перешкоджає "поганому" програмуванню, перебуваючи в IDE. Він показує, які члени ви повинні та не повинні використовувати. Я думаю, що це головна причина використання приватного та публічного. (Наприклад, коли ви компілюєте C # до машинного коду, приватне все ще буде приватним? Хто знає?). Читаючи інші відповіді, здається, що використання @Symbol також може зробити члена недоступним. Але навіть символи все ще можна знайти з консолі.
Кокодоко

Чи виникає помилка TypeScript під час транспіляції TypeScript в JavaScript? (Як і перевірка типу відбувається в час транзиту. Замість приватного механізму виконання.)
Eljay

4

Прийшов дуже пізно до цієї партії, але я потрапив на питання ОП у пошуку, так що ... Так, ви можете мати приватні властивості, загорнувши декларацію класу в закриття

Є приклад того, як у мене є приватні методи в цьому кодексі . У фрагменті нижче класу Subscribable є дві 'приватні' функції processта processCallbacks. Будь-які властивості можуть бути додані таким чином, і вони залишаються приватними через використання закриття. Конфіденційність IMO є рідкісною потребою, якщо проблеми чітко розділені і Javascript не потрібно роздувати, додаючи більше синтаксису, коли закриття акуратно виконує цю роботу.

const Subscribable = (function(){

  const process = (self, eventName, args) => {
    self.processing.set(eventName, setTimeout(() => processCallbacks(self, eventName, args)))};

  const processCallbacks = (self, eventName, args) => {
    if (self.callingBack.get(eventName).length > 0){
      const [nextCallback, ...callingBack] = self.callingBack.get(eventName);
      self.callingBack.set(eventName, callingBack);
      process(self, eventName, args);
      nextCallback(...args)}
    else {
      delete self.processing.delete(eventName)}};

  return class {
    constructor(){
      this.callingBack = new Map();
      this.processing = new Map();
      this.toCallbacks = new Map()}

    subscribe(eventName, callback){
      const callbacks = this.unsubscribe(eventName, callback);
      this.toCallbacks.set(eventName,  [...callbacks, callback]);
      return () => this.unsubscribe(eventName, callback)}  // callable to unsubscribe for convenience

    unsubscribe(eventName, callback){
      let callbacks = this.toCallbacks.get(eventName) || [];
      callbacks = callbacks.filter(subscribedCallback => subscribedCallback !== callback);
      if (callbacks.length > 0) {
        this.toCallbacks.set(eventName, callbacks)}
      else {
        this.toCallbacks.delete(eventName)}
      return callbacks}

    emit(eventName, ...args){
      this.callingBack.set(eventName, this.toCallbacks.get(eventName) || []);
      if (!this.processing.has(eventName)){
        process(this, eventName, args)}}}})();

Мені подобається такий підхід, тому що він добре розмежовує проблеми і зберігає речі справді приватними. Єдиним недоліком є ​​необхідність використання "self" (або чогось подібного) для позначення "цього" в приватному контенті.


4

Я думаю , що відповідь Бенджаміна, мабуть, найкраща для більшості випадків, поки мова не підтримує явно приватні змінні.

Однак, якщо вам з якоїсь причини потрібно запобігти доступ Object.getOwnPropertySymbols(), метод, який я розглядав, - це приєднання унікального, не конфігуруваного, не перелічуваного, незаписаного властивості, яке може використовуватися як ідентифікатор властивості до кожного об'єкта в будівництві (наприклад, унікальна Symbol, якщо ви ще не маєте якоїсь іншої унікальної властивості, наприклад an id) Потім просто збережіть карту "приватних" змінних кожного об'єкта за допомогою цього ідентифікатора.

const privateVars = {};

class Something {
    constructor(){
        Object.defineProperty(this, '_sym', {
            configurable: false,
            enumerable: false,
            writable: false,
            value: Symbol()
        });

        var myPrivateVars = {
            privateProperty: "I'm hidden"
        };

        privateVars[this._sym] = myPrivateVars;

        this.property = "I'm public";
    }

    getPrivateProperty() {
        return privateVars[this._sym].privateProperty;
    }

    // A clean up method of some kind is necessary since the
    // variables won't be cleaned up from memory automatically
    // when the object is garbage collected
    destroy() {
        delete privateVars[this._sym];
    }
}

var instance = new Something();
console.log(instance.property); //=> "I'm public"
console.log(instance.privateProperty); //=> undefined
console.log(instance.getPrivateProperty()); //=> "I'm hidden"

Потенційна перевага цього підходу перед використанням A WeakMap- це швидший час доступу, якщо продуктивність стане проблемою.


1
Виправте мене, якщо я помиляюся, але чи не міститиме цей код витоки пам’яті, оскільки privateVars все ще зберігатиме приватні змінні об’єкта, навіть якщо об’єкт уже знищений?
Рассел Сантос

@RussellSantos ви маєте рацію, припускаючи, що об’єкти потрібно буде зібрати сміття в якийсь момент. Дякую, що вказали на це. У своєму прикладі я додав destroy()метод, який повинен викликатися за допомогою коду, коли об'єкт потрібно видалити.
NanoWizard

4

Так, цілком може, і дуже легко теж. Це робиться шляхом викриття ваших приватних змінних та функцій шляхом повернення графічного об'єкта-прототипу в конструктор. Це нічого нового, але знайдіть трохи js foo, щоб зрозуміти його елегантність. Цей спосіб не використовує глобальні масштаби чи слабкі карти. Це форма відображення, вбудована в мову. Залежно від того, як ви це використовуєте; можна або примусити виняток, який перериває стек викликів, або поховати виняток як an undefined. Це демонструється нижче, і про ці функції можна прочитати тут

class Clazz {
  constructor() {
    var _level = 1

    function _private(x) {
      return _level * x;
    }
    return {
      level: _level,
      public: this.private,
      public2: function(x) {
        return _private(x);
      },
      public3: function(x) {
        return _private(x) * this.public(x);
      },
    };
  }

  private(x) {
    return x * x;
  }
}

var clazz = new Clazz();

console.log(clazz._level); //undefined
console.log(clazz._private); // undefined
console.log(clazz.level); // 1
console.log(clazz.public(1)); //1
console.log(clazz.public2(2)); //2
console.log(clazz.public3(3)); //27
console.log(clazz.private(0)); //error


3
class Something {
  constructor(){
    var _property = "test";
    Object.defineProperty(this, "property", {
        get: function(){ return _property}
    });
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"
instance.property = "can read from outside, but can't write";
console.log(instance.property); //=> "test"

2
Найкраще уникати відповідей лише з кодом. Було б краще, якщо ви могли б пояснити, як ваш код відповідає на питання ОП
Stewart_R

Це дійсно, як зробити змінну для читання більше, ніж приватну змінну. Приватна змінна не повинна бути доступною зовні. console.log(instance.property)повинен кинути або дати вам невизначений, а не повернути вам "тест".
oooyaya

3

Ще один спосіб, подібний до останніх двох опублікованих

class Example {
  constructor(foo) {

    // privates
    const self = this;
    this.foo = foo;

    // public interface
    return self.public;
  }

  public = {
    // empty data
    nodata: { data: [] },
    // noop
    noop: () => {},
  }

  // everything else private
  bar = 10
}

const test = new Example('FOO');
console.log(test.foo); // undefined
console.log(test.noop); // { data: [] }
console.log(test.bar); // undefined

2

Більшість відповідей або говорять, що це неможливо, або вимагають використання WeakMap або Symbol, які є функціями ES6, які, ймовірно, потребуватимуть поліфілів. Однак є й інший спосіб! Перевірте це:

// 1. Create closure
var SomeClass = function() {
  // 2. Create `key` inside a closure
  var key = {};
  // Function to create private storage
  var private = function() {
    var obj = {};
    // return Function to access private storage using `key`
    return function(testkey) {
      if(key === testkey) return obj;
      // If `key` is wrong, then storage cannot be accessed
      console.error('Cannot access private properties');
      return undefined;
    };
  };
  var SomeClass = function() {
    // 3. Create private storage
    this._ = private();
    // 4. Access private storage using the `key`
    this._(key).priv_prop = 200;
  };
  SomeClass.prototype.test = function() {
    console.log(this._(key).priv_prop); // Using property from prototype
  };
  return SomeClass;
}();

// Can access private property from within prototype
var instance = new SomeClass();
instance.test(); // `200` logged

// Cannot access private property from outside of the closure
var wrong_key = {};
instance._(wrong_key); // undefined; error logged

Я називаю цей метод аксесуаром . Основна ідея полягає в тому, що у нас є закриття , ключ всередині закриття, і ми створюємо приватний об'єкт (у конструкторі), доступ до якого можна отримати лише у вас, якщо у вас є ключ .

Якщо вас цікавить, ви можете прочитати більше про це в моїй статті . Використовуючи цей метод, ви можете створювати для кожного об'єкта властивості, до яких не можна отримати доступ за межами закриття. Тому ви можете використовувати їх у конструкторі чи прототипі, але ніде більше. Я не бачив цього методу ніде, але думаю, що він справді потужний.


Питання полягало в тому, як цього досягти в класах ES6.
Майкл Францл

Можна точно використовувати такий самий метод у класах ES6. Класи ES6 - це головним чином лише цукор поверх функцій, як я представив у своєму прикладі. Цілком можливо, що в оригінальному плакаті використовується транспілятор, і в цьому випадку для слабких карт або символів все-таки знадобиться поліфайл. Моя відповідь справедлива незалежно.
гітаріно

2

Дивіться цю відповідь для чистого та простого "класового" рішення з приватним та загальнодоступним інтерфейсом та підтримкою композиції


2

Я знайшов дуже просте рішення, просто скористайтеся Object.freeze(). Звичайно, проблема полягає в тому, що пізніше ви нічого не можете додати до об'єкта.

class Cat {
    constructor(name ,age) {
        this.name = name
        this.age = age
        Object.freeze(this)
    }
}

let cat = new Cat('Garfield', 5)
cat.age = 6 // doesn't work, even throws an error in strict mode

це також відключить метод setName(name) { this.name = name; }
сеттера на

2

Я використовую цю схему, і це завжди працює для мене

class Test {
    constructor(data) {
        class Public {
            constructor(prv) {

                // public function (must be in constructor on order to access "prv" variable)
                connectToDb(ip) {
                    prv._db(ip, prv._err);
                } 
            }

            // public function w/o access to "prv" variable
            log() {
                console.log("I'm logging");
            }
        }

        // private variables
        this._data = data;
        this._err = function(ip) {
            console.log("could not connect to "+ip);
        }
    }

    // private function
    _db(ip, err) {
        if(!!ip) {
		    console.log("connected to "+ip+", sending data '"+this.data+"'");
			return true;
		}
        else err(ip);
    }
}



var test = new Test(10),
		ip = "185.167.210.49";
test.connectToDb(ip); // true
test.log(); // I'm logging
test._err(ip); // undefined
test._db(ip, function() { console.log("You have got hacked!"); }); // undefined


2

На насправді це можливо.
1. Спочатку створіть клас і в конструктор поверніть викликану _publicфункцію.
2. У виклику _publicфункції передайте thisпосилання (щоб отримати доступ до всіх приватних методів і реквізитів) , і всі аргументи з constructor (що буде передано new Names())
3. У області _publicфункцій також знаходиться Namesклас з доступом до this(_this ) посилання на приватний Namesклас

class Names {
  constructor() {
    this.privateProperty = 'John';
    return _public(this, arguments);
  }
  privateMethod() { }
}

const names = new Names(1,2,3);
console.log(names.somePublicMethod); //[Function]
console.log(names.publicProperty); //'Jasmine'
console.log(names.privateMethod); //undefined
console.log(names.privateProperty); //undefind

function _public(_this, _arguments) {
  class Names {
    constructor() {
      this.publicProperty = 'Jasmine';
      _this.privateProperty; //"John";
      _this.privateMethod; //[Function]
    }

    somePublicMethod() {
      _this.privateProperty; //"John";
      _this.privateMethod; //[Function]
    }

  }
  return new Names(..._arguments);
}

2

Ви можете спробувати це https://www.npmjs.com/package/private-members

Цей пакет збереже членів за примірником.

const pvt = require('private-members');
const _ = pvt();

let Exemplo = (function () {    
    function Exemplo() {
        _(this).msg = "Minha Mensagem";
    }

    _().mensagem = function() {
        return _(this).msg;
    }

    Exemplo.prototype.showMsg = function () {
        let msg = _(this).mensagem();
        console.log(msg);
    };

    return Exemplo;
})();

module.exports = Exemplo;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.