javascript get only asked params inside function as arguments - javascript

I know we can get all arguments in javascript inside function when it is called anywhere . we can get extra arguments which we didnt asked also .
But can we get only asked arguments on javascript function?
Like :
function a(a,b){
console.log(arguments);
}
if we call function a somewhere a(1,2,3,4,5)
then the output will be like [1,2,3,4,5]
but i want only [1,2] as i have expected only two params in function?
My condition is
index: (req, res, next) => {
var params = ['batch_id', 'section_id', 'subject_id', 'term', 'assesment_id', 'assesment_type'];
var _ = req._;
req.utils.requestValidation([req,res,next], params,'query')
// But i dont want to send params like above always instead like below
req.utils.requestValidation(arguments, params,'query')
and where it is called is
requestValidation: (data, options, param) => {
if (!options) return;
var _ = data[0]._ || data._;
var rules = {};
var data = {};
var sanity = {};
var elr = [validator.escape, validator.ltrim, validator.rtrim];
options.map((item, index) => {
rules[item] = 'required';
sanity[item] = elr;
});
data[param] = sanity;
if (typeof data != 'string') {
sanitizer.setOptions(data);
var data = sanitizer.sanitize(data[0], data[1], data[2],param);
return data[0].validation.validate(rules, data[0][param]);
}
return data.validation.validate(rules, data[param]);
},

if you need only two parameters just cut arguments to two items
if you want automatic this you can write function-wrapper, something like this:
function wrapperCutParams(func, paramsCount){
return function(){
var args = Array.prototype.slice(arguments, 0);
if(args.length > paramsCount){
args = args.slice(0, paramsCount)
}
func.apply(this, args)
}
}
Then
var a = function a(a,b){
console.log(arguments);
}
a = wrapperCutParams(a, 2)
Or just
a = wrapperCutParams(function a(a,b){
console.log(arguments);
}, 2)

Since you declared those arguments the most readable way would be to use them as they are, if you need to put them in an array, just do it.
myArgs = [a, b];

Write a higher-order function which takes the underlying function as a parameter, and returns a function which truncates the argument list to the number of arguments the function is asking for, based on its length property.
function slice_args(fn) {
return function() {
return fn.apply(this, Array.prototype.slice.call(arguments, 0, fn.length));
};
}
Then
function a(a,b){
console.log(arguments);
}
var b = slice_args(a);
b(1,2,3,4,5)
> [1, 2]

Related

.map() unable to access Object's this.function

Thanks in advance for any responses:
I don't think this is a duplicate: I reviewed that article in the first comment, that is just a general breakdown of objects and using "this" within javascript.
My other this.function's perform just fine, so I at least have the basics of JS Obj's figured out.
This issue is related to using .map() with a this.function within a constructed object.
The following Google Appscript code uses .map() to update a string in a 2d array. [[string, int],[string, int]]
For some reason, when using .map() it is am unable to access the function "this.removeLeadingZero". If that same function is placed outside of the OBJ it can be called and everything works just fine. For some reason the system claims row[0] is an [object, Object] but when I typeof(row[0]) it returns "string" as it should.
Error: TypeError: Cannot find function removeLeadingZero in object [object Object]. (line 106, file "DEEP UPC MATCH")
Is there any issue using this.function's with .map() inside an object or am I using an incorrect syntax?
function test2DMapping(){
var tool = new WorkingMappingExample()
var boot = tool.arrayBuild();
Logger.log(boot)
}
function WorkingMappingExample(){
this.arr= [["01234", 100],["401234", 101],["012340", 13],["01234", 0422141],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3],["01234", 1],["01234", 2],["12340",3]];
//mapping appears faster that normal iterations
this.arrayBuild = function(){
var newArray1 =
this.arr.map( function( row ) {
**var mUPC = removeLeadingZero2(row[0])** //working
**var mUPC = this.removeLeadingZero(row[0])** // not working
var index = row[1]
Logger.log(mUPC + " " + index)
row = [mUPC, index]
return row
} )
return newArray1;
};
}; //end of OBJ
//THE NEXT 2 FUNCTIONS ARE WORKING OUTSIDE OF THE OBJECT
function removeLeadingZero2(upc){
try {
if (typeof(upc[0]) == "string"){
return upc.replace(/^0+/, '')
} else {
var stringer = upc.toString();
return stringer.replace(/^0+/, '')
}
} catch (err) {
Logger.log(err);
return upc;
}
}
function trimFirstTwoLastOne (upc) {
try {
return upc.substring(2, upc.length - 1); //takes off the first 2 #'s off and the last 1 #'s
} catch (err) {
Logger.log(err);
return upc;
}
}
Inside the function that you pass to map, this doesn't refer to what you think it does. The mapping function has its own this, which refers to window, normally:
var newArray1 = this.arr.map(function(row) {
// this === window
var mUPC = this.removeLeadingZero(row[0]);
var index = row[1];
Logger.log(mUPC + " " + index);
return [mUPC, index];
});
You have four options:
Array#map takes a thisArg which you can use to tell map what the this object in the function should be:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}, this); // pass a thisArg
Manually bind the function:
var newArray1 = this.arr.map(function(row) {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
}.bind(this)); // bind the function to this
Store a reference to the outer this:
var self = this;
var newArray1 = this.arr.map(function(row) {
// self === (outer this)
var mUPC = self.removeLeadingZero(row[0]);
// ...
});
Use an arrow function:
var newArray1 = this.arr.map(row => {
// this === (outer this)
var mUPC = this.removeLeadingZero(row[0]);
// ...
});
Additionally, you could stop using this and new.
I have solved this issue and below is the answer in case anyone else runs into this:
this needs to be placed into a variable:
var _this = this;
and then you can call it within the object:
var mUPC = _this.removeLeadingZero(row[0])
Javascript scope strikes again!

