JavaScript Code Contract Libraries? - javascript

I am just starting up a new web application and I want to implement some form of contract'esque style validation in my JavaScript. I did some quick googling, and came across JsContact but the syntax isn't quite what I had in mind. Is anyone aware of other libraries?
I am thinking I want the syntax to be something like
String.prototype.padLeft = function(c, width) {
Verify.value(c).isRequired().isNotNull().isChar();
Verify.value(width).isRequired().isNotNull().isNumber().greaterThan(0);
...
Verify.value(result).isNotNull();
return result;
};
Although it won't take long to put together my own library that has the syntax/methods I want, if someone else has already done the work and it is close enough, it will save me some time. Thanks in advance.
UPDATE
I won't have time to work on this until this afternoon, so I will give it a few more hours to see if anyone has any recommendations. If not, I will post whatever I create up somewhere as an answer below for other people to reference if they desire.
I have also given a little more thought to the API that would make sense, and I am currently thinking something like (contrived examples):
function searchUser(firstName, middleInit, lastName) {
Verify.value(firstName).isString().matching(/\w+/); // Must have value
Verify.value(middleInit).whenNotNull().isChar(); // May be null, but not undefined
Verify.value(lastName).isString().withMinimumLengthOf(2); // Must have value
...
}
function syncTime(serverTime, now) {
Verify.value(serverTime).isDate(); // Must have value.
Verify.value(now).whenDefined().isDate(); // May be undefined, but not null.
}
My current thought is that tolerating NULL or UNDEFINED values is atypical (at least for me?), as such, rather than explicitly specifying that a value .isNotNull() you would actually disable the rule for .whenDefined() or .whenNotNull() as shown above. I may make .whenNotNull() not error on UNDEFINED, but I see NULL vs. UNDEFINED as an important distinction; we'll see... all other methods will be pretty typical... thoughts? comments?

Given that no one has recommended any existing libraries, or that I am crazy for thinking this is a good idea I went ahead and threw together a basic library. The code isn't fancy, but it does what I want, and it is reasonably fast to run (approx 40 chained checks per ms in IE).
I settled on a final syntax like:
function syncTime(serverTime, now) {
Verify.value(serverTime).always().isDate(); // Cannot be undefined or null.
Verify.value(now).whenDefined().isDate(); // Cannot be null, but must be date when defined.
//Code
}
function searchForUser(firstName, middleInit, lastName) {
Verify.value(firstName).always().isString().withMinimumLengthOf(2); // Cannot be undefined or null.
Verify.value(lastName).always().isString().withMinimumLengthOf(2); // Cannot be undefined or null.
Verify.value(middleInit).whenNotNull().isChar().between('A', 'Z'); // Cannot be undefined, but must be single char string when not null.
//Code
}
I opted for an explicit 'Must Have Value' via the .always() check, personally I found it nicer to read; but I could see some going another way.
Given that the source is more than I want to post in this answer, please head to this CodePlex Wiki Page if you are interested in the source. I guess it turned in to more of a fluent assertion library; but it does what I need.
Update
I updated the source on the linked CodePlex page above. Specifically, I restructed the Verify class to make use of a 'value context' rather than always building new Verifier objects; improved IE's performance greatly (never was an issue with FireFox or Chrome)... now handles about 100 chained checks per ms in IE.

I may suggest you the next code contracts library: dbc-code-contracts.
NPM: https://www.npmjs.com/package/dbc-code-contracts
GitLab repo (home): https://gitlab.com/o.oleg/orbios.dbc#README
CI-builds with the unit-tests: https://gitlab.com/o.oleg/orbios.dbc/-/jobs/
Sample code:
Dbc.Contract.throwException = true;
const domId = "my-div";
const div = document.createElement("div");
div.id . = domId;
document.body.appendChild(div);
const state = Dbc.Dom.removeById(domId);
Dbc.Contract.isTrue(state);
Dbc.Contract.isNull(document.getElementById(domId));
The following contracts are supported (2nd November, 2017):
isFunction
isObject
isSymbol
isBoolean
isTrue
isFalse
isString
isEmptyString
isNotEmptyString
areStringsEqual
isNumber
isNumberLess
isNumberBigger
areNumbersEqual
isValueNaN
isDefined
isUndefined
isNull
isArray
isEmptyArray
isNotEmptyArray
isObjectImmutable
isPromise
isPrototypeOf
Also, there are internal contract checks, inside the DOM methods from this library.

