main.js (3486B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2019 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var isObject = require( '@stdlib/assert/is-object' ); 24 var isFunction = require( '@stdlib/assert/is-function' ); 25 var defineProperty = require( './../../define-property' ); 26 27 28 // MAIN // 29 30 /** 31 * Defines a memoized object property. 32 * 33 * @param {Object} obj - object on which to define the property 34 * @param {(string|symbol)} prop - property name 35 * @param {Object} desc - property descriptor 36 * @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 37 * @param {boolean} [desc.enumerable=false] - boolean indicating if the property shows up when enumerating object properties 38 * @param {boolean} [desc.writable=false] - boolean indicating if the value associated with the property can be changed with an assignment operator 39 * @param {Function} desc.value - function whose return value will be memoized 40 * @throws {TypeError} first argument must be an object 41 * @throws {TypeError} third argument must be an object 42 * @throws {TypeError} property descriptor `value` property must be a function 43 * 44 * @example 45 * var obj = {}; 46 * 47 * function foo() { 48 * return 'bar'; 49 * } 50 * 51 * defineMemoizedProperty( obj, 'foo', { 52 * 'configurable': false, 53 * 'enumerable': false, 54 * 'writable': false, 55 * 'value': foo 56 * }); 57 * 58 * var v = obj.foo; 59 * // returns 'bar' 60 */ 61 function defineMemoizedProperty( obj, prop, desc ) { 62 if ( !isObject( obj ) ) { 63 throw new TypeError( 'invalid argument. First argument must be an object. Value: `' + obj + '`.' ); 64 } 65 if ( !isObject( desc ) ) { 66 throw new TypeError( 'invalid argument. Property descriptor must be an object. Value: `' + desc + '`.' ); 67 } 68 if ( !isFunction( desc.value ) ) { 69 throw new TypeError( 'invalid argument. The `value` property of the property descriptor must be a function. Value: `' + desc.value + '`.' ); 70 } 71 // Copy descriptor properties to a new data descriptor object: 72 desc = { 73 'configurable': ( desc.configurable === void 0 ) ? false : desc.configurable, 74 'enumerable': ( desc.enumerable === void 0 ) ? false : desc.enumerable, 75 'writable': ( desc.writable === void 0 ) ? false : desc.writable, 76 'value': desc.value 77 }; 78 79 // Define a configurable (at least temporarily) accessor property: 80 defineProperty( obj, prop, { 81 'configurable': true, 82 'enumerable': desc.enumerable, 83 'get': getter, 84 'set': ( desc.writable ) ? memoize : void 0 85 }); 86 87 /** 88 * Temporary get accessor. 89 * 90 * @private 91 * @returns {*} property value 92 */ 93 function getter() { 94 var value = desc.value.call( obj ); 95 memoize( value ); 96 return value; 97 } 98 99 /** 100 * Defines a memoized object property. 101 * 102 * @private 103 * @param {*} value - value to set 104 */ 105 function memoize( value ) { 106 desc.value = value; 107 defineProperty( obj, prop, desc ); 108 } 109 } 110 111 112 // EXPORTS // 113 114 module.exports = defineMemoizedProperty;