npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

define-utility

v2.0.2

Published

Improved syntax for defining special properties on objects.

Downloads

15

Readme

define Utility


Why?

  • You'd like to create special properties on Objects with a better syntax than Object.defineProperty
  • You're creating an API that you'd like to be more dummy proof.
  • You like dot notation.
  • Your project doesn't have enough dependencies.

Usage

Filthy es5 casual:

const define = require('define-utility');

es6 master race:

import define from 'define-utility'

Now that it's in your project, instead of doing this:

const obj = {}

Object.defineProperty(obj, 'foo', { value: 'bar' })
Object.defineProperty(obj, 'ace', { value: 'base' })

You can do this:

const obj = {}

define(obj)
  .property('foo', { value: 'bar'})
  .property('ace', { value: 'base'})

Since a property definition with just a value equates to a read-only, or constant property, you can also shorten it even further, to this:

const obj = {}

define(obj)
  .const('foo', 'bar')
  .const('ace', 'base')

Or you could define a writable property:

const obj = {}

define(obj)
  .let('mass', 1000)

obj.mass = 500

Also getters and setters:


const obj = {}

define(obj)
  .let('sqrMagnitude', 10)
  .get('magnitude', () => Math.sqrt(obj.magnitude))
  .set('throttle', m => m > obj.magnitude ? obj.magnitude : m < 0 ? 0 : m)

//or use .access to set both on the same property at once:

define(obj)
  .let('_mass', 1000)
  .access('mass',
    () => obj._mass,
    v => obj._mass = v > 0 ? v : 0)

You can use the access method to set backing fields:

  const obj = {}

  const PERCENT = Symbol('percent') //i like using symbols for backing fields

  define(obj)
    .access('percent', //first string or symbol is the fields
      () => `${this[PERCENT] || 0} %`, //first function is the getter          
      v => this[PERCENT] = v < 0 ? 0 : v > 100 ? 100 : v, //second function is the setter        
      PERCENT, //second string or symbol is the backing field
      50) //any value defined after will be used as the backing fields default value

  // Equivalent to
  define(obj)
    .access('percent',
      () => `${this[PERCENT] || 0} %`,
      v => this[PERCENT] = v < 0 ? 0 : v > 100 ? 100 : v
    )
    .let(PERCENT, 50)


Any of the shortcuts can be made enumerable or configurable:


  const obj = {}

  define(obj)
    .const('id', 0) // { value: 0}
    .enum.const('attribute', 'HEAT') // { value: 'HEAT', enumerable: true }
    .enum.let('celsius', 32 ) // { value: 32, writable: true, enumerable: true }
    .enum.get('fahrenheit', () => (obj.celsius * 9 + (32 * 5)) / 5) // { get: [Function], enumerable: true }
    .enum.config.const('name', 'Thermometer') // { value: 'name', enumerable: true, configurable: true }

  // you CAN also do
    .config.enum.let('place', 'Ocean') // { value: 'Ocean', writable: true, configurable: true, enumerable: true }

  // but that's the same as
  obj.place = 'Ocean'
  // so that would be silly

Class properties

define works great for classes:


const X = Symbol('x'), Y = Symbol('y')

class Vector {

  constructor(initialX = 0, initialY = 0) {

    define(this)
      .enum.access('x', X, () => this[X], v => this[X] = isFinite(v) ? v : this[X], initialX)
      .enum.access('y', Y, () => this[Y], v => this[Y] = isFinite(v) ? v : this[Y], initialY)
      .enum.get('magnitude', () => Math.sqrt(this.x ** 2, this.y ** 2))
      .enum.get('angle', () => Math.atan2(this.y, this.x) * 180 / Math.PI)

  }

  //why not use the standard getter syntax?
  //I generally always do, but the descriptor for a standard getter
  //is { get: [Function], set: undefined, enumerable: false, configurable: true }
  //so, if you'd like different modifiers than that, use define()
  get xPlusY() {
    return this.x + this.y
  }

  copy() {
    return new Vector(this.x, this.y)
  }

}

You can define accessors on the prototype of a class, as well, just make sure you use the function() {} expression, instead of the () => {} expression:

  class Person {
    constructor(first, last, age) {

      define(this)
        .const('first', first)
        .const('last', last)
        .enum .let('age', age)

    }
  }

  define(Person.prototype)
    //function(){} expression required here
    .get.enum('fullName', function() { return this.first + ' ' + this.last })

Special Considerations

Use the target property if you're defining a brand new object


const obj = define({})
  .enum.const('foo', 'bar')
  .target

console.log(obj.foo) // bar

If you don't provide an input, define will create a new Object that doesn't inherit from anything


const obj = define().target

// Equivalent to

const Obj = Object.create(null)

If you like the :: function.bind operator, define can be used with it.


  const one = {}

  one::define() // == define(one)

Define cannot be instanced.


new define() // throws error