Passing metadata between functions - javascript

I created an API with Node.js, and I don't want the API to change nor do I want to add extra parameters to a function. However, the internal code in the library needs to now send some metadata between an internal API method and an external facing method.
Is there a way to pass (meta) data between functions somehow in JS that does not involve parameters/arguments?
TL;DR, it would be really useful to pass metadata between functions for the purposes of JS APIs, that should not change signatures.
(One trick is if the function is created everytime it is called, you can assign data onto the function object itself, but that is not true in this case (function is not being created everytime it is called).)
The trick I am currently using - and it is not a good one - there is an options {} object being used in the API. I am passing a hidden property in that objects object "__preParsed". The user will use that objects object as they normally would, behind the scenes I use it for some bookkeeping stuff that they don't need to know about.
Ok here is the code:
//public API
beforeEach.cb = function (desc, opts, fn) {
const _args = pragmatik.parse(arguments, rules.hookSignature);
_args[ 1 ].cb = true;
return beforeEach.apply(ctx, _args);
};
beforeEach = function (desc, opts, aBeforeEach) {
handleSetupComplete(zuite);
const _args = pragmatik.parse(arguments, rules.hookSignature);
const obj = { //have to do this until destructuring works
desc: _args[ 0 ],
opts: _args[ 1 ],
fn: _args[ 2 ]
};
handleBadOptionsForEachHook(obj.opts, zuite);
return 'there is more code but I omitted it';
};
as you can see the first method calls the second, or the second can be called directly, both are public APIs.
We need to parse the arguments in both calls, but as an optimization, we shouldn't have to parse them a second time if the second method was called by the first instead of directly.
The solution I will use for the moment is:
beforeEach.cb = function (desc, opts, fn) {
const _args = pragmatik.parse(arguments, rules.hookSignature);
_args[ 1 ].cb = true;
_args[ 1 ].__preParsed = true;
return beforeEach.apply(ctx, _args);
};
the opts options object is public, but the user won't know about the __preParsed property. The internal API will.
The problem with this is that the user can call the public API directly without an options object, and since the signature is very much varargs, then I really don't know until I have parsed it with my parse engine, which arg if any is the objects object!

You could abuse the this object to carry non-argument metadata in as follows by invoking your function using Function.prototype.call:
function inner (arg1, arg2) {
console.log('inner called with', arg1, arg2)
console.log('inner metadata', this._meta_count)
}
inner.call({_meta_count: 17}, 'ARG ONE', 'ARG TWO')
inner.call({_meta_count: 18}, 'ARG ONE B', 'ARG TWO B')

You could just add a new undocumented parameter to the end. JavaScript won't care and previous calls will still work, why is that a problem for you?
If you are checking parameter count and throwing errors, you could expect the hidden parameter to be an object with a magic property, if it's not, throw the error.
function go(a, b, c, _internal) {
if (_internal && ! _internal.hasOwnProperty('_magic')) {
throw new Error('invalid internal parameter passed');
}
}
You can get a little more paranoid and store the magic property as a Symbol, then the caller couldn't pass it by accident, they would have to be acting nefariously.
function go(a, b, c, _internal) {
if (_internal && !_internal.hasOwnProperty(go.internalParamProp)) {
throw new Error('invalid internal parameter passed');
}
console.log("Internal param", _internal && _internal[go.internalParamProp])
}
// Symbol for the magic property name to avoid accidental passing of internal param
go.internalParamProp = Symbol('');
// Passing the internal param
// Uses JS syntax that is not yet supported in some browsers
// If it's a concern, use or var obj={}; obj[go.internalParamProp] = 45
go(1, 2, 3, {
[go.internalParamProp]: 45
})
// Regular call
go(1, 2, 3)
// Invalid call
go(1, 2, 3, 4)

Related

How to create non-static methods/class that I can call off of multiple objects/contexts?

