function defineMemoizedProperty( obj, prop, desc ) {
	if ( !isObject( obj ) ) {
		throw new TypeError( format( 'invalid argument. First argument must be an object. Value: `%s`.', obj ) );
	}
	if ( !isObject( desc ) ) {
		throw new TypeError( format( 'invalid argument. Property descriptor must be an object. Value: `%s`.', desc ) );
	}
	if ( !isFunction( desc.value ) ) {
		throw new TypeError( format( 'invalid argument. The `value` property of the property descriptor must be a function. Value: `%s`.', desc.value ) );
	}
	// Copy descriptor properties to a new data descriptor object:
	desc = {
		'configurable': ( desc.configurable === void 0 ) ? false : desc.configurable,
		'enumerable': ( desc.enumerable === void 0 ) ? false : desc.enumerable,
		'writable': ( desc.writable === void 0 ) ? false : desc.writable,
		'value': desc.value
	};

	// Define a configurable (at least temporarily) accessor property:
	defineProperty( obj, prop, {
		'configurable': true,
		'enumerable': desc.enumerable,
		'get': getter,
		'set': ( desc.writable ) ? memoize : void 0
	});

	/**
	* Temporary get accessor.
	*
	* @private
	* @returns {*} property value
	*/
	function getter() {
		var value = desc.value.call( obj );
		memoize( value );
		return value;
	}

	/**
	* Defines a memoized object property.
	*
	* @private
	* @param {*} value - value to set
	*/
	function memoize( value ) {
		desc.value = value;
		defineProperty( obj, prop, desc );
	}
}
Defines a memoized object property.

@param {Object} obj - object on which to define the property
@param {(string|symbol)} prop - property name
@param {Object} desc - property descriptor
@param {boolean} [desc.configurable=false] - boolean indicating if the property descriptor can be changed and if the property can be deleted from the provided object
@param {boolean} [desc.enumerable=false] - boolean indicating if the property shows up when enumerating object properties
@param {boolean} [desc.writable=false] - boolean indicating if the value associated with the property can be changed with an assignment operator
@param {Function} desc.value - function whose return value will be memoized
@throws {TypeError} first argument must be an object
@throws {TypeError} third argument must be an object
@throws {TypeError} property descriptor `value` property must be a function

@example
var obj = {};

function foo() {
    return 'bar';
}

defineMemoizedProperty( obj, 'foo', {
    'configurable': false,
    'enumerable': false,
    'writable': false,
    'value': foo
});

var v = obj.foo;
// returns 'bar'