/cloz

create closed objects

Primary LanguageJavaScriptMIT LicenseMIT

cloz.js

Overview

Cloz provides simple closed objects with some simple methods. A closed object can have closed properties which cannot be accessed directly. If you want to read or write those properties, use 'get' or 'set' methods.

Why use closed objects?

If you use objects for both namespace and class and your project become larger, it is recommended to distingish between the two roles.

// use as namespace
var my_project = {};
my_project.model = {};
my_project.controller = {};
my_project.view = {};

// use as class property
my_project.contributors = ['someone', 'somebody'];
my_project.view.index = function(){
	return '<p>index</p>';
};

Therefore, functional objects, which is often used as class, should not show the tree of structure in case used as namespace. A closed object has no information of the tree available, and you can manage objects more semantically.

// cloz
// my_project is available
// but my_project.contributors is forbidden
var my_project = cloz({}, {
	contributors: ['someone', 'somebody'],
});

// cloz
// my_project.view is available
// but my_project.view.index is forbidden
my_project.view = cloz({}, {
	index: function(){
		return '<p>index</p>';
	},
});

Basic usage

To create a cloz (equal to a closed object), a base object is needed.

// base object
var base = {};

// create new cloz
var creature = cloz(base);

// If the base object is empty and never shared, the following is OK.
var creation = cloz();

To inherit a cloz, just put it as a base object.

var mammal = cloz(creature);

To extend a base object, provide the second argument.

var man = cloz(mammal, {
	name: 'man',
	speak: function(){},
});

To get a property of cloz, use cloz.get().

var miki = cloz(man, {
	name: 'Miki',
	hair: 'blond',
	languages: cloz(base, {
		ja: 'こんにちは。',
		en: 'Hi.',
	}),
	speak: function(language){
		return this.get('languages').get(language);
	},
});

console.log(miki.get('name')); // => "Miki"
console.log(miki.get('speak', 'ja')); // => "こんにちは。"

To set a property of cloz, use cloz.set().

miki.set('hair', 'brown');
miki.set('laugh', function(){ return 'Haha.'; });

If a preset property's value is a cloz, use cloz.extend() instead.

miki.extend('language', {
	ja: 'やあ。',
	zh: '你好。',
});

console.log(miki.get('speak', 'ja')); // => "やあ。" (overridden)
console.log(miki.get('speak', 'en')); // => "Hi." (preset)
console.log(miki.get('speak', 'zh')); // => "你好。" (new)

How cloz works

Cloz's inheritance is prototypal. If a value of property of a base object is changed, that of the cloz will be also changed. But overridden values are static.

var miki_clone = cloz(miki, {
	name: 'Cloned Miki',
});

console.log(miki_clone.get('name')); // => "Cloned Miki"
console.log(miki_clone.get('hair')); // => "brown"

miki.set('name', 'Original Miki');
miki.set('hair', 'black');

console.log(miki_clone.get('name')); // => "Cloned Miki" (referred to miki_clone)
console.log(miki_clone.get('hair')); // => "black" (referred to miki)

You shoud not create deep-nested cloz (3 level or more) becase that can unexpectedly affect the base object as below.

var dog = cloz(mammal, {
	status: cloz(base, {
		feelings: cloz(base, {
			happy: '^o^',
		}),
	}),
});

var pochi = cloz(dog);
pochi.get('status').extend('feelings', {
	happy: '^w^',
});

// pochi's method affected dog's property
console.log(dog.get('status').get('feelings').get('happy')); // => ^w^

API

get(property [, arguments ])

Get the property's value or execute the function.

gain(property [, value = null [, arguments ] ])

Behave similarly to get() but return the default value if the property is not found.

var app = cloz({}, {
	platform: ['Android', 'iOS'],
});

var game = cloz(app);

console.log(game.gain('os', ['Windows Phone'])); // => Array [ "Windows Phone" ]
console.log(game.get('os')); // => Error: Cannot find property "os"

getAll()

Get an object containing all properties and each value.

set(property, value)

Set the value to the property.

set(extension)

Set the values to the properties using a key-value object.

extend(property, extension)

Extend the cloz value of the property.

extension._cloz(function)

Call the function whenever the cloz or its descendant cloz is created.

// output "created!" twice
var parent = cloz({}, {
	_cloz: function(){
		console.log('created!');
	}
});
var child = cloz(parent);

extension.__cloz(function)

Call the function when the cloz itself is created.

// output "created!" only once
var parent = cloz({}, {
	__cloz: function(){
		console.log('created!');
	}
});
var child = cloz(parent); // => no output