So I have a node.js module that I cannot modify that has non-static methods such as .set, .get, .remove, etc. I want to create non-static wrapper methods for these, but want to do it in a way where I can leave the object/context they're being called off of ambiguous.
For example, I currently use these methods like:
this.set(name, value, options);
and want to recreate a wrapper function where the this above may change.
I was thinking it should look something like:
export default function($) {
return {
set: function (name, value, options) {
$.set(name, value, options);
},
get: function (name) {
return $.get(name);
},
remove: function (name) {
$.remove(name);
}
};
};
Where the $ being passed in is the object/context the method is being called off of (such as but necessarily this), but that doesn't seem to work. Any ideas? Is this even possible?
EDIT: As I said in a comment below, I'm trying to default some options so I don't have to constantly specify certain options every time I call the method, and using the wrapper function to do so. I've omitted some code above from inside the wrapper function before the $.set(name, value, options) line is called to make my example more easily understandable since its not relevant to what my question is. Sorry for the confusion - I can see why the wrapper looks unnecessary given the example I gave.
EDIT 2: Here is the link to the original problem I'm trying to solve:
How to create a wrapper class for node.js plugin
EDIT 3: So I'm an idiot and was accidentally searching my console output for something, which is why it wasn't showing the error message I was receiving all along:
this.Vue.setCookie is not a function
Despite my IDE recognizing where the function was coming from, I'm guessing the setCookie, getCookie, etc. functions are limited to the scope of the function that they're all defined in.
Here's a version that, if I read the two questions correctly, should do what you want. Note that a dummy cookie implementation is included at the bottom.
The trouble is that it looks very much like the code that you supplied; I don't know why that wouldn't work.
// Creates a wrapper for a cookies object such as our `foo.bar.cookies`
const wrapCookies = (cookies, defaults) => ({
set: (name, value, options) =>
cookies.set(name, value, Object.assign({}, defaults, options || {})),
get: (name) => cookies.get(name),
remove: (name) => cookies.remove(name)
})
console.log('Test the original cookie implementation')
console.log('----------------------------------------')
foo.bar.cookies.set('c1', 'v1', {a: 1})
console.log('c1', foo.bar.cookies.get('c1'))
foo.bar.cookies.set('c2', 'v2', {a: 2})
foo.bar.cookies.remove('c1')
// Create wraper with given defaults
const myCookies = wrapCookies(foo.bar.cookies, {b: 10, c: 42})
console.log(' ')
console.log('Test the wrapper')
console.log('----------------------------------------')
myCookies.set('c3', 'v3', {a: 5}) // defaults `b` and `c`
console.log('c2', myCookies.get('c2')) // keeps original references
console.log('c3', myCookies.get('c3')) // handles new references
myCookies.set('c4', 'v4', {a: 7, b: 101}) // overrides `b`
<script>
// Dummy implementation for demonstration.
// Saves and logs on `set`, `remove`, just returns on `get`
const foo = {
bar: {
cookies: ((storage) => ({
set: (name, value, options) => {
console.log(`setting: "${name}" to "${value}" using ${JSON.stringify(options)})}`)
storage[name] = {value, options}
},
get: (name) => storage[name],
remove: (name) => {
console.log(`removing: "${name}"`)
delete storage[name]
}
}))({})
}
}
</script>
If the main question was just how to combine the defaults with your new object, then you probably want to read up on Object.assign.
It might also be instructive to look up Proxies.

How to include or detect the name of a new Object when it's created from a Constructor