How do I incorporate an options object as a parameter when I want to support an infinite amount of arguments?

I am accepting an infinite amount of arguments and looping through whatever the user provides. I would like to incorporate an options object into this module, but I am not sure how that would work. Would this code just see the options object as one of the normal params?
module.exports = function () {
var args = Array.prototype.slice.call(arguments);
var masterObject = [];
args.forEach(function (array) {
array.map(function (item) {
var found = false;
for (var i = 0; i < masterObject.length; i++) {
if (masterObject[i].word === item.word) {
masterObject[i].count += item.count;
found = true;
}
}
if (!found) {
masterObject.push(item);
}
});
});
return masterObject;
};
Well, you need to decide between
var mymodule = require('mymodule')(opts);
mymodule(1, 2, 3);
and
var mymodule = require('mymodule');
mymodule(1, 2, 3, opts);
or something else. The first one:
module.exports = function (opts) {
return function() {
var args = Array.prototype.slice.call(arguments);
// ...
};
};
The second one:
module.exports = function (opts) {
var args = Array.prototype.slice.call(arguments);
opts = args.pop();
// ...
};
I like Amadan's response to this problem, I just wanted to add a related note:
What I see more often than not: APIs that accept an infinite number of values, AND accept options, will use the combination of an array (to contain the n-length values) and an object to pass in the options.
This way you don't need any voodoo, and your API is super clean:
module.exports = function (array, opts) {
// parse your options
opts = opts || {};
// loop over array
array.forEach(item => {
// to infinity, and beyond!
});
}
If you want to go crazy, and can use ES6 Rest Parameters, but if you did that, the options parameter would have to be supplied first (and if the user didn't have any options to pass, they would have to use null or an empty object, which could be weird for some APIs, but it's a possible way to approach this problem):
module.exports = function (opts, ...args) {
// do something with your options
opts.foo = opts.foo || true;
// now loop through your infinite args
args.forEach(item => {
console.log(item);
});
}

Losing scope on recursive call

I'm creating a module that accepts a data set and an integer n and recursively fills that dataset with n products at a time, after the first call, the function loses its scope and errors out. Why, And what's the best practice for fixing this?
Code:
function ProductFactory(){
var bigArr = [0,1,2,3,4,5,6,7,8,9];
var smallArr = [1,2,3,4];
return {
getProductList: getProductList,
getAllProducts: getAllProducts
};
function getProductList(start, size){ return start < 5 ? bigArr : smallArr }
function getAllProducts(batchSizeRequested, dataSet) {
var startPage = dataSet.length / batchSizeRequested;
var productBatch = this.getProductList(startPage, batchSizeRequested);
dataSet = dataSet.concat(productBatch);
if (productBatch.length === batchSizeRequested)
getAllProducts(batchSizeRequested, dataSet);
}
}
var productGetter = new ProductFactory();
productGetter.getAllProducts(10, []);
1) First of all you shouldn't call getProductList using this, in this case you can just call it as it is, because getProductList is not a function that was assigned directly to this object. It is just a closure that uses local variables in it's code. If you want to call function using this, you should assign it using this, for example this.getProductList = function() {}
2) I don't think there are other scoping problems except redundant this, but I found another issue, though.
You are not actually return anything from your function, plus recursive call does not have an exit point.
Fixed code looks like this.
function ProductFactory(){
var bigArr = [0,1,2,3,4,5,6,7,8,9];
var smallArr = [1,2,3,4];
return {
getProductList: getProductList,
getAllProducts: getAllProducts
};
function getProductList(start, size){ return start < 5 ? bigArr : smallArr }
function getAllProducts(batchSizeRequested, dataSet) {
var startPage = dataSet.length / batchSizeRequested;
var productBatch = getProductList(startPage, batchSizeRequested);
dataSet = dataSet.concat(productBatch);
if (productBatch.length === batchSizeRequested) {
return getAllProducts(batchSizeRequested, dataSet);
} else {
return dataSet;
}
}
}
var productGetter = ProductFactory();
var products = productGetter.getAllProducts(10, []);
console.log(products)
The typical approach to a function call like this is to assign an external value to this (typically called self):
function ProductFactory(){
...
var self = this;
function getAllProducts(batchSizeRequested, dataSet) {
...
getAllProducts.apply(self, [batchSizeRequested, dataSet]);
}
}
In this case, however, please try to remember that you have defined a closure function getAllProducts that is only privately accessible internal to the constructor. Instead you should probably do:
function ProductFactory(){
...
var self = this;
this.getAllProducts = function(batchSizeRequested, dataSet) {
...
self.getAllProducts(batchSizeRequested, dataSet);
}
}

