3

Could anyone recommend good resources for using traits in javascript? After some searching I mainly find articles about libraries that provide traits functionality, but I was curious about best practices on how to implement traits without a library.

I came across this post on SO, are there any other approaches? Traits in javascript

Any real world examples would be welcome as well.

Thanks.

Community
  • 1
  • 1
Alex Heyd
  • 1,323
  • 1
  • 10
  • 17

5 Answers5

3

I would suggest something simple, along the lines of:

  1. Let traits be defined as standard JavaScript objects.

    var equalsTrait = {
        eq: function(obj) {
            return this == obj
        },
        neq: function(obj) {
            return ! this.eq(obj)
        }
    };
    
  2. Write a function to extend a given class with your traits (and bind it to a sensible location in the global scope):

    window.Traits = {};
    Traits.addToClass = function(traits, cls) {
        for (var key in traits) {
            if (cls.prototype[key]) {
                alert("Class " + cls + " already has a method named " + key + "!");
            }
            else {
                cls.prototype[key] = traits[key];
            }
        }
    }
    
  3. Profit!

aroth
  • 54,026
  • 20
  • 135
  • 176
  • Thanks for the example. So from a pattern perspective, what would you say are the criteria that needs to be met for traits to be properly implemented? Traits are reusable functionality that can be implemented by any object. Anything else besides that? I see in libraries that they handle namespace conflicts. In your example, the traits get copied to every instance created, would it be better (if even desirable at all) to have traits shared amongst all instances? – Alex Heyd Aug 08 '11 at 15:31
2

Two papers that do describe library agnostic pure function based Mixin and Trait approaches for JavaScript are A fresh look at JavaScript Mixins by Angus Croll from May 2011 and The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins from April 2014.

so long

Appendix I

please see also:

Appendix II

Since from time to time I'm apparently fiddle with this matter I wan't to add some final thoughts to it ...

The library agnostic approach without too much glue code (as mentioned above) does work only for very fine grained composable units of behavioral reuse. Thus, as long as one does not run into more than 1 or 2 easily resolvable conflicts, patterns based on e.g. Angus Croll's Flight Mixins are the path to follow.

If it comes to real traits, there has to be an abstraction level to it. This layer (e.g. provided as some sort of syntactic sugar like a DSL) needs to hide the complexity e.g. of composing traits from traits or of conflict resolution at a traits apply time (when a trait's behavior gets applied to an object/type).

By now there are 3 examples at SO that from my perspective provide exactly what the OP did ask for …

Any real world examples would be welcome as well.

Community
  • 1
  • 1
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
2

Some (limited) information about traits in the trait.js library

Not about Javascript, but a good paper about inheritance systems and traits "Traits: A Mechanism for Fine-grained Reuse". A description of implementation details can be found in "Applying Traits to the Smalltalk Collection Hierarchy". More papers of this type listed on this page.

widged
  • 2,749
  • 21
  • 25
0

You can use function to implement traits without a library.

See working example Traits + Inheritance

Thanks to dbarbeau

// Usage __traits(TargetClass, Trait1, Trait2, ...);
// Mix multiple definitions as traits. Properties will be overwritten if names are duplicating. 
function __traits(mixtureTarget) {
    for(var a=1; a < arguments.length; ++a) {
        var mixin = arguments[a];
        for (var p in mixin){ if (mixin.hasOwnProperty(p)){ mixtureTarget[p] = mixin[p]; } };
        Object.getOwnPropertyNames(mixin.prototype).forEach( function(name) {
            mixtureTarget.prototype[name] = mixin.prototype[name];
        });
    }; 
};
pavel
  • 14
  • 4
0

there is simple and lightweight a package in npm for this. you can check it here, it really made trait from PHP feature easily get implemented on Javascript.

https://github.com/regs37/trait.js

// create a simple trait that you want to be reusable
const MyTrait = trait({
  sampleTrait: function(){
    return "trait";
  }
})

// lets have a sample class User
class User {

}

// we will inherit the trait to the User Class
MyTrait.in(User);

// sample instance of the user
let user = new User();

// try to call he trait we have inherited
console.log(user.sampleTrait()); // trait
<script src="https://unpkg.com/trait.js@1.2.12/build/trait.min.js"></script>
  • This nice project actually qualifies more for the many existing approaches / solutions / implementations which are better labeled as *mixin*. A trait is distinct from the more straightforward *mixin* approach by providing (additional to the base composition task) conflict resolution processes / operators like `before`, `after`, `alias` for e.g. equally named methods. Providing the mixin functionality to whatever kind of `prototype` object (like with [`inherit_to`](https://github.com/regs37/trait.js/blob/master/src/methods/inherit_to.js)) does not automatically make an implementation a *trait*. – Peter Seliger Oct 06 '20 at 17:48