View on GitHub

CloneJS

The true prototype-based lazy programming framework.

Download this project as a .zip file Download this project as a tar.gz file v1.3.2-alpha

This framework provides:

What is the Clone?

clone function produces new objects — Clones.
Clone object — this is the lazy shallow copy, i.e., it is actually not a copy, it's just a reference to the object, with one difference: if you will add/replace any of its properties, it would not affect the cloned object (prototype).
All JavaScript objects are clones of Object.prototype (except itself and objects, created by Object.create(null)).

Try the true prototype-based OOP

With this framework you can easilly create and manipulate objects without constructors, instead of classic js way, where you should define a constructor for every object (that you want to use as prototype), even if you didn't need it. It's possible to build and maintain extremely large numbers of "classes" with comparatively little code.

It's trivial to create new "classes" - just clone the object and change a couple of properties and voila... new "class".

It's really class-free: clone() produces objects (prototypes), not function-constructors, unlike all other class-producing tools (Ext.define, dojo.declare etc).

Read more:

Installation

Node.js:

npm install clonejs

CDN⠙ for client-side:

<script src="http://quadroid.github.io/clonejs/cdn/clone.min.js"></script>

Usage

var clone = require('clonejs');//</node.js>

/// Forget about classes.    
//  Instead of creating class (function), create prototype (object):

var duck$ = { // $ postfix means prototype: Duck.prototype === duck$
    quack: function(){
        console.log( this.name +" Duck: Quack-quack!");
    }
};

/// Inheritance is simple (talkingDuck prototype extends duck prototype):

var talkingDuck$ = clone.extend( duck$, {
    quack: function(){
        duck$.quack.call(this);
        console.log("My name is "+ this.name +"!");
    }
});

/// Forget about the `new` operator, use `clone` function to create instances:

var donald = clone( talkingDuck$, {name: "Donald"});
donald.quack();// Donald Duck: Quack-quack! 
               // My name is Donald!
var daffy  = clone( talkingDuck$, {name: "Daffy"});
daffy.quack(); // Daffy Duck: Quack-quack! 
               // My name is Daffy!

/// Forget about the `instanceof` operator, use JS native 
//  .isPrototypeOf() method instead:

duck$.isPrototypeOf(donald);// true
Object-oriented notation:
  var duck$ = clone.extend({
      quack: function(){
          console.log( this.name +" Duck: Quack-quack!");
      }
  });

  var talkingDuck$ = duck$.$extend({
      quack: function(){
          duck$.quack.call(this);
          console.log("My name is "+ this.name +"!");
      }
  });

  var donald = talkingDuck$.$clone({name: "Donald"});
  var daffy  = talkingDuck$.$clone({name: "Daffy"});

Lazy initialization

How to initialize object without constructor?
Lazy initialization is the tactic of delaying the calculation of a value until the first time it is needed.

var obj = clone.new({
    name: "object"
    },{
    $inits: {
        lazy: function(){
            console.log("Lazy initialization...");
            return this.name +" lazy initiated.":
        }
    }
});

console.log( "obj.lazy: " + obj.lazy );
// Lazy initialization...
// obj.lazy: object lazy initiated.

console.log( "obj.lazy: " + obj.lazy );// initializer does't run again
// obj.lazy: object lazy initiated.

This code will work on IE8-, but you need to remember:

Internet Explorer 8– obsticles

Your accessor function should not return null or undefined.
If accessor returns boolean, you need to compare it with true or false obviously:

if( obj.lazyBoolean == true   ) console.log(true);
// or
if( obj.lazyBoolean.valueOf() ) console.log(true);
// or
if( obj.$get('lazyBoolean')   ) console.log(true);

If accessor returns object, you need to call valueOf() method:

console.log( obj.lazyObject.valueOf().name );

// for info, this will works without errors/warnings on all browsers:
console.log( ({name: "obj.property" }).valueOf().name );// obj.property
console.log( (function(){return "fn"}).valueOf()()    );// fn
console.log( (777).valueOf() );// 777
console.log( "str".valueOf() );// str
console.log( false.valueOf() );// false
// but this will throw error:
console.log( (undefined).valueOf() );
console.log(      (null).valueOf() );

You can call valueOf() method only on first access.
If accessor returns primitive value (string, number, boolean), you can use it as normal.
JavaScript automatically invokes valueOf() in places where a primitive value is expected.


For more details, see API documentation