Инкапсуляция в JavaScript с помощью getter и setter

Я понимаю, что об этом спрашивали, но исследовали и потерпели неудачу - извините!

Я хочу реализовать инкапсуляцию в JS как можно проще. Я понимаю, что любой "var" в классе будет частным.

Я просто не уверен, как получить и установить значения любого частного var. В приведенном ниже примере методы интерфейса для получения и установки 'color' не работают, потому что эти функции не могут получить доступ к частному свойству 'color' объекта. Я не могу найти четкий пример, показывающий мне, как это реализовать.

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

Спасибо!

<button onclick="testOOP()">Click me</button>

<script>
//<!-- 
function testOOP(){
var v1 = new vehicle(4, "red"); //setting new values during instantiation
var v2 = new vehicle(2, "blue");
showVehDetails(v1);
showVehDetails(v2);
v2.wheels=1;            //demonstrating no encapsulation
showVehDetails(v2);
v2.setcolour("orange");     //using an interface - fails
showVehDetails(v2);
}

    function showVehDetails(v){
        document.write("This vehicle is " + v.getcolour() + " and has " + v.getwheels() + " wheels.<br/>");
    }

    //*************'vehicle' - Class definition**************
    function vehicle(thewheels, thecolour){
        this.wheels = thewheels;            //public property
        var colour = thecolour;             //private property
    }   
    vehicle.prototype = {
        constructor: vehicle,
        getcolour: function(){
            return this.colour;         //but how to create a GETTER for colour?
        },
        getwheels: function(){
            return this.wheels;
        },
        setwheels: function(newwheels){
            this.wheels = newwheels;
        },
        setcolour: function(newcolour){   //and how to create a SETTER for colour?
            this.colour = newcolour;
        }
    }
    //************End class definition************************
   //-->
 </script>

1 ответ

Решение

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

function Vehicle(thewheels, thecolour){
  this.wheels = thewheels;
  this.colour = thecolour;
}

Vehicle.prototype = {
  getColour: function() {
    return this.colour;
  }
  // etc
};

... но вы должны спросить себя, какую выгоду вы получаете от размещения геттеров / сеттеров вокруг этих участников? Довольно редко можно использовать шаблон получения / установки в JavaScript. Обычно вы просто создаете публичных участников. Использование таких вещей, как _ Префикс для членов - типичный способ сообщить: "Я знаю, что это доступно, но вы не должны изменять это напрямую".

Если вы хотите сделать вещи по-настоящему "приватными", вам нужно сделать несколько трюков с замыканиями:

function Vehicle(theWheels, theColor) {
  return {
    getColour: function() { return theColor; },
    setColour: function(value) { theColor = value; }
  };
}

... но недостатком этого подхода является каждый Vehicle объект имеет свою копию этих функций; Вы не получаете преимущества памяти прототипа.

Обновление:

Также обратите внимание: если вы хотите запускать логику при смене членов, заключая в себе методы, есть более приятные способы создания методов получения и установки в современном JS:

function Vehicle(theWheels, theColor) {
  this._wheels = theWheels;
  this._color = theColor;
}

Vehicle.prototype = {
  get color() { return this._color; },
  set color(value) { this._color = value; console.log('Changed color'); },

  get wheels() { return this._wheels; },
  set wheels(value) { this._wheels = value; }
}

Звонящий просто получает доступ .wheels а также .color как обычные свойства, и он будет вызывать ваши методы.

Другие вопросы по тегам