prop-d

1.3.1 • Public • Published

prop-d

An ES-5 object property descriptor factory.

Build Status Coverage Status Code Climate

Description

Writing out object descriptors is tedius and not very DRY, however they can be very useful.
This is a tiny (1k minified, <0.5k gzipped) library to take away the tedium and make your code more readable.

Install

$ npm install prop-d --save-dev

Usage

Require it and define a property on an object:

const prop = require('prop-d');
 
const o = Object.defineProperty({},'p',prop(5));
// o = {"p":5}

OK, so that's not so interesting, an object literal would be simpler. How about non-enumerable properties?

const o = Object.defineProperty({public:5},'_private',prop(42).hidden);
 
Object.keys(o).forEach(k=>console.log(k));
// only 'public' is listed

Or how about defining a load of properties of different kinds and using Object.create in a factory function.

const myProperties = {
  generalProperty: prop(),
  initialisedProp: prop(42),
  alwaysTrue: prop(true).constant,
  _private: prop().hidden,
  _arrayInstance: prop(()=>[]).hidden.constant,
  squareIt: prop(x=>x*x, true)
};
 
//the resultant descriptors can be used in an object factory 
function myObjectFactory(){
  return Object.create(null, myProperties);
}
 
var myNewObject = myObjectFactory();

API

prop ([value, [isMethod]])

returns a Prop object which has all the properties of a data descriptor with the following defaults:

property initial value
enumerable true
writable true
configurable false
value value

If the supplied value is not a function then it is assigned to the value property.

If the supplied value is a function and isMethod is false or missing, then the function will be used as a factory function for the descriptor value.

If the supplied value is a function and isMethod is true then the function is directly assigned as thedescriptor value.

example

const props={
  a:prop(5),
  b:prop({}),
  c:prop(function(){return {}}),
  d:prop(x=>x+1,true)
};

const o1 = Object.create(null, props);
const o2 = Object.create(null, props);

console.log(o1);
// { a: 5, b: {}, c: {}, d: [Function] }

//o1.b and o2.b are pointing at the SAME object
o1.b === o2.b; //true
o1.b.theSame=true;
console.log(o2);
//{ a: 5, b: { theSame: true }, c: {}, d: [Function] }

//o1.c and o2.c are pointing at their own instances
o1.c === o2.c; //false

//o1.d and o2.d are pointing at the same method
o1.d === o2.d; //true
o1.d(4);// returns 5;

Using an instance generating method can also allow things like auto-incrementing ids:

const prop = require('prop-d');

var counter=0;

const proto={
  get id(){return this._id}
}

const props={
  _id: prop(()=>counter++),
  foo: prop('foo')
}

function create(){
  return Object.create(proto,props);
}

//...

var o1=create();
//{id:0, foo:'foo'}
var o2=create();
//{id:1, foo:'foo'}

Methods of the prop object

There are six chainable properties of the object returned by prop() which modify the descriptor, two for each of the three boolean descriptor properties:

descriptor property property to set to true property to set to false
enumerable .visible .hidden
writable .variable .constant
configurable .thawed .frozen

For example:

console.log(prop('foo').hidden.constant)
// {enumerable: false, writable: false, configurable: false, value: 'foo'}

All prop methods make a new root object

If you are making a lot of constant or hidden variables, it can be tedius to write them out all the time (and not as DRY as we would like), so there is one other trick up prop's sleeve. Every prop object can act as a root method exacly as the prop object itself.

const privateProp = prop().hidden;
const fooProps = {
  _a: privateProp(5),
  _b: privateProp(()=>[]).constant
}

//or even
const privateArray = prop(()=>{}).hidden.constant;
const barProps = {
  _a1: privateArray,
  _a2: privateArray
}

This also means that you can use a variety of styles depending on taste. All of the following examples do the same thing:

const prop = require('prop-d');
var fooDescriptor = prop('foo').hidden.constant;
const prop = require('prop-d');
var fooDescriptor = prop.hidden.constant('foo');
const {hidden} = require('prop-d');
var fooDescriptor = hidden('foo').constant;
const {hidden:{constant:hc_prop}} = require('prop-d');
var fooDescriptor = hc_prop('foo');

Testing

run mocha tests

npm test

run mocha tests with nyc for coverage

npm run coverage

Contributing

In lieu of a coding style, please use the style of the existing code as an example.

Release History

  • 1.0.0
    • Initial release, all test passing
  • 1.0.1
    • Added coveralls, 100% coverage
  • 1.1.0
    • Made the chainable methods return new objects, no longer possible to accidentally modify a reference to a prop object - warning also removed from doc.
    • Removed some code that had become unessesary due to the above change.
    • Reduced the code size a little
    • Added a restriction on node version to package.json
  • 1.2.0
    • Removed much of the ES6 dependency and shimmed the last bit.
  • 1.3.0
    • Stopped messing with the prototype chain and just added the required methods and getters to the return function.
    • Removed the shim of setPrototypeOf
    • Now passing tests for node versions from 0.12 to 7 and iojs.
  • 1.3.1
    • Minor change to remove a little unnecessary complexity.
    • Added code climate to the list of badges

License

Copyright (c) 2017 Euan Smith

MIT License

Package Sidebar

Install

npm i prop-d

Weekly Downloads

4

Version

1.3.1

License

MIT

Last publish

Collaborators

  • zakalwe314