I also have thrown together my idea of type contracts, which does what I want. A little late, I think, but I'll recommend it nevertheless for people willing to look at it: https://github.com/lindem/FirstContract
It's a WIP, but I needed something like it.
function bmi (weight, height) {
return weight / height * height;
}
var c = require("firstcontract").c
/*
* contract applies to function taking two non-negative numbers,
* returning a negative number:
*/
, contract = c(["R+0", "R+0"], "R+0")
, cbmi = contract(bmi)
;
it was created so that I can add and remove it without changing the function monitored itself and provides just a clamp around the function. It's commonjs and on npm.

One more - https://www.npmjs.com/package/bycontract
It's a small library that expects JSDoc expressions (http://usejsdoc.org/) for a contract. A good chance for you are already familiar with the syntax.
Just see it in action:
// Simple test
byContract( true, "boolean" ); // ok
// Multiple Types
byContract( 100, "string|number|boolean" ); // ok
// Optional Parameters
function foo( bar, baz ) {
byContract( arguments, [ "number=", "string=" ] );
}
Here kinda real-world example:
/**
* #param {number|string} sum
* #param {Object.<string, string>} payload
* #param {function} cb
* #returns {HTMLElement}
*/
function foo( sum, payload, cb ) {
// Test if the contract is respected at entry point
byContract( arguments, [ "number|string", "Object.<string, string>", "function" ] );
// ..
var res = document.createElement( "div" );
// Test if the contract is respected at exit point
return byContract( res, HTMLElement );
}
// Test it
foo( 100, { foo: "foo" }, function(){}); // ok
foo( 100, { foo: 100 }, function(){}); // exception - ByContractError: Value of index 1 violates the contract `Object.<string, string>`

Related

Having an Object return something other than it's whole self in Javascript

A piece of code I'm working on at the moment would benefit, potentially more from a semantic point of view, from the ability to have a call to 'just an object' return something other than the whole object. This may sound confusing so I shall elaborate with code.
If I had an Object constructor 'rectangle' defined as:
function Rectangle(side1, side2) {
this.area = side1 * side2;
}
What I'd then like to be able to do is call an instance of that object and then get a return value for it like so:
var foo = new Rectangle(1, 2);
return foo;
As it stands the return value will be something like a key:value pair. However, what I want is the return value to be something like "Hi Dave". I have read through various documentations on the Internet and have failed to find anything suitable.
Whilst I'm aware I could assign a property name to the "Hi Dave" statement and call that instead; for my application that does not make semantic sense. I am also aware that 'this' is not a variable and thus I can't just assign to that.
Any help would be much appreciated.
EDIT: Made an adjustment over what I want returned to avoid confusion.
I think the closest you can come to this is to override the .prototype.valueOf and .prototype.toString methods. This doesn't give you exactly what you wanted, which is being able to get a different return value, but, it will give you the desired value when used with strings.
class StringRectangle {
constructor(val1, val2) {
this.area = val1 * val2;
this.__proto__.valueOf = () => 'My area is: ' + this.area;
this.__proto__.toString = () => 'My area is: ' + this.area;
}
}
const stringRect = new StringRectangle(2, 3);
// This is where the above fails for what you want
stringRect; // StringRectangle {area: 6}
// But, maybe these are good enough, since you're displaying strings?
// Uses valueOf
'My area is: ' + stringRect + '!'; // My area is: 6!
// Uses toString
`My area is: ${stringRect}!` // My area is: 6!
Looking further into your ideal solution, I don't think there is any way to do it cross browser, if at all. The value of references is stored at the machine level. Ex: what does console.log actually do? I have no idea without looking into the V8 code:
console.log(console.log); // function log() { [native code] }
It's that native code bit that's the limiting part here. If you want to delve into the native code, start here for the V8 console.log.
Thanks for the learning here; haven't delved this much into prototypes in a while.
You can define a static method on the class
class Rectangle {
constructor(side1, side2) {
this.area = side1 * side2;
}
static whoAmI() {return "I am a rectangle"}
}
var foo = new Rectangle(1, 2);
Rectangle.whoAmI();

Unexpected '.' from wrapped expression to chain

