What other options are there for passing and using arguments in a function using an object besides these two?
Option 1:
let timerClosure = function ({
period, // number
funStart, // function
funEnd, // function
funStartArguments = [],
funEndArguments = [],
warming = 0
}) {// something }
Option 2:
let timerClosure = function (timerConfigObj) {
let period = timerConfigObj.period; // number
let funStart = timerConfigObj.funStart;
let funEnd = timerConfigObj.funEnd;
let funStartArguments = timerConfigObj.funStartArguments || [];
let funEndArguments = timerConfigObj.funStartArguments || [];
let warming = timerConfigObj.warming || 0;
}
Those, or other ways of spinning them, are basically it. Well, those and using an array, but if you use an array you may as well use discrete parameters, you'll have the same issue with order being significant and the problems with that as you get to more than three parameters.
Another way to spin what you have:
let timerClosure = function (timerConfigObj) {
const {
period, // number
funStart, // function
funEnd, // function
funStartArguments = [],
funEndArguments = [],
warming = 0
} = timerConfigObj;
// ...
};
You've said "...and describing" in the title but not the text. If that part is important to you, you can describe these more completely by using JDDoc annotations, which many IDEs can read and present to you (even if you never actually run JSDoc) when you're using the function:
/**
* Does something nifty with timers and closures.
*
* #param {Object} options - Options for the nifty thing.
* #param {number} options.period - `period` description...
* #param {function} options.funStart - `funStart` description...
* #param {function} options.funEnd - `funEnd` description...
* #param {array} options.funStartArguments - `funStartArguments` description...
* #param {array} options.funEndArguments - `funEndArguments` description...
* #param {number} options.warning - `warning` description...
*/
let timerClosure = function ({
period, // number
funStart, // function
funEnd, // function
funStartArguments = [],
funEndArguments = [],
warming = 0
}) {
// ...
};
Similarly, if you create a TypeScript type/interface and document its properties, IDEs will show that to you as well.
/**
* Options for `timerClosure`
*/
interface TimerClosureOptions {
/**
* Period description...
*/
period: number;
funStart: function;
funEnd: function;
funStartArguments?: any[];
funEndArguments?: any[];
warming?: number;
}
/**
* Does something nifty with timers and closures.
*
* #param {TimerClosureOptions} options - Options for the nifty thing.
*/
let timerClosure = function ({
period,
funStart,
funEnd,
funStartArguments = [],
funEndArguments = [],
warming = 0
}: TimerClosureOptions) {
// ...
};
Related
I have a wrapper class like this (for a undo-redo system using command pattern):
class Command {
constructor(doFunction, undoFunction) {
this.doFunction = doFunction;
this.undoFunction = undoFunction;
}
do = (args) => { return this.doFunction(args) }
undo = (args) => { return this.undoFunction(args) }
}
How can I add JSDoc to the do and undo functions for then use the same #param types from provided this.doFunction and this.undoFunction, so when I use:
/** #param {number} n */
func1 = (n) => { return n+1 }
/** #param {number} n */
func2 = (n) => { return n-1 }
myCommand = new Command(func1, func2)
myCommand.do(...) // Here I want the intellisense to ask me for a `n` #param of type number
I appreciate the help.
You need to type the class, not the functions, because you pass the functions themselves as arguments in the constructor
I would do it like this
/**
* #typedef {function(arg: number): number} NumberFunc
*/
class Command {
/**
* #param {NumberFunc} doFunction
* #param {NumberFunc} undoFunction
*/
constructor(doFunction, undoFunction) {
this.doFunction = doFunction;
this.undoFunction = undoFunction;
}
/** #param {number} args */
do = (args) => { return this.doFunction(args) }
/** #param {number} args */
undo = (args) => { return this.undoFunction(args) }
}
/** #param {number} n */
func1 = (n) => { return n+1 }
/** #param {number} n */
func2 = (n) => { return n-1 }
/** #param {string} n */
func3 = (n) => { return n-1 }
const myCommand = new Command(func1, func2); // ok
const badCommand = new Command(func1, func3); // bad
const myCommand.do(1); // ok
const myCommand.do('1'); // bad
This is related to the leetcode - question here, which asks:
Implement the RandomizedSet class:
RandomizedSet() Initializes the RandomizedSet object.
bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise.
bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise.
int getRandom() Returns a random element from the current set of elements (it's guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.
You must implement the functions of the class such that each function works in average O(1) time complexity.
I am able to pass some of the test cases but it fails one of the test cases (where in some places, my program returns undefined). What is it that I am doing wrong here? I am unable to find my mistake.
var RandomizedSet = function() {
this.map = new Map();
this.vector = [];
};
/**
* #param {number} val
* #return {boolean}
*/
RandomizedSet.prototype.insert = function(val) {
if(this.map.has(val)) return false;
else {
let position = 0;
if(this.vector.length > 0)
position = this.vector.length-1;
this.map.set(val, position);
this.vector.push(val);
return true;
}
};
/**
* #param {number} val
* #return {boolean}
*/
RandomizedSet.prototype.remove = function(val) {
if(this.map.has(val)) {
const index = this.map.get(val);
const lastVal = this.vector[this.vector.length-1];
this.vector[index] = lastVal;
this.vector.pop();
this.map.delete(val);
return true;
}else {
return false;
}
};
/**
* #return {number}
*/
RandomizedSet.prototype.getRandom = function() {
const randIndex = Math.floor(Math.random() * this.vector.length);
return this.vector[randIndex];
};
/**
* Your RandomizedSet object will be instantiated and called as such:
* var obj = new RandomizedSet()
* var param_1 = obj.insert(val)
* var param_2 = obj.remove(val)
* var param_3 = obj.getRandom()
*/
When moving the last element into the place of the removed element, you forgot to update the moved element's index in the map:
RandomizedSet.prototype.remove = function(val) {
if(this.map.has(val)) {
const index = this.map.get(val);
const lastVal = this.vector[this.vector.length-1];
this.vector[index] = lastVal;
this.vector.pop();
this.map.set(lastVal, index); // ADDED
this.map.delete(val);
return true;
}else {
return false;
}
};
Be aware of the case index == this.vector.length-1; the order of operations shown above will handle this case correctly without additional code.
I'm attempting to create a revisable document, with the edits stored as fast-json-patched objects.
The rough outline is :
const jsonpatch = require('fast-json-patch');
/**
* Generate a doc, with all the state changes recorded as
* diffed objects.
* #param {object} docParams The parameters to generate the doc from
* #returns {object} the doc
*/
function generateDoc(docParams) {
const defaults = {
docnumber: 'TS99999',
edits: 1,
};
// create a complete set of properties to work from
const { docnumber, edits } = {
...defaults,
...docParams,
};
// basic docs setup
const doc = {
parameters: { docnumber, edits },
history: [],
state: { docnumber, notes: [] },
};
// update the doc 'edits' times
for (let edit = 0; edit < edits; edit++) {
// clone to preserve the current state
const currentState = JSON.parse(JSON.stringify(doc.state));
// add at least one note, up to every edit
const notesToAdd = Math.ceil(Math.random() * 5);
for (let i = 0; i < notesToAdd; i++) {
doc.state.notes.push('Note: ' + Math.ceil(Math.random() * 500));
}
doc.history.push(jsonpatch.compare(currentState, doc.state));
}
return doc;
}
/**
* Set the current doc state to the state at the spercifier point in time
* #param {object} doc The doc to update
* #param {integer} edit The point in time to use
* #returns {boolean} Was the doc set updated?
*/
function timetravel(doc, editPoint) {
if (
doc.parameters.currentedit === editPoint ||
editPoint > doc.parameters.edits ||
editPoint < 1
) {
return false; // don't travel too far into the future or past!
}
const patchesToApply = doc.history.slice(0, editPoint);
const patches = [].concat.apply([], patchesToApply);
let newDoc = {};
newDoc = jsonpatch.applyPatch(newDoc, patches).newDocument;
doc.state = newDoc;
doc.parameters.currentedit = editPoint;
return true;
}
// Testing....
const doc = generateDoc({
docnumber: 'TS99999',
edits: 5,
});
console.log(doc);
timetravel(doc, 2);
console.log(doc);
Clearly my understanding of what should be happening is wrong, as I get the following error...
/Users/dd/Code/patchtesting/node_modules/fast-json-patch/commonjs/core.js:14
obj[key] = this.value;
just at the jsonpatch.applyPatch line.
I've tried alternative approaches:
// seems to be one popular suggestion...
const patchesToApply = doc.history.slice(0, editPoint);
const patches = [].concat.apply([], patchesToApply);
doc.state = patches.reduce(jsonpatch.applyReducer, {});
doc.parameters.currentedit = editPoint;
or...
// Trying to see the effect of applying a single patch at a time...
patches.forEach(patch => {
console.log(patch);
newDoc = jsonpatch.applyPatch(newDoc, [patch]).newDocument;
console.log(newDoc);
});
The patches that are generated make sense, I just can't seem to apply them :-(
Sorry, it was a basic coding / fencepost-ish error:
...
// basic docs setup
const doc = {
parameters: { docnumber, edits },
history: [],
state: { docnumber, notes: [] },
};
// ADDED: need to record the initial state
doc.history.push(jsonpatch.compare({}, doc.state))
// update the doc 'edits' times
...
;
I am using JSDoc for parameter documentation.
It is clear how to document the parameter types for many_prompts, but what is the right way to document the function it returns?
/**
* #param {Number} - number of times to prompt
* #return {Function(prompt{Number})} - the returned function
*/
function many_prompts(count) {
return function(prompt) {
for(var i=0; i < count; i++) alert(prompt);
}
}
//Example of use:
var y =many_prompts(3);
y('Hello World');
This seems to be working for me.
/**
* #param {Number} count - number of times to prompt
* #return {function(): void} - the returned function
*/
manyPrompts(count) {
/**
* My inner function
*
* #param {object} prompt Some parameter
*/
const inner = function(prompt) {
for (let i=0; i < count; i++) {
alert(prompt);
};
};
return inner;
}
You can document the inner function and then reference it like so
/**
* #param {Number} - number of times to prompt
* #return {many_prompts~inner} - the returned function
*/
function many_prompts(count){
/**
* My inner function
*
* #param {object} prompt Some parameter
*/
var inner = function(prompt){
for(var i=0;i<count;i++) alert(prompt)
};
return inner;
}
The way I prefer:
/**
* #param {number} count - number of times to prompt
* #returns { (prompt:string) => void } - the returned function
*/
manyPrompts(count) {
/**
* My inner function
*
* #param {object} prompt Some parameter
*/
const inner = function(prompt) {
for (let i=0; i < count; i++) {
alert(prompt);
};
};
return inner;
}
This is my solution for this.
I'm not describing a return in the first function and also document the inner function, which results in getting the documentation from the inner function.
/**
* Function to create a Function with multiple prompt messages
* #function
* #param {Number} count - number of times to prompt
*/
function many_prompts(count) {
/**
* To prompt a value multiple times
* #function
* #param {String} prompt - parameter to prompt
* #return {Function} prompt the input parameter
*/
return function(prompt) {
for(var i=0; i < count; i++) alert(prompt);
}
}
//Example of use:
var y = many_prompts(3);
y('Hello World');
Which is then shown e.g. in vscode like this...
For the outer function:
For the inner function:
You can also add an additional description when assigning the function, to describe the difference
/**
* Function to prompt a value 3 times
* #function
* #param {Number} prompt - parameter to prompt
* #return {Function} prompt the input parameter
*/
const y = many_prompts(3);
y('Hello World');
The following code is my attempt at a fairly generic javascript hash code implementation. I'm planning to use this code in conjunction with a hash table implementation (e.g. jshashtable) that utilizes hashCode() if its defined for keys. I have attempted to adhere closely to java's hash code implementations for numbers, strings, and arrays.
Questions:
Are there any issues with this implementation regarding correctness
or performance?
Are there any pre-existing implementations for hash
codes that do the same (or roughly the same) thing?
Aside from
jshashtable, are there other hash table implementations that utilizes
hashCode() and equals() in the same way that I should also consider?
NOTE: I'm aware that the code below could leverage other libs like underscore and jquery but I'd prefer not to have any 3rd party deps for my implementation. This is not say that I'm not interested in hash code libs that themselves may depend on jquery, underscore, etc.
/**
* Computes a hash code for an object based on a given subset of its fields
* #param obj any type
* #param keys an array of strings representing some subset of the keys in obj or undefined
* #returns {Number} a java-like hash code for obj based on the hash codes of a subset of its fields
* specified in keys.
*/
function hashCode(obj, keys) {
if (!isDefined(keys)) return typeHashCode(obj);
var result = 1;
for (var k = 0; k < keys.length; k++) {
var key = keys[k];
if (isDefined(obj[key]))
result = multiplyBy31AndAdd(result, typeHashCode(obj[key]));
}
return result;
}
/**
* #param obj
* #returns {Number}
*/
function typeHashCode(obj) {
var result = 1;
if (isDefined(obj)) {
if (typeof obj === 'string')
result = multiplyBy31AndAdd(result, stringHashCode(obj));
else if (typeof obj === 'number' && isFinite(obj))
result = multiplyBy31AndAdd(result, numberHashCode(obj));
else if (typeof obj === 'object') {
if (nonEmptyObject(obj)) {
if (isDefined(obj[hashCode]))
result = multiplyBy31AndAdd(result, obj.hashCode());
else {
if (Array.isArray(obj))
result = multiplyBy31AndAdd(result, arrayHashCode(obj));
else {
//This is what jshashtable does. If there were an easy and agreed upon way
//of uniquely identifying objects in javascript, a better approach
//may be to use the object's id
result = multiplyBy31AndAdd(result, stringHashCode(obj.toString()));
}
}
}
}
}
return result;
}
/**
* Generates a hash code for a 64 bit floating point number, similar to java's hash
* code implementation. This does not handle NaN and Inf the same way as java.
* More info can be found at [1]
* [1] http://stackoverflow.com/questions/2003493/javascript-float-from-to-bits
* #param num a finite number as defined by isFinite()
* #returns {Number}
*/
function numberHashCode(num) {
var buf = new ArrayBuffer(8);
(new Float64Array(buf))[0] = num;
return (new Uint32Array(buf))[0] ^ (new Uint32Array(buf))[1];
}
/**
* Generates a hash code for a string, similar to java's hash code
* implementation. More info can be found at [1]
* [1] http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
* #returns {Number}
*/
function stringHashCode(str) {
var hash = 0;
if (str.length === 0) return hash;
for (var i = 0; i < str.length; i++) {
var character = str.charCodeAt(i);
hash = multiplyBy31AndAdd(hash, character);
}
return hash;
}
/**
* #param array
* #returns {Number} hash code for the array
*/
function arrayHashCode(array) {
var result = 1;
for (var i = 0; i < array.length; i++) {
result = multiplyBy31AndAdd(result, typeHashCode(obj));
}
return result;
}
/**
* Code taken from:
* http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
* #param currentValue a number
* #param toAdd a number
* #returns {Number} the 32 bit integer representation of 31 * currentValue + toAdd
*/
function multiplyBy31AndAdd(currentValue, toAdd) {
var rv = ((currentValue<<5)-currentValue)+toAdd;
return rv & rv; //Convert to 32 bit integer
}
function isDefined(obj) {
return !(obj === undefined || obj === null);
}
/**
* Taken from http://stackoverflow.com/questions/4994201/is-object-empty
* #param obj an object
* #returns {Boolean} obj is {}
*/
function nonEmptyObject(obj) {
return !(Object.keys(obj).length === 0);
}