Obiekty - inner sposoby tworzenia obiektów

Wraz z rozwojem JavaScript dochodziły nowe sposoby na tworzenie obiektów. Jednym z nich jest użycie metody Object.create(obPrototype, propertyObject). Jako pierwszy parametr przyjmuje obiekt, który stanie się prototypem nowo tworzonych obiektów:


const ob = {
    name : "Marcin"
}

const son = Object.create(ob);
son.age = 10;

console.log(son);
object create

Przy tworzeniu nowych obiektów za pomocą Object.create() ich prototypem staje się obiekt, który podaliśmy w nawiasach. Dzięki temu można to wykorzystać do stworzenia dziedziczenia:


const animalObj = {
    eat : function() {
        console.log(this.name + " właśnie je");
    }
}

const birdObj = Object.create(animalObj);
birdObj.fly = function() {
    console.log(this.name + " właśnie lata");
}

const bird = Object.create(bird);
bird.name = "Ptak 1";
bird.fly();
bird.eat();

Drugim parametrem Object.create() jest obiekt, który zawiera dodatkowe właściwości nowo tworzonego obiektu. Każdą taką zmienną możemy opisać za pomocą kilku właściwości:


const obj = Object.create(Object.prototype, {
    foo: {
        writable: true,
        configurable: true,
        value: 'hello'
    },
    bar: {
        configurable: false,
        get: function() { return 10; },
        set: function(value) {
            console.log('Ustawiam wartość bar na: ', value);
        }
    }
}

Każda taka właściwość może być opisana za pomocą właściwości:

  • writable (true/false) - czy zmienna może być zmieniana.
  • configurable (true/false) - czy zmienna może być zmieniana przez ten obiekt, lub czy może być usuwana (delete ob.nazwaWlasciwosci)
  • value - wartość tej właściwości. Nie można tego używać wraz z get/set
  • get - tak zwany getter - funkcja wywoływana gdy pobieramy daną wartość
  • set - tak zwany setter - funkcja wywoływana gdy ustawiamy daną wartość
  • enumerable - czy wartość ma być widoczna przy pętlach iteracyjnych (np. for in) - np. length nie jest

W powyższym kodzie stworzyliśmy obiekt, od razu przy tym ustawiając jego właściwości. Możemy też takie właściwości dodawać poza ciałem obiektu za pomocą defineProperty():


const ob = {
    _name : "marcin",
    _height : 184
};

Object.defineProperty(ob, 'name', {
    set : function(newName) {
        this._name = newName;
    },
    get : function() {
        return this._name.charAt(0).toUpperCase() + this._name.substr(1).toLowerCase();
    }
});

Object.defineProperty(ob, 'height', {
    get : function(height) {
        this._height = height;
    },
    set : function(height) {
        this._height = height + 'cm';
    }
});

Object.defineProperty(ob, 'gender', {
    writable : false,
    value : "male"
});

console.log(ob.name); //Marcin
ob.name = "grzegorz";
console.log(ob.name); //Grzegorz

ob.height = 180;
console.log(ob.height); //180cm

ob.gender = "woman"; //male - nie możemy zmienić tej właściwości

Powyższe definiowanie właściwości możemy też połączyć z konstruktorem:


function Car(brand, color) {
    this.brand = brand;
    this.color = color;

    var _speed; //zmienna prywatna niedostępna z zewnątrz

    Object.defineProperty(this, "speed", {
        get: function() {
            return this._speed;
        },
        set: function(value) {
            this._speed = value;
            if (this._speed > 180) {
                this._speed = 180;
            }
        }
    });
}

const car = new Car("BMW", "Black");
car.speed = 160;
car.speed += 20;
car.speed += 20; // 180 a nie 200!
console.log(car.speed); //180km

Jeżeli temat cię zainteresował polecam dwa artykuły: https://addyosmani.com/resources/essentialjsdesignpatterns/book/ i http://robotlolita.me/2011/10/09/understanding-javascript-oop.html