I have this method that is calculating a total, and part of it is giving a warning in JS Lint. We're trying to get cleaner JS Lint inspections at work, so I want to see if there's a rational way to get around this that I'm not thinking of.
calculateTotal = function() {
var hours = parseFloat($hours.val());
var rate = parserFloat($rate.val());
var total = '';
if (!isNaN(hours) && !isNaN(rate)) {
// This throws the error.
total = (rate * hours).toFixed(2);
}
$total.val(total);
}
I can avoid the message if I do the following:
total = rate * hours;
total = total.toFixed(2);
It's a little too verbose for me to just jump at it, but it may be the best bet.
I checked out this question, and considered doing Number(rate * hours).toFixed(2), but that's (marginally) less performant, plus it would be a bad precedent to start with all of the warnings about using String() as stated in response to the accepted answer there.
This could be moot if my above attempt is the best way to get JS Lint to stop complaining, but I would like to hear from other people.
TL;DR
JSLint is going to force you to move the toFixed() from behind of the parentheses. I'd suggest the least annoying place to move it is in the $total.val(total) assignment.
This lints as-is on JSLint.com:
/*jslint white:true, browser:true */
/*global $hours, $rate, $total */
var calculateTotal = function() {
"use strict";
var hours = parseFloat($hours.val());
var rate = parseFloat($rate.val());
var total;
if (!isNaN(hours) && !isNaN(rate)) {
// This throws the error.
total = rate * hours;
}
$total.val(total.toFixed(2)); // moved `toFixed` to here
};
A little longer...
I tried it against the most recent version of JSLint, and it's borking at left_check in JSLint's code, here:
function left_check(left, right) {
// Warn if the left is not one of these:
// e.b
// e[b]
// e()
// identifier
var id = left.id;
if (
!left.identifier &&
(
left.arity !== "binary" ||
(id !== "." && id !== "(" && id !== "[")
)
) {
warn("unexpected_a", right);
return false;
}
return true;
}
left is essentially (rate & hours) and right is . with toFixed the next token in this case.
As dangerous as it is to assume code function from comments, I think the comments tell us where JSLint is coming from -- It wants methods called only on objects, not on operations, including type coercions that often occur inside of them. It pretty much has to let you make "fluent" calls, where you chain methods, and the only valid things that can have method calls are...
an object: e
A property of an object: e.b
A property in a collection: e[key]
The return value of a function: e()
Just to double check, since your construction used to work in "old JSLint" (the last version before JSLint for ES6), I asked Douglas Crockford. He's pretty terse, but he did confirm JSLint is working as intended.
Sorry I can't be more help there. I think there are places where (someExpression).someMethod() is expedient, but understand where JSLint's coming from too. If you're going to have the potential for type coercion, coerce explicitly.
Interesting question; thanks for asking.

Programming optional ignorance

