Как получить доступ к закрытым полям из родительского класса в JavaScript?

#javascript #class #oop #private

Вопрос:

У меня есть класс кучи, в котором есть закрытое values поле. Это хорошо, так как я не хочу, чтобы кто-либо мог напрямую изменять values .

 class Heap {
  
  #values;
  
  constructor(array = []) {
    this.#values = array;
  }

    insert(item) {
    this.#values.push(item);
    this.#bubbleUp(this.#values.length - 1);
  }
}
 

Но теперь я хотел бы расширить свой класс Heap до подкласса PriorityQueue. В этом классе мне нужно изменить сигнатуру некоторых методов (например insert ), чтобы он присваивал приоритет значению. Однако я не могу понять, как получить доступ к values полю из базового класса. Например, учитывая следующий класс PriorityQueue:

 class PriorityQueue extends Heap {
  
  constructor(array = []) {
    super(array);
  }
  
  insert(item, priority) {

    // Error: Private field '#values' must be declared in an enclosing class
    this.#values.push({ item, priority }); 
    this.#bubbleUp(this.#values.length - 1);
  }
}
 

Я получаю сообщение об ошибке при попытке ввести значение values .

Есть ли какой-либо способ обойти эту проблему? Я хочу сделать поле закрытым в базовом классе, но по-прежнему доступным для подкласса.

Спасибо!

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

1. Просто вызвать родительский insert метод? super.insert({ item, priority }) .

2. » Я хочу сделать поле закрытым в базовом классе, но при этом доступным для подкласса». вот что такое защищенный доступ. Однако в JS этого пока нет. Итак, все, что вы хотите использовать в подклассах, должно быть общедоступным.

Ответ №1:

Я не могу понять, как получить доступ к values полю из базового класса.

Это невозможно. Private действительно означает private в JS. Не используйте его, если вы хотите, чтобы поле было доступно за пределами класса.

Я хочу сделать поле закрытым в базовом классе, но по-прежнему доступным для подкласса.

Это был бы защищенный элемент, который JS не поддерживает.

Есть ли какой-либо способ обойти эту проблему?

Ну, на самом деле вам не нужно обращаться к .#values . Все, что вам нужно сделать, это вызвать метод базового класса insert :

 class PriorityQueue extends Heap { 
  insert(item, priority) {
    super.insert({ item, priority });
  }
}
 

Я хотел бы расширить свой Heap класс до PriorityQueue подкласса. В этом классе мне нужно изменить сигнатуру некоторых методов (например, insert), чтобы он присваивал приоритет значению.

Это плохая идея. Подкласс не должен изменять сигнатуры методов, иначе это нарушит принцип подстановки Лискова. Вместо этого используйте композицию вместо наследования, где приоритетная очередь имеет или содержит кучу:

 class PriorityQueue {
  #heap = new Heap(v => v.priority); // assuming it takes a custom comparator?
  
  push(item, priority) {
    this.#heap.insert({ item, priority });
  }
  pop() {
    return this.#heap.…
  }
}
 

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

1. Спасибо за ваш ответ, ваш пост очень помогает. Мой Heap класс использует компаратор. Я никогда даже не рассматривал возможность структурирования PriorityQueue для создания экземпляра кучи, а не для наследования от класса кучи. Мне явно есть чему поучиться. Кстати, рекомендуете ли вы какие-либо книги для изучения таких тем, как композиция вместо наследования ?