Source: framework/components/component.js

Object.assign(pc, function () {
    /**
     * @constructor
     * @name pc.Component
     * @classdesc Components are used to attach functionality on a {@link pc.Entity}. Components
     * can receive update events each frame, and expose properties to the PlayCanvas Editor.
     * @description Base constructor for a Component
     * @param {pc.ComponentSystem} system The ComponentSystem used to create this Component
     * @param {pc.Entity} entity The Entity that this Component is attached to
     * @property {Boolean} enabled Enables or disables the component.
     */
    var Component = function (system, entity) {
        this.system = system;
        this.entity = entity;

        pc.events.attach(this);

        if (this.system.schema && !this._accessorsBuilt) {
            this.buildAccessors(this.system.schema);
        }

        this.on("set", function (name, oldValue, newValue) {
            this.fire("set_" + name, name, oldValue, newValue);
        });

        this.on('set_enabled', this.onSetEnabled, this);
    };

    Component._buildAccessors = function (obj, schema) {
        // Create getter/setter pairs for each property defined in the schema
        schema.forEach(function (descriptor) {
            // If the property descriptor is an object, it should have a `name`
            // member. If not, it should just be the plain property name.
            var name = (typeof descriptor === 'object') ? descriptor.name : descriptor;

            Object.defineProperty(obj, name, {
                get: function () {
                    return this.data[name];
                },
                set: function (value) {
                    var data = this.data;
                    var oldValue = data[name];
                    data[name] = value;
                    this.fire('set', name, oldValue, value);
                },
                configurable: true
            });
        });

        obj._accessorsBuilt = true;
    };

    Component.prototype = {
        buildAccessors: function (schema) {
            Component._buildAccessors(this, schema);
        },

        onSetEnabled: function (name, oldValue, newValue) {
            if (oldValue !== newValue) {
                if (this.entity.enabled) {
                    if (newValue) {
                        this.onEnable();
                    } else {
                        this.onDisable();
                    }
                }
            }
        },

        onEnable: function () { },

        onDisable: function () { },

        onPostStateChange: function () { }
    };

    /**
     * @private
     * @property {pc.ComponentData} data Access the {@link pc.ComponentData} directly.
     * Usually you should access the data properties via the individual properties as
     * modifying this data directly will not fire 'set' events.
     */
    Object.defineProperty(Component.prototype, "data", {
        get: function () {
            var record = this.system.store[this.entity.getGuid()];
            return record ? record.data : null;
        }
    });

    return {
        Component: Component
    };
}());