In Javascript what is the best way to handle scenarios when you have a set of arrays to perform tasks on sets of data and sometimes you do not want to include all of the arrays but instead a combination.
My arrays are labeled in this small snippet L,C,H,V,B,A,S and to put things into perspective the code is around 2500 lines like this. (I have removed code notes from this post)
if(C[0].length>0){
L=L[1].concat(+(MIN.apply(this,L[0])).toFixed(7));
C=C[1].concat(C[0][0]);
H=H[1].concat(+(MAX.apply(this,H[0])).toFixed(7));
V=V[1].concat((V[0].reduce(function(a,b){return a+b}))/(V[0].length));
B=B[1].concat((MAX.apply(this,B[0])-MIN.apply(this,B[0]))/2);
A=A[1].concat((MAX.apply(this,A[0])-MIN.apply(this,A[0]))/2);
D=D[1].concat((D[0].reduce(function(a,b){return a+b}))/(D[0].length));
S=S[1].concat((S[0].reduce(function(a,b){return a+b}))/(S[0].length));
}
It would seem counter-productive in this case to litter the code with tones of bool conditions asking on each loop or code section if an array was included in the task and even more silly to ask inside each loop iteration with say an inline condition as these would also slow down the processing and also make the code look like a maze or rabbit hole.
Is there a logical method / library to ignore instruction or skip if an option was set to false
All I have come up with so far is kind of pointless inline thing
var op=[0,1,1,0,0,0,0,0]; //options
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
op[0]&&[L[0]=1];
op[1]&&[C[0]=1,console.log('test, do more than one thing')];
op[2]&&[H[0]=1];
op[3]&&[V[0]=1];
op[4]&&[B[0]=1];
op[5]&&[A[0]=1];
op[6]&&[A[0]=1];
It works in that it sets only C[0] and H[0] to 1 as the options require, but it fails as it needs to ask seven questions per iteration of a loop as it may be done inside a loop. Rather than make seven versions of the the loop or code section, and rather than asking questions inside each loop is there another style / method?
I have also noticed that if I create an array then at some point make it equal to NaN rather than undefined or null the console does not complain
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
L=NaN;
L[0]=1;
//1
console.log(L); //NaN
L=undefined;
L[0]=1
//TypeError: Cannot set property '0' of undefined
L=null
L[0]=1
//TypeError: Cannot set property '0' of null
Am I getting warmer? I would assume that if I performed some math on L[0] when isNaN(L)===true that the math is being done but not stored so the line isn't being ignored really..
If I understand what you want I would do something like this.
var op = [...],
opchoice = {
//these can return nothing, no operation, or a new value.
'true': function(val){ /*operation do if true*/ },
'false': function(val){ /*operation do if false*/ },
//add more operations here.
//keys must be strings, or transformed into strings with operation method.
operation: function(val){
//make the boolean a string key.
return this[''+(val == 'something')](val);
}
};
var endop = [];//need this to prevent infinite recursion(loop).
var val;
while(val = op.shift()){
//a queue operation.
endop.push(opchoice.operation(val));
}
I'm sure this is not exactly what you want, but it's close to fulfilling the want of not having a ton of conditions every where.
Your other option is on every line do this.
A = isNaN(A) ? A.concat(...) : A;
Personally I prefer the other method.
It looks like you repeat many of the operations. These operations should be functions so at least you do not redefine the same function over and over again (it is also an optimization to do so).
function get_min(x)
{
return +(MIN.apply(this, a[0])).toFixed(7);
}
function get_max(x)
{
return +(MAX.apply(this, a[0])).toFixed(7);
}
function get_average(x)
{
return (x[0].reduce(function(a, b) {return a + b})) / (x[0].length);
}
function get_mean(x)
{
return (MAX.apply(this, x[0]) - MIN.apply(this, x[0])) / 2;
}
if(C[0].length > 0)
{
L = L[1].concat(get_min(L));
C = C[1].concat(C[0][0]);
H = H[1].concat(get_max(H));
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A);
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
You could also define an object with prototype functions, but it is not clear whether it would be useful (outside of putting those functions in a namespace).
In regard to the idea/concept of having a test, what you've found is probably the best way in JavaScript.
op[0] && S = S[1].concat(get_average(S));
And if you want to apply multiple operators when op[0] is true, use parenthesis and commas:
op[3] && (V = V[1].concat(get_average(V)),
B = B[1].concat(get_mean(B)),
A = A[1].concat(get_mean(A));
op[0] && (D = D[1].concat(get_average(D)),
S = S[1].concat(get_average(S)));
However, this is not any clearer, to a programmer, than an if() block as shown in your question. (Actually, many programmers may have to read it 2 or 3 times before getting it.)
Yet, there is another solution which is to use another function layer. In that last example, you would do something like this:
function VBA()
{
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A));
}
function DS()
{
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
op = [DS,null,null,VBA,null,null,...];
for(key in op)
{
// optional: if(op[key].hasOwnProperty(key)) ... -- verify that we defined that key
if(op[key])
{
op[key](); // call function
}
}
So in other words you have an array of functions and can use a for() loop to go through the various items and if defined, call the function.
All of that will very much depend on the number of combinations you have. You mentioned 2,500 lines of code, but the number of permutations may be such that writing it one way or the other will possibly not reduce the total number of lines, but it will make it easier to maintain because many lines are moved to much smaller code snippet making the overall program easier to understand.
P.S. To make it easier to read and debug later, I strongly suggest you put more spaces everywhere, as shown above. If you want to save space, use a compressor (minimizer), Google or Yahoo! both have one that do a really good job. No need to write your code pre-compressed.

Form handling and validation in pure JavaScript

My intention is to get your thoughts and criticism about the script below, as regards the algorithm's design, performance and cross-browser compatibility.
I have just started getting into JavaScript having missed out on its awesomeness for quite a while. My background and experience is in developing C/C++/PHP based RESTful backends.
In order to understand the language and the right way of using it, I decided to do something which I am sure has been done many times before. But learning to use a new language and paradigm often entails pain anyway.
This is my attempt to create a normal form processing and validation script/ function.
In order to reduce complexity and keep code simple/clean, I decided to use HTML5 Custom Data Attributes (data-*) to assign metadata for each element in the form:
Data-Required: True or False. If set to true, this parameter makes the form-field required and so it cannot be empty. A value set to false indicates that the field is optional. Default is false.>
Data-Type: Type of validation to be performed. Examples include 'email', 'password', 'numbers' or any other 'regexp'.
A fairy simple example of such a form would be:
<form action="postlistings" id="postlistings" enctype='multipart/form-data' method="post" class="postlistings">
<ul class="login-li">
<li>
<input class="title" name="title" type="title" id="title" data-required="true" data-type="title"></a>
</li>
<li>
<textarea name="body" id="elm1" class="elm1" name="elm1" data-type="body" data-required="true" >
</textarea>
</li>
<li>
<span class="nav-btn-question">Add Listing</span>
</li>
</ul>
</form>
Reminder: This is my first piece of JavaScript code.
The idea is to call Form while passing the form name to retrieve and validate all the field values in one loop for performance. The validation involves two steps as can be guessed from the Data-* attributes described above:
i. Check for required form fields.
In case the values fail to meet step 1 requirement, an error message from configuration is pulled for the specific form value. Thus, for all values that fail to meet this requirement, an array of error messages are collected and passed on to the View.
ii. Perform respective validations.
Validations are only performed if all the values passed step 1. Otherwise, they follow the same steps as indicated in 1 above.
function Form(){
var args = Array.prototype.slice.call(arguments),
formName = args[0],
callback = args.pop(),
userError = [{type: {}, param: {}}],
requiredDataParam = 'required',
typeDataParam = 'type',
form = document.forms[formName],
formLength = form.length || null,
formElement = {id: {}, name: {}, value: {}, required: {}, type: {}};
function getFormElements(){
var num = 0;
var emptyContent = false;
for (var i = 0; i < formLength; i += 1) {
var formField = form[i];
formElement.id[i] = inArray('id', formField) ? formField.id : null;
formElement.name[i] = inArray('name', formField) ? formField.name : null;
formElement.value[i] = inArray('value', formField) ? formField.value : null;
formElement.required[i] = getDataAttribute(formField, requiredDataParam);
formElement.type[i] = getDataAttribute(formField, typeDataParam);
if (formElement.required[i] === true){
if(!formElement.type[i]) {
error('Validation rule not defined!');
}
else if (!formElement.value[i]) {
userError[num++] = {'type': 'required', 'param': form[i]};
emptyContent = true;
}
}
if (emptyContent === false) {
// Perform validations only if no empty but required form values were found.
// This is so that we can collect all the empty
// inputs and their corresponding error messages.
}
}
if (userError) {
// Return empty form errors and their corresponding error messages.
}
return formElement;
};
// Removed the getFormParam function that was not used at all.
return {
getFormElements: getFormElements
}
};
Two outside functions that are used in the JS script above (from JQuery source):
var inArray = function(elem, array){
if (array.indexOf){
return array.indexOf(elem);
}
for (var i = 0, length = array.length; i < length; i++){
if (array[i] === elem){
return i;
}
}
return -1;
}
// This is a cross-platform way to retrieve HTML5 custom attributes.
// Source: JQuery
var getDataAttribute = function(elem, key, data) {
if (data === undefined && elem.nodeType === 1) {
data = elem.getAttribute("data-" + key);
if (typeof data === "string") {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
!CheckType.isNaN ? parseFloat(data) :
CheckType.rbrace.test(data) ? parseJSON(data) :
data;
}
else {
data = undefined;
}
}
return data;
}
An example of Config Error messages can be set as follows:
var errorMsgs = {
ERROR_email: "Please enter a valid email address.",
ERROR_password: "Your password must be at least 6 characters long. Please try another",
ERROR_user_exists: "The requested email address already exists. Please try again."
};
As I post this for your review, please ignore any styling conventions that I might not have followed. My intention is to get your expert reviews on anything I should be doing different or could do better concerning the code itself, and the algorithm.
Besides the styling conventions, all criticism and questions are welcome.
First I'd like to clear up a common misconception. Forgive me if you already understand this clearly; maybe it will be helpful for someone else.
Learning and using jQuery or a similar library does not preclude or conflict with learning the JavaScript language. jQuery is simply a DOM manipulation library which takes away many of the pain points of using the DOM. There's plenty of room to learn and use JavaScript, the language, even if you use a library to abstract away some of the DOM details.
In fact, I would argue that using the DOM directly is likely to teach bad JavaScript coding habits, because the DOM is very much not a "JavaScript-ish" API. It was designed to work identically in JavaScript and Java and potentially other languages, and so it completely fails to make good use of the features of the JavaScript language.
Of course as you said, you're using this as a learning exercise; I just don't want you to fall into the trap that I've seen many people fall into of thinking, "I don't want to learn jQuery, because I want to learn JavaScript instead!" That's a false dichotomy: you have to learn JavaScript in either case, and using jQuery for the DOM doesn't interfere with that at all.
Now some details...
While it's OK to quote property names in an object literal and when you reference the properties, it's customary - and more readable - not to quote them when they are valid JavaScript names. e.g. in your formElement object
formElement = { id: {}, name: {}, value: {}, required: {}, type: {} };
(there was a missing semicolon at the end there too)
and where you use the names you can do:
formElement.id[i] = ...
formElement.name[i] = ...
etc.
Don't run your loops backwards unless the program logic requires it. It doesn't make the code faster except possibly in the case of an extremely tight loop, and it makes it unclear whether you're just prematurely optimizing or actually need the backwards loop.
Speaking of optimization, that loop has several inArray() calls. Since each of those loops through an array, that could be more of a performance impact than the outer loop. I imagine these arrays are probably pretty short? So performance wouldn't matter at all anyway, but this is something to think about in cases where you have longer arrays and objects. In some cases you can use an object with property names and values for a faster lookup - but I didn't look closely enough at what you're doing to suggest anything.
In any case, you're using inArray() wrong! But not your fault, that is a ridiculously named function in jQuery. The name clearly suggests a boolean return value, but the function returns the zero-based array index or -1 if the value is not found. I strongly recommend renaming this function as indexOf() to match the native Array method, or arrayIndex(), or some such.
That same loop has form[i] repeated numerous times. You could do this at the top of the loop:
var field = form[i];
and then use field throughout, e.g. field.id instead of form[i].id. This is generally faster, if it matters (which it probably doesn't here), but more importantly it's easier to read.
Do not use strict boolean comparisons like if( foo === true ) and if( bar === false) unless you really need to - and those cases are rare. The code sends a signal to the reader that there is something going on that's different from the usual boolean test. The only time these particular tests should be used is when you have a variable that may contain a boolean value or may contain some other type of value, and you need to distinguish which is which.
A good example of a case where you should use tests like these is an optional parameter that defaults to true:
// Do stuff unless 'really' is explicitly set to false, e.g.
// stuff(1) will do stuff with 1, but stuff(1,false) won't.
function stuff( value, really ) {
if( really === false ) {
// don't do stuff
}
else {
// do stuff
}
}
That specific example doesn't make a lot of sense, but it should give you the idea.
Similarly, an === true test could be used in a case where need to distinguish an actual boolean true value from some other "truthy" value. Indeed, it looks like this line is a valid case for that:
if (formElement['required'][i] === true){
given that if (formElement['required'][i] comes from the getDataAttribute() function which may return a boolean or other type.
If you are just testing for truthiness, though - and this should be most of the time - simply use if( foo ) or if( ! foo ). Or similarly in a conditional expression: foo ? x : y or !foo ? x : y.
The above was a long-winded way of saying that you should change this:
if (empty_content === false) {
to:
if (!empty_content) {
Your getFormParam() function goes to some work to convert an undefined result to null. There is usually no reason to do this. I don't see any place where that function is called, so I can't advise specifically, but in general you'd be testing for truthiness on something like this, so null and undefined would both be treated as false. Or in cases where you do need to distinguish null/undefined from other values (say, an explicit false), you can easily do it with != null or == null. This is one case where the "looser" comparison performed by == and != is very useful: both null and undefined evaluate the same with these operators.
You asked to ignore coding style, but one little suggestion here: You have a mix of camelCaseNames and names_with_underscores. In JavaScript, camelCaseNames are more idiomatic for function and variable names, with PascalCaseNames for constructor functions. Of course feel free to use underscores where they make more sense, for example if you're writing code that works with database columns in that format you may want your variable names to match the column names.
Hope that helps! Keep up the good work.
Update for your new code
I'm having a bit of trouble following the logic in the code, and I think I know part of the reason. It's a combination of naming conventions and inside-out objects.
First, the name formElement is really confusing. When I see element in JavaScript, I think of either a DOM element (HTMLElement) or an array element. I'm not sure if this formElement represents one or the other or neither.
So I look at the code to figure out what it's doing, and I see it has id:{}, name:{}, ... properties, but the code later treats each of those as an Array and not an Object:
formElement.id[i] = ...
formElement.name[i] = ...
formElement.value[i] = ...
formElement.required[i] = ...
formElement.type[i] = ...
(where i is an integer index)
If that code is right, those should be arrays instead: id:[], name:[], ....
But this is a red flag. When you see yourself creating parallel arrays in JavaScript, you're probably doing it wrong. In most cases you're better off replacing the parallel arrays with a single array of objects. Each of the objects in that array represents a single slice through all your parallel arrays, with a property for each of the previous arrays.
So, this object (where I've made the correction from {} to [] to match its current use):
formElement = { id: [], name: [], value: [], required: [], type: [] };
should be:
formInfo = [];
and then where you have the code that goes:
formElement.id[i] = ...;
formElement.name[i] = ...;
formElement.value[i] = ...;
formElement.required[i] = ...;
formElement.type[i] = ...;
It should be:
var info = {
id: ...,
name: ...,
value: ...,
required: ...,
type: ...
};
formInfo.push( info );
and adjust the rest of the code to suit. For example:
formElement.required[i]
would be:
formInfo[i].required
or even simpler since it's in the same function:
info.required
And note: I'm not saying info and formInfo are great names :-) they are just placeholders so you can think of a better name. The main idea is to create an array of objects instead of a set of parallel arrays.
One last thing and then I'm out of time for now.
That getDataAttribute() function is a complicated little piece of work. You don't need it! It would be simpler would just call the underlying function directly where you need it:
var info = {
...
required: formField.getAttribute('data-required') === 'true',
type: formField.getAttribute('data-type')
};
This also gives you full control of how the attributes are interpreted - as in the === 'true' test above. (This gives you a proper boolean value, so when you test the value later you don't have to use === true on it.)
On a stylistic note, yes, I did hard code the two 'data-xxxx' names right there, and I think that's a better and more clear way to do it.. Don't let your C experience throw you off here. There's no advantage to defining a string "constant" in this particular case, unless it's something that you want to make configurable, which this isn't.
Also, even if you do make a string constant, there's a minor advantage to having the complete 'data-whatever' string instead of just 'whatever'. The reason is that when somebody reads your HTML code, they may see a string in it and search the JS code for that string. But when they search for data-whatever they won't find it if the data- prefix is automagically prepended in the JS code.
Oh, I forgot one last thing. This code:
function Form(){
var args = Array.prototype.slice.call(arguments),
formName = args[0],
callback = args.pop(),
is working way too hard! Just do this instead:
function Form( formName, callback ) {
(and keep the var for the remaining variable declarations of course)
I cannot add comments yet so here is a little tip. I would separate the getFormElements() into smaller private functions. And I would add the errorMsgs to the Form function.
But for a first script in JavaScript, it is very impressive. This is actually the real reason I respond. I think it deserves more upvotes, and I would be very interested in a JS ninja responding to this question.
Good luck!

javascript get function body

I have a function e.g.
var test = function () {alert(1);}
How can I get the body of this function?
I assume that the only way is to parse the result of test.toString() method, but is there any other way? If parsing is the only way, what will be the regex to get to body? (help with the regex is extremly needed, because I am not familiar with them)
IF(!!!) you can get the toString(), then you can simply take the substring from the first indexOf("{") to the lastIndexOf("}"). So, something like this "works" (as seen on ideone.com):
var test = function () {alert(1);}
var entire = test.toString(); // this part may fail!
var body = entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}"));
print(body); // "alert(1);"
2015 update
Upon revisiting the state of function decompilation, it can said that it's generally safe in certain well-considered use cases and enviroments (e.g: Node.js workers with user defined functions).
It should be put in the same bucket as eval, which is a powerful tool that has its place, but should only be used on rare occasions. Think twice, that's my only advice.
The conclusions from Kangax's new research:
It's still not standard
User-defined functions are generally looking sane
There are oddball engines (especially when it comes to source code
placement, whitespaces, comments, dead code)
There might be future oddball engines (particularly mobile or unusual
devices with conservative memory/power consumption)
Bound functions don't show their original source (but do preserve
identifier... sometimes)
You could run into non-standard extensions (like Mozilla's expression
closures)
ES6 is coming, and functions can now look very different than
they used to
Minifiers/preprocessors are not your friend
"function decompilation" — a process of getting
string representation of a Function object.
Function decompilation is generally
recommended against, as it is a
non-standard part of the language, and
as a result, leads to code being
non-interoperable and potentially
error-prone.
#kangax on comp.lang.javascript
Simplest Use-Case
If you just want to execute the body of the function (e.g. with eval or using the Worker API), you can simply add some code to circumvent all the pitfalls of extracting the body of the function (which, as mentioned by others, is a bad idea in general):
'(' + myFunction + ')()';
I am using this trick in this Worker-related JSFiddle.
Complete Function Serialization With Accurate Stacktrace
I also wrote a more complete library that can:
Serialize any kind of function to string
Be able to send that string representation anywhere else, execute it with any custom arguments, and be able to reproduce the original stacktrace
Check out my CodeBuilder code here.
Note that much of the code takes care of making sure that we get an accurate stacktrace, wherever we execute the serialized function at a later point in time.
This fiddle demonstrates a simplified version of that logic:
Use JSON.stringify to properly serialize the function (that comes in handy when, e.g., we want to make it part of a bigger serialization "data package").
We then wrap it in one eval to un-escape the "JSON-ish"-escaped string (JSON does not allow functions + code, so we must use eval), and then in another eval to get back the object we wanted.
We also use //# sourceMappingURL (or the old version //# sourceMappingURL) to show the right function name in the stacktrace.
You will find that the Stacktrace looks Ok, but it does not give you the correct row and column information relative to the file that we defined the serialized functions in, which is why my Codebuilder makes use of stacktracejs to fix that.
I use the CodeBuilder stuff in my (now slightly dated) RPC library where you can find some examples of how it is used:
serializeInlineFunction example
serializeFunction example
buildFunctionCall example
extending #polygenelubricants' answer:
using: .toString()
Testee:
var y = /* olo{lo} */
/* {alala} */function/* {ff} */ x/*{s}ls{
}ls*/(/*{*{*/)/* {ha-ha-ha} */
/*
it's a function
*/
{
return 'x';
// }
}
/*
*/
By indexOf and lastIndexOf:
function getFunctionBody(fn) {
function removeCommentsFromSource(str) {
return str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '$1');
}
var s = removeCommentsFromSource( fn.toString() );
return s.substring(s.indexOf('{')+1, s.lastIndexOf('}'));
};
getFunctionBody(y);
/*
"
return 'x'
"
*/
used: rm comments from js source
This code provides the body when using ES6 arrow functions like var testFn=(q)=>q+1;
function getFunctionBody(test){
var entire = test.toString(); // note: not safe-guarded; this part may fail like this!
return entire.substring((entire.indexOf("{")+1)||(entire.indexOf("=>")+2), entire.lastIndexOf("}")!==-1?entire.lastIndexOf("}"):entire.length);
}
//testing/showcase code
var tests = [
function () {alert(1);},
()=>{return 1;},
q=>q+1
];
for (var i=0;i<tests.length;i++){
console.log(tests[i],getFunctionBody(tests[i]));
}
I originally submitted this code as an edit to polygenelubricants accepted answer, but it was rejected as the changes were considered to be too drastic.
var fn1 = function() {};
var fn2 = function() { alert("lol!"); };
Function.prototype.empty = function() {
var x = this.toString().match(/\s*function\s*\w*\s*\(.*?\)\s*{\s*}\s*;?\s*/);
return x != null;
};
alert(fn1.empty()); // true
alert(fn2.empty()); // false
'
Solução proposta pelo Paulo Torres no grupo A.P.D.A. no facebook.
you can try this functiion:
function extractFunctionBody(fn) {
var reg = /function \((.*)\)[ ]?{(.*)}$/g;
var match = reg.exec(fn.toString().replace(/\n/g, ";"));
if (match){
return match[2];
} else {
return "";
}
}
Try this:
/\{(\s*?.*?)*?\}/g.exec(test.toString())[0]
test.toString() will hold your entire declaration.
/{(\s*?.?)?}/g will match everything between your braces

Categories

Resources