Kinds

enyo/kind

enyo/kind is the Enyo framework's module for generating kinds. A kind is a constructor-with-prototype (like a class) that has advanced features like prototype-chaining (inheritance).

A plug-in system is included for extending the abilities of the kind generator, and constructors are allowed to perform custom operations when subclassed.

In this article, we look at several things that happen when kind() is invoked. To learn about what happens once you have an instantiated object, see Objects and Published Properties and Components.

Special Property Names

Generally, the properties defined in the configuration object passed to kind() are copied directly to the generated prototype, but certain property names trigger special processing. Some examples of special properties are:

Certain kinds in the framework define their own special properties, e.g., the published property supported by enyo/CoreObject/Object.

Lifecycle of a Trivial Kind

A trivial kind has a simple lifecycle:

    var
        kind = require('enyo/kind');

    var MyKind = kind({
        name: 'MyKind',
        kind: null, // otherwise it will default to 'Control'
        constructor: function () {
            // do any initialization tasks
        }
    });

That's it. MyKind() is now a function that you can use with the new operator to create instances.

        myInstance = new MyKind();

Like all JavaScript objects, a kind instance will be garbage-collected when there are no references to it.

Inheritance: this.inherited()

It's common for one kind to be based on another kind. The new kind inherits all the properties and methods of the old kind. If the new kind overrides a method from the old kind, you can call the overridden method using this.inherited():

    var
        kind = require('enyo/kind');

    var MyNextKind = kind({
        name: 'MyNextKind',
        kind: MyKind,
        constructor: function () {
            // do any initialization tasks before MyKind initializes
            //
            // do inherited initialization (optional, but usually a good idea)
            this.inherited(arguments);
            //
            // do any initialization tasks after MyKind initializes
            }
        });

MyNextKind starts with all the properties and methods of MyKind, but then we override constructor(). Our new constructor may call the old constructor using the this.inherited() syntax. The first parameter passed to this.inherited() must be the literal arguments, which is a special JavaScript variable containing information about the executing function. (For more about arguments, see developer.mozilla.org.)

In its constructor, MyNextKind may specify things to do before or after calling the old constructor, or it may choose to not call the old constructor at all.

This override system works the same for any method, not just constructor():

    var
        kind = require('enyo/kind');

    var MyOriginalKind = kind({
        name: 'MyOriginalKind',
        doWork: function () {
            this.work++;
        }
    });

    var MyDerivedKind = kind({
        name: 'MyDerivedKind',
        kind: MyOriginalKind,
        doWork: function () {
            if (this.shouldDoWork) {
                this.inherited(arguments);
            }
        }
    });

Note that you could also call an inherited method using only raw JavaScript, like so:

    MyKind.prototype.<method name>.apply(this, arguments);

However, the this.inherited() syntax is shorter and eliminates the need to specify the superkind's name (in this case, MyKind).

Additional Reading