Can a function receive an object as an argument in javascript? - javascript

var currentbutton = {};
function setPreset(obj) {
try{
if(obj.name===name && obj.value===value){
//log.error("preset array's OID at position ["+index+"] is"+presets[index].name +" and the value stored is "+presets[index].value);
currentbutton.name=obj.name;
currentbutton.value=obj.value;
log.error("currentbutton name= "+currentbutton.name+ "currentbutton value= " + currentbutton.value );
}
else
log.error("adklafjklajkl");
}
catch(ie){
log.error("couldn't set preset");
}
presets.forEach(function(obj));
I know there must be mistakes in this code that I wrote, first of all, I was told that the function need to receive an object as an argument, which I have no idea how to pass it to the function. I tried google, but I did not find any relevant information on whether a function can receive an object as an argument.
presets is an array which contains objects which has two properties (called "name" and "value")
basically, the array Presets goes through its enumerated list of variables with forEach, and compare if the argument obj's name and value are identical or not to any of the objects stored inside the array, if they are identical, set the currentbutton's name and value to the one inside the argument obj. Then we will have other functions which will operate on currentbutton that i don't have to worry about.
I know it's not really clear because I am not even sure if that's what is wanted of me.

You don't quite understand how forEach works. The forEach method takes a function as its argument:
[1,2,3].forEach(function(item) {
alert(item);
});
That function passed into forEach is given an argument itself. Here, I've named it item. The forEach method repeatedly invokes the function and supplies a successive member of the array as the first argument each time it is invoked.
Now, instead of passing in a literal function, I can use a variable to hold my function:
var alertStuff = function(item) {
alert(item);
}
Then, I use that function (referring to it by variable name) in forEach:
[1,2,3].forEach(alertStuff);
// is the same as...
[1,2,3].forEach(function(item) {
alert(item);
});
Thus, you want to use presets.forEach(setPreset);.

Define a function which accepts a paramter
function myNewFunc(obj){
alert(obj.myFirstProp);
}
Define an object which we are going to pass as an argument to the above function
var myObject = {
myFirstProp: "testing"
};
Call the function and pass the object as an argument
myNewFunc(myObject);

Your brackets were screwed up and you invoked forEach wrong.
var presets = [
{name:'a', value:1},
{name:'b', value:2},
{name:'c', value:3},
];
var currentbutton = {};
function setPreset(obj) {
try{
if(obj.name===name && obj.value===value){
//log.error("preset array's OID at position ["+index+"] is"+presets[index].name +" and the value stored is "+presets[index].value);
currentbutton.name=obj.name;
currentbutton.value=obj.value;
log.error("currentbutton name= "+currentbutton.name+ "currentbutton value= " + currentbutton.value );
} else { // syntax error, opening { of else block was missing
log.error("adklafjklajkl");
}
} // syntax error, closing } of try block was missing
catch(ie){
log.error("couldn't set preset");
}
} // syntax error, closing } of function was missiong
presets.forEach(setPreset);

Related

array.filter by object property, argument is not defined

I am trying to write a filter function that takes 2 parameters:
id type and the actual id value. Using these IDs, I want to filter an array of objects.For example, here I am trying to get a new array that only includes the values with the name of 'Mike'.
object:
var sample = [
{ name: 'Mike'},
{ name: 'John'}
];
filter function:
function filterById(obj, parameter, id) {
return obj.parameter == id;
}
this:
console.log(sample.filter(filterById(name, 'Mike')));
returns name is not defined.
Do I need to pass in the actual array as well? Is it possible to pass parameters into filter functions at all?
You would need to pass the "parameter" as a string too, and use the square bracket notation, and for this all to work your filterById function would itself have to return a function which matches the function used by Array.prototype.filter:
var sample = [
{ name: 'Mike'},
{ name: 'John'}
];
function filterById(parameter, id) {
return function(obj){
return obj[parameter] == id;
}
}
console.log(sample.filter(filterById('name', 'Mike')));
You don't have to invoke the function by yourself – it is a high-order function, so you have to provide only function. And here we come to the problem – you want to pass arguments there, but you can't!
So, there are few approaches. The first one is just to return another function, which will keep data in closure:
function filterById(parameter, id) {
return function(item) {
return item[parameter] == id;
}
}
The second option is to create another function via .bind, which is close to the idea of partial application. It will create new function with pre-defined parameters. They are always first, so you have to move actual item definition to the last position:
function filterById(parameter, id, item) {
return item[parameter] === id;
}
// we can create function for the future reference:
const filterByMike = filterById.bind(null, 'name', 'Mike');
sample.filter(filterByMike);
It's hard to say what is better, but I'd personally prefer the second approach.

strange Javascript notation - calling a function

I am trying to use some code from this tutorial and it contains some strange javascript notation that I am not familiar with chart.attr = function(name, value) {... . More than it being unfamiliar to me, it is throwing errors. I am trying to figure out how it can be changes to work in pure javascript.
function LineChart(config) {
function chart() {
// Draw the line.
chartContainer.append("path")
.datum(p.data)
.attr("class", "line")
.attr("d", line);
}
// **** This is the notation I do not understand, and gives me errors ****
chart.attr = function(name, value) {
if (arguments.length == 1)
{
return p[name];
}
else if (arguments.length == 2)
{
p[name] = value;
}
return chart;
}
chart.update = function() {
}
return chart;
}
Your code is trying to use a variable p which is undefined. It should be defined in the LineChart function as:
function LineChart(config) {
var p =
{
parent : null,
labels : [ "X", "Y" ],
...
};
...
}
As for the notation that you don't understand, this is an anonymous function expression which is being assigned to the chart.attr property. Even though it can be called by chart.attr(), this is still an anonymous function because it doesn't have a name.
The purpose of this particular function is to be a getter and setter for properties of the p object. It looks at the arguments to determine the way the function should behave: if there is only one argument, then it needs to return the property value, if there are two arguments then it should set the property value.
Example usage would look like:
var c = new LineChart();
var parent = c.attr('parent'); // get the value of the parent property
c.attr('parent', $('#something')); // set the value of the parent property
Let's dissect that line of code:
//Define chart.attr as a function that by default takes 2 parameters;
chart.attr = function(name, value) {
//If the function only gets 1 argument (so the first one)
if (arguments.length == 1)
{
//return the element with key "name" from the array p
//effectively a getter
return p[name];
}
// else, check if there are 2 arguments, but no more
else if (arguments.length == 2)
{
Assign the value of "value" to the element with key "name" from p
effectively a setter;
p[name] = value;
}
//at the end, return the chart
return chart;
}
So what this piece of code does is that if you pass only 1 argument to chart.attr(), it retrieves the value associated with that key from the array p. If you pass 2 arguments, it uses the second argument as the value of the key-valuepair from the array p with the first argument as the key.
now, without knowing the error you get, it's hard to debug this. However, the only way in which this would give an error is if p is undefined. if p doesn't contain that key, it returns null if it's a getter, and creates if it's a setter.
There is another way for this code to fail. And since the op didn't provide the error I will just speculate.
This can fail if you call, for example, chart.attr('somekey','somevalue') before chart.attr = function(name,value) { } is executed. This happens because of function hoisting...you are assigning a value to a property in this line of code. You're not defining a function...you're assigning one.
If you call chart.attr('somekey','somevalue') in the above conditions, you'll get a chart.attr is not a function error.

in jaydata: pass variables to filter, only global works

I have this function:
function db_borrarServer(idABorrar){
serversDB.servidores
.filter(function(elementoEncontrado) {
return elementoEncontrado.id_local == this.idABorrar;
})
.forEach(function(elementoEncontrado){
console.log('Starting to remove ' + elementoEncontrado.nombre);
serversDB.servidores.remove(elementoEncontrado);
serversDB.saveChanges();
});
}
does not work, but it does if I replace the variable "this.idABorrar" with a number, it does
return elementoEncontrado.id_local == 3;
or if I declare idABorrar as a global, works to.
I need to pass idABorrar as variable. How can I do this?
The EntitySet filter() function (as any other predicate functions) are not real closure blocks, rather an expression tree written as a function. To resolve variables in this scope you can only rely on the Global and the this which represents the param context. This follows HTML5 Array.filter syntax. To access closure variables you need to pass them via the param. Some examples
inside an event handler, the longest syntax is:
$('#myelement').click(function() {
var element = this;
context.set.filter(function(it) { return it.id_local == this.id; },
{ id: element.id});
});
you can also however omit the this to reference the params as of JayData 1.2 and also use string predicates
$('#myelement').click(function() {
var element = this;
context.set.filter("it.id_local == id", { id: element.id});
});
Note that in the string syntax the use of it to denote the lambda argument is mandatory.
In JayData 1.3 we will have an even simplex calling syntax
$('#myelement').click(function() {
var element = this;
context.set.filter("it.id_local", "==", element.id);
});
In the filter you should pass an object which is the this object, like this:
.filter(function(){},{idABorrar: foo})
foo can be const or any variable which is in scope.
The .filter() function takes an optional 2nd parameter which is assigned to this inside of the first parameter function.
So you can modify your code like so :
function db_borrarServer(idABorrar){
serversDB.servidores
.filter(function(elementoEncontrado) {
return elementoEncontrado.id_local == this;
}, idABorrar)
.forEach(function(elementoEncontrado){
console.log('Starting to remove ' + elementoEncontrado.nombre);
serversDB.servidores.remove(elementoEncontrado);
serversDB.saveChanges();
});
}
Let me know how you go - I'm very new to jaydata too and I've also been going a bit crazy trying to get my head into this paradigm.
But I came across your question trying to solve the same issue, and this is how I resolved it for me.

Having a closure issue. Can't seem to resolve it. Please advise

I have this code:
_trackit: function(){
for(var key in this.items.sublinks){
switch(key){
case 'shoes':
for(var innerkey in this.items.sublinks[key]){
(function(){
$(innerkey).observe('click', (function(e){
Event.stop(e);
someClass.click_link( this.items.sublinks[key][innerkey],false)
}));
)(this);
}
break;
}
}
}
The hash I am passing in has a size of 2. But as you would guess both of the links (since the hash maps to links), are passing the last hash value to come through (someClass.click_link <- in here this value, this.item.sublinks[key][innerkey]).
I've tried using an innerfuction etc... but something is messing up. If I go to "inner function deep", then this.items returns undefined.
Any help?
Since you're passing this in as an argument, you just need to create a parameter for it — call it, say, _this — and then you can refer to _this instead of this inside the function:
(function(_this, innerkey){
$(innerkey).observe('click', (function(e){
Event.stop(e);
someClass.click_link( _this.items.sublinks[key][innerkey],false)
}));
)(this, innerkey);
(There are other ways as well, but the above seems to be the way you were going for when you passed this in as an argument? And it's a perfectly respectable way to do it.)
Edited to add: Per Rob W's comment, I've edited the above to add innerkey as a parameter as well, since otherwise the inner function(e){...} expression will refer to the same innerkey variable as the outer function — a variable which, as a loop variable, is likely to have changed by the time the inner function actually runs. Passing it as a parameter gives the inner expression a new innerkey variable that's equal to what innerkey was when the inner function was created.
As others mentioned, you need to have an argument to receive the "this" you are passing. You will also need to pass copies of the "key" and "innerkey" variables, in order to avoid the closures inside for loops bug.
var make_event_listener = function(that, key, innerKey){
return function(e){
Event.stop(e);
someClass.click_link( that.items.sublinks[key][innerkey], false)
};
};
//...
for(var innerkey in this.items.sublinks[key]){
$(innerkey).observe('click', make_event_listener(this, key, innerKey) );
}
//...
OF course, you can use an anonymous version of make_event_listener instead but I find this way more readable.
The second call to "this" references the actual element being clicked. Change it to:
_trackit: function () {
var self = this;
for (var key in this.items.sublinks) {
switch (key) {
case 'shoes':
for (var innerkey in this.items.sublinks[key]) {
(function () {
$(innerkey).observe('click', (function (e) {
Event.stop(e);
someClass.click_link(self.items.sublinks[key][innerkey], false)
}));)(this);
}
break;
}
}
}
}

How do I pass an extra parameter to the callback function in Javascript .filter() method?

I want to compare each string in an Array with a given string. My current implementation is:
function startsWith(element) {
return element.indexOf(wordToCompare) === 0;
}
addressBook.filter(startsWith);
This simple function works, but only because right now wordToCompare is being set as a global variable, but of course I want to avoid this and pass it as a parameter. My problem is that I am not sure how to define startsWith() so it accepts one extra parameter, because I dont really understand how the default parameters it takes are passed. I've tried all the different ways I can think of and none of them work.
If you could also explain how the passed parameters to 'built in' callback functions (sorry, I dont know of a better term for these) work that would be great
Make startsWith accept the word to compare against and return a function which will then be used as filter/callback function:
function startsWith(wordToCompare) {
return function(element) {
return element.indexOf(wordToCompare) === 0;
}
}
addressBook.filter(startsWith(wordToCompare));
Another option would be to use Function.prototype.bind [MDN] (only available in browser supporting ECMAScript 5, follow a link for a shim for older browsers) and "fix" the first argument:
function startsWith(wordToCompare, element) {
return element.indexOf(wordToCompare) === 0;
}
addressBook.filter(startsWith.bind(this, wordToCompare));
I dont really understand how the default parameters it takes are passed
There is nothing special about it. At some point, filter just calls the callback and passes the current element of the array. So it's a function calling another function, in this case the callback you pass as argument.
Here is an example of a similar function:
function filter(array, callback) {
var result = [];
for(var i = 0, l = array.length; i < l; i++) {
if(callback(array[i])) { // here callback is called with the current element
result.push(array[i]);
}
}
return result;
}
The second parameter of filter will set this inside of the callback.
arr.filter(callback[, thisArg])
So you could do something like:
function startsWith(element) {
return element.indexOf(this) === 0;
}
addressBook.filter(startsWith, wordToCompare);
For those looking for an ES6 alternative using arrow functions, you can do the following.
let startsWith = wordToCompare => (element, index, array) => {
return element.indexOf(wordToCompare) === 0;
}
// where word would be your argument
let result = addressBook.filter(startsWith("word"));
Updated version using includes:
const startsWith = wordToCompare => (element, index, array) => {
return element.includes(wordToCompare);
}
function startsWith(element, wordToCompare) {
return element.indexOf(wordToCompare) === 0;
}
// ...
var word = "SOMETHING";
addressBook.filter(function(element){
return startsWith(element, word);
});
You can use the arrow function inside a filter, like this:
result = addressBook.filter(element => element.indexOf(wordToCompare) === 0);
Arrow functions on MDN
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous. These function expressions are best suited for non-method functions and they can not be used as constructors.
For anyone wondering why their fat arrow function is ignoring [, thisArg], e.g. why
["DOG", "CAT", "DOG"].filter(animal => animal === this, "DOG")
returns []
it's because this inside those arrow functions are bound when the function is created and are set to the value of this in the broader encompassing scope, so the thisArg argument is ignored. I got around this pretty easily by declaring a new variable in a parent scope:
let bestPet = "DOG";
["DOG", "CAT", "DOG"].filter(animal => animal === bestPet);
=> ["DOG", "DOG"]
Here is a link to some more reading:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this
based on oddRaven answer
and
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
i did it 2 different way .
1) using function way .
2) using inline way .
//Here is sample codes :
var templateList = [
{ name: "name1", index: 1, dimension: 1 } ,
{ name: "name2", index: 2, dimension: 1 } ,
{ name: "name3", index: 3, dimension: 2 } ];
//Method 1) using function :
function getDimension1(obj) {
if (obj.dimension === 1) // This is hardcoded .
return true;
else return false;
}
var tl = templateList.filter(getDimension1); // it will return 2 results. 1st and 2nd objects.
console.log(tl) ;
//Method 2) using inline way
var tl3 = templateList.filter(element => element.index === 1 || element.dimension === 2 );
// it will return 1st and 3rd objects
console.log(tl3) ;
There is an easy way to use the filter function, access all params, and not over complicate it.
Unless the callback's thisArg is set to another scope filter does not create its own scope, and we can access params within the current scope. We can set 'this' to define a different scope in order to access other values if needed, but by default it is set to the scope it's called from. You can see this being used for Angular scopes in this stack.
Using indexOf is defeating the purpose of filter, and adding more overhead. Filter is already going through the array, so why do we need to iterate through it again? We can instead make it a simple pure function.
Here's a use-case scenario within a React class method where the state has an array called items, and by using filter we can check the existing state:
checkList = (item) => { // we can access this param and globals within filter
var result = this.state.filter(value => value === item); // returns array of matching items
result.length ? return `${item} exists` : this.setState({
items: items.push(item) // bad practice, but to keep it light
});
}

Categories

Resources