moll / js-oolong

Object utility library for JavaScript. Simple, tasteful and plentiful. Supports inherited properties.
Other
8 stars 6 forks source link

Oolong.js

NPM version Build status

Oolong.js is a library for JavaScript full of object-related utilities. It's similar to Underscore.js, but it focuses strictly on functions dealing with objects. It's implementation emphasizes simplicity and good taste. For example, it always takes inherited properties into account leading to less surprises for users of your code.

Oolong.js grew out of my frustration with Underscore.js and Lodash.js and their inconsistent and sometimes outright ignorance of inherited properties. This leads to unnecessary complexity, arbitrary constraints and a leaky-implementation in your code or public APIs. This behavior is cancer propelled around by ignorance and misunderstandings between dictionaries and interfaces. Oolong.js is my first step at killing it.

Installing

npm install oolong

Oolong.js follows semantic versioning, so feel free to depend on its major version with something like >= 1.0.0 < 2 (a.k.a ^1.0.0).

API

For extended documentation on all functions, please see the Oolong.js API Documentation.

Oolong

Warning About __proto__

Some JavaScript runtimes, notably V8 (used by Chrome and Node.js) support a nonstandard (as of ECMAScript 5) property called __proto__. Assigning to the __proto__ property, even if done dynamically via obj[key] = {foo: 42} changes the object's prototype, rather than merely giving it a new property named __proto__. That also means if you've got an object with a plain __proto__ property (like when parsing JSON) and pass it to Oolong's assign, it could inadvertently overwrite the target's prototype:

var O = require("oolong")

function Person(name) {
  this.name = name
}

Person.prototype.greet = function() { return "Hi, " + this.name }

var john = new Person("John")
O.assign(john, JSON.parse("{\"__proto__\": {\"age\": 42}}"))
john.name // => "John"
john.age // => 42
john.greet // => undefined

In other situations, like when you're merging two objects recursively with merge, this could cause the global prototype (Object.prototype) to be modified.

As Oolong.js is written primarily for ECMAScript 5 compliant runtimes with no engine-specific workarounds, it doesn't have special handling for ignoring __proto__. Unfortunately, even if it did, the presence of such special properties is far too likely to cause issues elsewhere to make a difference. It's quite common to assign dynamic values to object keys, e.g. when indexing an array (by creating an object with keys as values). Fortunately, you can and should disable __proto__ globally by overwriting it on the global Object.prototype:

Object.defineProperty(Object.prototype, "__proto__", {
  value: undefined, configurable: true, writable: true
})

After overwriting __proto__ on Object.prototype, assigning, merging or cloning objects with __proto__ properties won't behave in any special manner. Assignments to __proto__ will become regular property assignments:

var john = new Person("John")
O.assign(john, JSON.parse("{\"__proto__\": {\"age\": 42}}"))

john.name // => "John"
john.age // => undefined
john.greet() // => "Hi, John"
john.__proto__ // => {age: 42}

License

Oolong.js is released under a Lesser GNU Affero General Public License, which in summary means:

For more convoluted language, see the LICENSE file.

About

Andri Möll typed this and the code.
Monday Calendar supported the engineering work.

If you find Oolong.js needs improving, please don't hesitate to type to me now at andri@dot.ee or create an issue online.