I have a constructor that include a debug/log code and also a self destruct method
I tried to find info on internet about how to detect the new objects names in the process of creation, but the only recommendation that I found was pass the name as a property.
for example
var counter = {}
counter.a =new TimerFlex({debug: true, timerId:'counter.a'});
I found unnecessary to pass counter.a as a timerId:'counter.a' there should be a native way to detect the name from the Constructor or from the new object instance.
I am looking for something like ObjectProperties('name') that returns counter.a so I don't need to include it manually as a property.
Adding more info
#CertainPerformance What I need is to differentiate different objects running in parallel or nested, so I can see in the console.
counter.a data...
counter.b data...
counter.a data...
counter.c data... etc
also these objects have only a unique name, no reference as counter.a = counter.c
Another feature or TimerFlex is a method to self desruct
this.purgeCount = function(manualId) {
if (!this.timerId && manualId) {
this.timerId = manualId;
this.txtId = manualId;
}
if (this.timerId) {
clearTimeout(this.t);
this.timer_is_on = 0;
setTimeout ( ()=> { console.log(this.txtId + " Destructed" ) },500);
setTimeout ( this.timerId +".__proto__ = null", 1000);
setTimeout ( this.timerId +" = null",1100);
setTimeout ( "delete " + this.timerId, 1200);
} else {
if (this.debug) console.log("timerId is undefined, unable to purge automatically");
}
}
While I don't have a demo yet of this Constructor this is related to my previous question How to have the same Javascript Self Invoking Function Pattern running more that one time in paralel without overwriting values?
Objects don't have names - but constructors!
Javascript objects are memory references when accessed via a variables. The object is created in the memory and any number of variables can point to that address.
Look at the following example
var anObjectReference = new Object();
anObjectReference.name = 'My Object'
var anotherReference = anObjectReference;
console.log(anotherReference.name); //Expected output "My Object"
In this above scenario, it is illogical for the object to return anObjectReference or anotherReference when called the hypothetical method which would return the variable name.
Which one.... really?
In this context, if you want to condition the method execution based on the variable which accesses the object, have an argument passed to indicate the variable (or the scenario) to a method you call.
In JavaScript, you can access an object instance's properties through the same notation as a dictionary. For example: counter['a'].
If your intent is to use counter.a within your new TimerFlex instance, why not just pass counter?
counter.a = new TimerFlex({debug: true, timerId: counter});
// Somewhere within the logic of TimerFlex...
// var a = counter.a;
This is definitely possible but is a bit ugly for obvious reasons. Needless to say, you must try to avoid such code.
However, I think this can have some application in debugging. My solution makes use of the ability to get the line number for a code using Error object and then reading the source file to get the identifier.
let fs = require('fs');
class Foo {
constructor(bar, lineAndFile) {
this.bar = bar;
this.lineAndFile = lineAndFile;
}
toString() {
return `${this.bar} ${this.lineAndFile}`
}
}
let foo = new Foo(5, getLineAndFile());
console.log(foo.toString()); // 5 /Users/XXX/XXX/temp.js:11:22
readIdentifierFromFile(foo.lineAndFile); // let foo
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
function getLineAndFile() {
let err = getErrorObject();
let callerLine = err.stack.split("\n")[4];
let index = callerLine.indexOf("(");
return callerLine.slice(index+1, callerLine.length-1);
}
function readIdentifierFromFile(lineAndFile) {
let file = lineAndFile.split(':')[0];
let line = lineAndFile.split(':')[1];
fs.readFile(file, 'utf-8', (err, data) => {
if (err) throw err;
console.log(data.split('\n')[parseInt(line)-1].split('=')[0].trim());
})
}
If you want to store the variable name with the Object reference, you can read the file synchronously once and then parse it to get the identifier from the required line number whenever required.

JS-Interpreter - changing “this” context