Ternary execution of functions

I'm working on a project that will do a lot of processing of numbers in arrays. To try and encapsulate some condition logic I've done something like
//ignore the fact that it's a bad idea to extend JS base types
Array.prototype.ifThenElse = function (statement, funcA, funcB, args) {
return (statement) ? funcA(args) : funcB(args);
};
So this takes a boolean expression and executes the funcA if the bool is true, and executes funcB if it is not. The kicker here is that args should be the array itself. So here's a fiddle and the code:
var newData = [1, 2, 3, 4];
Array.prototype.ifThenElse = function (statement, funcA, funcB, args) {
return (statement) ? funcA(args) : funcB(args);
};
function timesTwo(arr) {
return arr.map(function (val, ix) {
return val * 2;
});
};
function timesThree(arr) {
return arr.map(function (val, ix) {
return val * 3;
});
};
var nArray = newData.ifThenElse(newData[0] < newData[1],timesTwo,timesThree,newData);
//console.log('This is the nArray ' + nArray);
var expression = !!0 > 100;
var expression2 = !!100 > 0;
var dData = newData.ifThenElse(expression, timesThree, timesTwo, newData);
var eData = newData.ifThenElse(expression2, timesThree, timesTwo, newData);
console.log(dData);//2,4,6,8 <=expression is false, timesTwo called
console.log(eData);//3,6,9,12 <=expression is true, timesThree called
I don't want to hardcode the functions that can be passed to `ifThenElse, but I'd also looking to see if there's a clever solution to make this more LINQ-like and somehow have newData automatically passed as the last parameter of the method
The value of this in a method called from an object generally refers to the object on which it was called.
Because your Array.prototype method is called on an Array, the value of this in the method is a reference to the Array.
So just pass this to pass the Array.
return (statement) ? funcA(this) : funcB(this);

Resolve function pointer in $(document).ready(function(){}); by json string name

I have a json object retrieved from server in my $(document).ready(...); that has an string that I would like to resolve to a function also defined within $(document).ready(...); so, for example:
$(document).ready(function{
$.getJSON(/*blah*/,function(data){/*more blah*/});
function doAdd(left,right) {
return left+right;
}
function doSub(left,right) {
return left-right;
}
});
with json string:
{"doAdd":{"left":10,"right":20}}
One way I thought about was creating an associative array of the function before loading the json:
var assocArray=...;
assocArray['doAdd'] = doAdd;
assocArray['doSub'] = doSub;
Using eval or window[](); are no good as the function may not be called for some time, basically I want to link/resolve but not execute yet.
Change your JSON to
{method: "doAdd", parameters : {"left":10,"right":20}}
Then do
var method = eval(json.method);
// This doesn't call it. Just gets the pointer
Or (haven't tried this)
var method = this[json.method]
How about something like this?
$(function(){
// Function to be called at later date
var ressolvedFunc = null;
// Ajax call
$.getJSON(/*blah*/,function(data){
// Generate one function from another
ressolvedFunc = (function(data) {
var innerFunc;
var left = data.left;
var right = data.right;
// Detect action
for (action in data) {
if (action == "doAdd")
innerFunc = function() {
return left + right;
};
else
innerFunc = function() {
return left - right;
};
}
return innerFunc;
})(data);
});
});
The anonymous function returns fresh function, with the new values stored within the enclosure. This should allow you to call the function at later date with the data previously retrieved from the GET request.
Rich
try this:
var doX = (function() {
var
data = [],
getDo = function(action) {
for(var d in data) {
if (data[d][action]) {
return data[d];
}
}
return null;
};
return {
set: function(sdata) {
data.push(sdata);
},
doAdd: function() {
var add = getDo("doAdd");
if (!add)
return 0;
return add.doAdd.left + add.doAdd.right;
},
doSub: function() {
var sub = getDo("doSub");
if (!sub)
return 0;
return sub.doAdd.left + sub.doAdd.right;
}
};
})();
$(document).ready(function{
$.getJSON(/*blah*/,function(data){ doX.set(data); });
});

Categories