Skip to content

Instantly share code, notes, and snippets.

@dherman
Forked from jashkenas/minimalist-classes.js
Created November 1, 2011 13:20
Show Gist options
  • Save dherman/1330478 to your computer and use it in GitHub Desktop.
Save dherman/1330478 to your computer and use it in GitHub Desktop.

Revisions

  1. Dave Herman revised this gist Nov 1, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion literal-classes.js
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@ Fox.CONSTANT = value;
    class Student {}

    // copy the own-properties from objectContainingStudentProperties into Student.prototype
    // I plan to advocate a general |expr .= expr| form in favor of "monocle-mustache,"
    // I plan to advocate a general |expr .= expr| form instead of "monocle-mustache,"
    // which makes this simple:

    Student.prototype .= objectContainingStudentProperties;
  2. Dave Herman revised this gist Nov 1, 2011. 2 changed files with 152 additions and 156 deletions.
    152 changes: 152 additions & 0 deletions literal-classes.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,152 @@
    // Demonstrating @jashkenas's examples in an even-more-minimalist version of
    // classes that only allow object-literal syntax for the class body.

    // Basic usage; unchanged.

    class Color {

    constructor: function(hex) {
    ...
    },

    r: 1, g: 1, b: 1,

    copy: function(color) {
    ...
    },

    setRGB: function(r, g, b) {
    ...
    },

    setHSV: function(h, s, v) {
    ...
    }

    }


    // Subclassing; unchanged.

    class Fox extends Animal {
    ...
    }

    // Class properties; unchanged.

    Fox.CONSTANT = value;


    // @jashkenas wrote:
    // class Student objectContainingStudentProperties

    class Student {}

    // copy the own-properties from objectContainingStudentProperties into Student.prototype
    // I plan to advocate a general |expr .= expr| form in favor of "monocle-mustache,"
    // which makes this simple:

    Student.prototype .= objectContainingStudentProperties;

    // Notice that this makes it clearer that we are *copying* own properties from the
    // objectContainingStudentProperties object, instead of, say, sharing or proto-extending.


    // @jashkenas wrote:

    // class Protester merge(YoungAdult, WorkEthic, Idealism, {
    // student: true
    // })

    class Protester {}

    Protester.prototype .= merge(YoungAdult, WorkEthic, Idealism, {
    student: true
    });

    // class expressions; unchanged

    animals.push(class Fox {});

    var subclass = function(parent) {
    return class extends parent;
    };


    // @jashkenas wrote:

    // var generateModelClass = function(columns) {

    // var definition = {};

    // columns.forEach(function(col) {
    // definition['get' + col] = function() {
    // return this[col];
    // };
    // definition['set' + col] = function(value) {
    // return this[col] = value;
    // };
    // });

    // return class definition;

    // };

    var generateModelClass = function(columns) {

    var C = class {};
    var p = C.prototype;

    columns.forEach(function(col) {
    p['get' + col] = function() {
    return this[col];
    };
    p['set' + col] = function(value) {
    return this[col] = value;
    };
    });

    return C;

    };


    // Monster class example; unchanged

    class Monster {

    constructor: function(name, health) {
    this.name = name;
    this.health = health;
    },

    attack: function(target) {
    log("The monster attacks " + target);
    },

    isAlive: function() {
    return this.health > 0;
    },

    setHealth: function(value) {
    if (value < 0) {
    throw new Error("Health must be non-negative.");
    }
    this.health = value;
    },

    numAttacks: 0,

    attackMessage: "The monster hits you!"

    }


    // The point in all this is that you can be just as dynamic if the body
    // is restricted to an object literal, but you may have to use assignment
    // to copy own-properties into the prototype from a dynamically computed
    // source.

    // tl;dr
    // Even-more-minimal classes are an expression form ([] means optional):
    // class [name] [extends parent] [object literal]
    156 changes: 0 additions & 156 deletions minimalist-classes.js
    Original file line number Diff line number Diff line change
    @@ -1,156 +0,0 @@
    // Here is a proposal for minimalist JavaScript classes, humbly offered.

    // There are (at least) two different directions in which classes can be steered.
    // If we go for a wholly new semantics and implementation, then fancier classical
    // inheritance can be supported with parallel prototype chains for true inheritance
    // of properties at both the class and instance level.

    // If however, we keep current JavaScript prototype semantics, and add a form that
    // can desugar to ES3, things must necessarily stay simpler. This is the direction
    // I'm assuming here.

    // If we want to have static class bodies (no executable code at the top level),
    // then we would do well to reuse the known and loved JavaScript idiom for
    // fixed lists of properties -- the object literal.

    // First, basic usage from a real-world library (Three.js)

    class Color {

    constructor: function(hex) {
    ...
    },

    r: 1, g: 1, b: 1,

    copy: function(color) {
    ...
    },

    setRGB: function(r, g, b) {
    ...
    },

    setHSV: function(h, s, v) {
    ...
    }

    }


    // To create a class with its prototype chain set correctly:

    class Fox extends Animal {
    ...
    }

    // Note that "Animal" here is a class object (constructor function) in its
    // own right. Fox.prototype is set to an instance of Animal that has been
    // constructed without calling its constructor function -- this is the
    // usual two-step setting-up-a-prototype shuffle.


    // There is no special syntax for setting class-level properties, as they are
    // relatively rare. Just add them to the class object itself:

    Fox.CONSTANT = value;


    // Note that the right-hand side of a class definition is just an expression,
    // an object literal is not required. You can be fully dynamic when creating a
    // class:

    class Student objectContainingStudentProperties

    // Or even:

    class Protester merge(YoungAdult, WorkEthic, Idealism, {
    student: true
    })

    // The point I'm trying to make being that the own properties of the right hand
    // side, however they're derived, become the prototypal properties of the resulting
    // class.


    // Similarly, class definitions are themselves expressions, and anonymous classes
    // are equally possible:

    animals.push(class Fox {});

    var subclass = function(parent) {
    return class extends parent;
    };


    // Naturally, classes can be built up programmatically in this fashion.

    var generateModelClass = function(columns) {

    var definition = {};

    columns.forEach(function(col) {
    definition['get' + col] = function() {
    return this[col];
    };
    definition['set' + col] = function(value) {
    return this[col] = value;
    };
    });

    return class definition;

    };


    // Finally, the Monster class from the current nutshell proposal
    // (http://wiki.ecmascript.org/doku.php?id=harmony:classes#the_proposal_in_a_nutshell)
    // ... sans unnecessary restrictions:

    class Monster {

    constructor: function(name, health) {
    this.name = name;
    this.health = health;
    },

    attack: function(target) {
    log("The monster attacks " + target);
    },

    isAlive: function() {
    return this.health > 0;
    },

    setHealth: function(value) {
    if (value < 0) {
    throw new Error("Health must be non-negative.");
    }
    this.health = value;
    },

    numAttacks: 0,

    attackMessage: "The monster hits you!"

    }


    // I think that's about the run of it. Note what is left out: public / private /
    // static / frozen / const properties and their ilk. Personally, I'm of the view
    // that all of these modifiers are deeply undesirable in a language as dynamic
    // as JavaScript and won't be much used, if added ... but I also think that
    // getters and setters should be deprecated and removed.

    // If public / private / static / frozen / const must be a part of class syntax
    // in JS.next, then they must be valid prefixes for object literals as well --
    // and can easily be used to define classes with those properties under this
    // proposal.

    // There are no new semantics here, and these classes can easily be transpiled
    // into ES3 if needed -- just simpler declaration of constructors with prototypal
    // properties and correctly configured prototype chains.

    // tl;dr
    // Classes are a new expression with the form ([] means optional):
    // class [name] [extends parent] [expression]
  3. @jashkenas jashkenas revised this gist Nov 1, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion minimalist-classes.js
    Original file line number Diff line number Diff line change
    @@ -109,7 +109,7 @@ var generateModelClass = function(columns) {

    class Monster {

    constructor: (name, health) {
    constructor: function(name, health) {
    this.name = name;
    this.health = health;
    },
  4. @jashkenas jashkenas revised this gist Nov 1, 2011. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion minimalist-classes.js
    Original file line number Diff line number Diff line change
    @@ -44,9 +44,14 @@ class Fox extends Animal {
    ...
    }

    // Note that "Animal" here is a class object (constructor function) in its
    // own right. Fox.prototype is set to an instance of Animal that has been
    // constructed without calling its constructor function -- this is the
    // usual two-step setting-up-a-prototype shuffle.


    // There is no special syntax for setting class-level properties, as they are
    // relatively rare. Just add them to the class object (constructor function):
    // relatively rare. Just add them to the class object itself:

    Fox.CONSTANT = value;

  5. @jashkenas jashkenas created this gist Nov 1, 2011.
    151 changes: 151 additions & 0 deletions minimalist-classes.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,151 @@
    // Here is a proposal for minimalist JavaScript classes, humbly offered.

    // There are (at least) two different directions in which classes can be steered.
    // If we go for a wholly new semantics and implementation, then fancier classical
    // inheritance can be supported with parallel prototype chains for true inheritance
    // of properties at both the class and instance level.

    // If however, we keep current JavaScript prototype semantics, and add a form that
    // can desugar to ES3, things must necessarily stay simpler. This is the direction
    // I'm assuming here.

    // If we want to have static class bodies (no executable code at the top level),
    // then we would do well to reuse the known and loved JavaScript idiom for
    // fixed lists of properties -- the object literal.

    // First, basic usage from a real-world library (Three.js)

    class Color {

    constructor: function(hex) {
    ...
    },

    r: 1, g: 1, b: 1,

    copy: function(color) {
    ...
    },

    setRGB: function(r, g, b) {
    ...
    },

    setHSV: function(h, s, v) {
    ...
    }

    }


    // To create a class with its prototype chain set correctly:

    class Fox extends Animal {
    ...
    }


    // There is no special syntax for setting class-level properties, as they are
    // relatively rare. Just add them to the class object (constructor function):

    Fox.CONSTANT = value;


    // Note that the right-hand side of a class definition is just an expression,
    // an object literal is not required. You can be fully dynamic when creating a
    // class:

    class Student objectContainingStudentProperties

    // Or even:

    class Protester merge(YoungAdult, WorkEthic, Idealism, {
    student: true
    })

    // The point I'm trying to make being that the own properties of the right hand
    // side, however they're derived, become the prototypal properties of the resulting
    // class.


    // Similarly, class definitions are themselves expressions, and anonymous classes
    // are equally possible:

    animals.push(class Fox {});

    var subclass = function(parent) {
    return class extends parent;
    };


    // Naturally, classes can be built up programmatically in this fashion.

    var generateModelClass = function(columns) {

    var definition = {};

    columns.forEach(function(col) {
    definition['get' + col] = function() {
    return this[col];
    };
    definition['set' + col] = function(value) {
    return this[col] = value;
    };
    });

    return class definition;

    };


    // Finally, the Monster class from the current nutshell proposal
    // (http://wiki.ecmascript.org/doku.php?id=harmony:classes#the_proposal_in_a_nutshell)
    // ... sans unnecessary restrictions:

    class Monster {

    constructor: (name, health) {
    this.name = name;
    this.health = health;
    },

    attack: function(target) {
    log("The monster attacks " + target);
    },

    isAlive: function() {
    return this.health > 0;
    },

    setHealth: function(value) {
    if (value < 0) {
    throw new Error("Health must be non-negative.");
    }
    this.health = value;
    },

    numAttacks: 0,

    attackMessage: "The monster hits you!"

    }


    // I think that's about the run of it. Note what is left out: public / private /
    // static / frozen / const properties and their ilk. Personally, I'm of the view
    // that all of these modifiers are deeply undesirable in a language as dynamic
    // as JavaScript and won't be much used, if added ... but I also think that
    // getters and setters should be deprecated and removed.

    // If public / private / static / frozen / const must be a part of class syntax
    // in JS.next, then they must be valid prefixes for object literals as well --
    // and can easily be used to define classes with those properties under this
    // proposal.

    // There are no new semantics here, and these classes can easily be transpiled
    // into ES3 if needed -- just simpler declaration of constructors with prototypal
    // properties and correctly configured prototype chains.

    // tl;dr
    // Classes are a new expression with the form ([] means optional):
    // class [name] [extends parent] [expression]