JS-Interpreter is a somewhat well-known JavaScript Interpreter. It has security advantages in that it can completely isolate your code from document and allows you to detect attacks such as infinite loops and memory bombs. This allows you to run externally defined code safely.
I have an object, say o like this:
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
I'd like to be able to run the code in process through JS-Interpreter:
for (let i = 0; i < o.process.length; i++)
interpretWithinContext(o, o.process[i]);
Where interpretWithinContext will create an interpreter using the first argument as the context, i.e. o becomes this, and the second argument is the line of code to run. After running the above code, I would expect o to be:
{
hidden: false,
regex: /^[a-z]+$/i,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: '^[a-z]+$'
}
That is, hidden and regex are now set.
Does anyone know if this is possible in JS-Interpreter?
I’ve spent a while messing around with the JS-Interpreter now, trying to figure out from the source how to place an object into the interpreter’s scope that can be both read and modified.
Unfortunately, the way this library is built, all the useful internal things are minified so we cannot really utilize the internal things and just put an object inside. Attempts to add a proxy object also failed failed since the object just wasn’t used in a “normal” way.
So my original approach to this was to just fall back to providing simple utility functions to access the outside object. This is fully supported by the library and probably the safest way of interacting with it. It does require you to change the process code though, in order to use those functions. But as a benefit, it does provide a very clean interface to communicate with “the outside world”. You can find the solution for this in the following hidden snippet:
function createInterpreter (dataObj) {
function initialize (intp, scope) {
intp.setProperty(scope, 'get', intp.createNativeFunction(function (prop) {
return intp.nativeToPseudo(dataObj[prop]);
}), intp.READONLY_DESCRIPTOR);
intp.setProperty(scope, 'set', intp.createNativeFunction(function (prop, value) {
dataObj[prop] = intp.pseudoToNative(value);
}), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"set('hidden', !get('visible'));",
"set('regex', new RegExp(get('validate'), 'i'));"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
However, after posting above solution, I just couldn’t stop thinking about this, so I dug deeper. As I learned, the methods getProperty and setProperty are not just used to set up the initial sandbox scope, but also as the code is being interpreted. So we can use this to create a proxy-like behavior for our object.
My solution here is based on code I found in an issue comment about doing this by modifying the Interpreter type. Unfortunately, the code is written in CoffeeScript and also based on some older versions, so we cannot use it exactly as it is. There’s also still the problem of the internals being minified, which we’ll get to in a moment.
The overall idea is to introduce a “connected object” into the scope which we will handle as a special case inside the getProperty and setProperty to map to our actual object.
But for that, we need to overwrite those two methods which is a problem because they are minified and received different internal names. Fortunately, the end of the source contains the following:
// Preserve top-level API functions from being pruned/renamed by JS compilers.
// …
Interpreter.prototype['getProperty'] = Interpreter.prototype.getProperty;
Interpreter.prototype['setProperty'] = Interpreter.prototype.setProperty;
So even if a minifier mangles the names on the right, it won’t touch the ones on the left. So that’s how the author made particular functions available for public use. But we want to overwrite them, so we cannot just overwrite the friendly names, we also need to replace the minified copies! But since we have a way to access the functions, we can also search for any other copy of them with a mangled name.
So that’s what I’m doing in my solution at the beginning in patchInterpreter: Define the new methods we’ll overwrite the existing ones with. Then, look for all the names (mangled or not) that refer to those functions, and replace them all with the new definition.
In the end, after patching the Interpreter, we just need to add a connected object into the scope. We cannot use the name this since that’s already used, but we can just choose something else, for example o:
function patchInterpreter (Interpreter) {
const originalGetProperty = Interpreter.prototype.getProperty;
const originalSetProperty = Interpreter.prototype.setProperty;
function newGetProperty(obj, name) {
if (obj == null || !obj._connected) {
return originalGetProperty.call(this, obj, name);
}
const value = obj._connected[name];
if (typeof value === 'object') {
// if the value is an object itself, create another connected object
return this.createConnectedObject(value);
}
return value;
}
function newSetProperty(obj, name, value, opt_descriptor) {
if (obj == null || !obj._connected) {
return originalSetProperty.call(this, obj, name, value, opt_descriptor);
}
obj._connected[name] = this.pseudoToNative(value);
}
let getKeys = [];
let setKeys = [];
for (const key of Object.keys(Interpreter.prototype)) {
if (Interpreter.prototype[key] === originalGetProperty) {
getKeys.push(key);
}
if (Interpreter.prototype[key] === originalSetProperty) {
setKeys.push(key);
}
}
for (const key of getKeys) {
Interpreter.prototype[key] = newGetProperty;
}
for (const key of setKeys) {
Interpreter.prototype[key] = newSetProperty;
}
Interpreter.prototype.createConnectedObject = function (obj) {
const connectedObject = this.createObject(this.OBJECT);
connectedObject._connected = obj;
return connectedObject;
};
}
patchInterpreter(Interpreter);
// actual application code
function createInterpreter (dataObj) {
function initialize (intp, scope) {
// add a connected object for `dataObj`
intp.setProperty(scope, 'o', intp.createConnectedObject(dataObj), intp.READONLY_DESCRIPTOR);
}
return function (code) {
const interpreter = new Interpreter(code, initialize);
interpreter.run();
return interpreter.value;
};
}
let o = {
hidden: null,
regex: null,
process: [
"o.hidden = !o.visible;",
"o.regex = new RegExp(o.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
const interprete = createInterpreter(o);
for (const process of o.process) {
interprete(process);
}
console.log(o.hidden); // false
console.log(o.regex); // /^[a-z]+$/i
<script src="https://neil.fraser.name/software/JS-Interpreter/acorn_interpreter.js"></script>
And that’s it! Note that while that new implementation does already work with nested objects, it may not work with every type. So you should probably be careful what kind of objects you pass into the sandbox. It’s probably a good idea to create separate and explicitly safe objects with only basic or primitive types.
Have not tried JS-Interpreter. You can use new Function() and Function.prototype.call() to achieve requirement
let o = {
hidden: null,
regex: null,
process: [
"this.hidden = !this.visible;",
"this.regex = new RegExp(this.validate, 'i');"
],
visible: true,
validate: "^[a-z]+$"
};
for (let i = 0; i < o.process.length; i++)
console.log(new Function(`return ${o.process[i]}`).call(o));
Hi may be interpretWithinContext look like something like that ?
let interpretWithinContext = (function(o, p){
//in dunno for what you use p because all is on object o
o.hidden = (o.hidden === null) ? false : o.hidden;
o.regex = (o.regex === null) ? '/^[a-z]+$/i' : o.regex;
console.log(o);
return o;
});
https://codepen.io/anon/pen/oGwyra?editors=1111

Javascript Function Calls: Regular call vs Call vs Bind Call

My question is simple:
I'm passing a function to some other function to be call later (sample callback function), the question is when, why and what is the best practice to do it.
Sample:
I have the xxx() function, and I have to pass it, as I show you below in the window.onload event.
What is the best practice and why? There is any performance aspect or why should I choose to use call or bind to call this function
function xxx(text)
{
var div = document.createElement("div");
div.innerHTML = text + " - this: " + this.toString();
document.body.appendChild(div)
}
function callFunction(func)
{
func("callFunction");
}
function callUsingCall(func)
{
func.call(this, ["callUsingCall"]);
}
function callUsingBind(func)
{
func.call(this, ["callUsingCall"]);
}
window.onload = function(){
callFunction(xxx);
callUsingCall(xxx);
callUsingBind(xxx.bind(document));
}
Thank you,
Sebastian P.
I don't think there's any "best" practise.
You use call if the function you're calling cares what this is.
You use bind if you want to ensure that the function can only be called with the specified value of this.
[There's some overhead to both, i.e. at least one depth of function calls / scope]
Otherwise you just call the function.
Simples :)
The this object is the context of the function. It's like you make a machine that something for you, and the this object would be the place that the machine works in, like your house. You can move it as you like.
We have 4 ways setting this objects.
Calling the function that is not a method:
fn(someArguments)
This way the this object is set to null or probably the window object.
Calling the function as a method:
someObject.fn(someArguments)
In this case the this object will point to someObject and it's mutable.
Calling with call or apply methods of the function.
fn.call(anotherObject, someArguments)
someObject.call(anotherObject, someArguments)
someObject.apply(anotherObject, [someArguments])
In this case the this object will point to someObject here. You are forcing it to have another context, when calling it.
Binding a the function
var fn2 = fn.bind(anotherObject, someArguments)
This will create another function that is binded to that this object we gave it(anotherObject). No matter how you call it, the this object is going to be the same.
Use Cases
Now you can do some tricky stuff knowing this. The reason that why we have it here(I think it came first from C++) is that methods of an object need to access to their parent. The this object provides the access.
var coolObject = {
points : ['People are amazing'],
addPoint : function (p) { this.points.push(p) }
}
So if you do the following it won't work:
var addPoint = coolObject.addPoint;
addPoint('This will result in an error');
The error will be thrown because the this object is not our coolObject anymore and doesn't have the points property. So at times like this, you can something like this:
var addPoint = coolObject.addPoint;
addPoint.call({points : []}, 'This is pointless');
This is pointless, but the function will work, even the this object is not what its supposed to be.
var anotherCoolObject = {
points : ['Im a thief!'],
addPoint : coolObject.addPoint
}
anotherCoolObject.addPoint('THIS IS CALL STEALING');
Still the function will work if you call it like that, since the this object will point to anotherCoolObject which has the points property.
The most popular use case I've seen is slicing the arguments object:
function returnHalf() {
return [].slice.call(arguments, 0, arguments.length / 2);
}
returnHalf('Half', 'is', 'not', 'awesome');
// >> [Half', 'is']
So you see, arguments object is not an instanceof array. If we do arguments.slice(...) then you're gonna be killed by the compiler. But here we use the array's method on arguments object, since it's array like.
Sometimes you don't want your function context to be changed or you wanna add your own arguments, you use bind.
For example when you add a listener for an event with jquery, when jquery calls your function, the this object will be the element. But sometimes you wanna do tricky stuff and change it:
var myElement = {
init : function () {
$(this.element).click(this.listener.bind(this));
},
view : "<li>${Name}</li>",
name : 'ed',
element : $('#myelement'),
listener : function () {
this.element.append($.tmpl( this.view, this ));
}
}
myElement.init();
So here, you bind it to the myElement, so you can have access to the object properties to render the view. Another examples would be the following:
for (var i = 0; i < 10; i++) {
setTimeout(function () {console.log(i)}, 10)
}
// All of them will be 10.
for (var i = 0; i < 10; i++) {
setTimeout((function () {console.log(this.i)}).bind({ i : i }, 10)
}
If you have put an asynchronous function call in a loop, by the time the callback is called, the loop is finished, and the counter have reached the end, you can use bind to cleanly bind the current counter to your callback.
Another good use case of it, that I use a lot is when passing my functions with arguments to async module, without creating closures.
async.parallel({
writeFile : function (cb) {
fs.writeFile('lolz.txt', someData, cb);
},
writeFile2 : function (cb) {
fs.writeFile('lolz2.txt', someData, cb);
}
}, function (err){
console.log('finished')
});
async.parallel({
writeFile : fs.writeFile.bind(fs, 'lolz.txt', someData),
writeFile2 : fs.writeFile.bind(fs, 'lol2z.txt', someData),
}, function (err){
console.log('finished')
});
These two implementations are identical.
Performance
Just check these out:
http://jsperf.com/bind-vs-call2
http://jsperf.com/js-bind-vs-closure/2
http://jsperf.com/call-vs-closure-to-pass-scope/10
bind has a big performance overhead comparing to other types of calling, but make sure you don't sacrifice performance with maintainability with pre-mature optimizations.
Also you can have a look at this article.

jQuery/Javascript: How can I evaluate the validity of function arguments efficiently with a range of valid types?

I've got a rather large plugin that I am currently writing in jQuery which is using a lot of internal functions that can accept varying arguments depending on the function.
I caught myself constantly writing the following in every function to stop the code from running if an argument hasn't been supplied or isn't valid:
add : function(args) {
if (args===undefined) return;
// function code;
},...
I was hoping that in a DRY type of sense it would be a good idea to write a little internal helper function that would do this for me.
Is this actually a good idea and most importantly what is the best/secure way to check for a varied range of acceptable arguments?
There are a lot of functions with multiple arguments in this plugin, for example:
load : function( filename , path , excludeFromRandom , callback ) {}
where filename is a string,
path is a string,
excludeFromRandom is a boolean and
callback can be a function or a string.
What is a good way to check for the existence and validity of these types of arguments without rewriting the same code over and over?
Any suggestions and ideas would be great.
Thanks for reading.
It depends to what extent you want to do this. In idea would be to create a validation function which takes a argument -> rule mapping. E.g.:
function foo(somestring, somenumber) {
var rules = {
'somestring': Validator.rules.isString,
'somenumber': Validator.rules.inRange(5,10);
};
}
Validator would contain the basic logic and some helper functions (rules):
var Validator = {
valid: function(args, rules) {
for(var name in rules) {
if(!rules[name](args[name])) {
return false;
}
}
return true;
},
rules: {
isString: function(arg) {
return (typeof arg === 'string');
},
inRange: function(x,y) {
return function(arg) {
return !isNaN(+arg) && x <= arg && arg <= y;
}
}
}
}
This is just a sketch, it certainly can be extended (like accepting multiple rules per argument), but it should give you some idea.
That said, you don't have to check every argument. Provide decent documentation. If people use your plugin in a wrong way, i.e. passing wrong argument types, then your code will throw an error anyway.
Update:
If want to do this very often, then a good idea is to write a wrapper function and you just pass the function and the rules to it:
function ensure(func, rules, context) {
context = context || this;
return function() {
if(Validator.valid(arguments, rules)) {
return func.apply(context, arguments);
}
return null; // or throw error, whatever you want
}
}
Then you can define your function normally as:
var foo = function(somestring, somenumber) {
// ...
};
and just add validation to it:
var rules = {...};
foo = ensure(foo, rules);
You could even consider to make ensure accept a callback which gets called on error or success of the function, instead of returning a value. There are a lot of possibilities.

Categories

Resources