I've been reading through an article titled Don’t Be Scared Of Functional Programming and there is a piece of code I'm having trouble understanding (pasted below). The code's purpose is to get an item from an array of objects called data. What I don't understand is how the function within the function works. Where is the item argument coming from when you invoke getItem()?
var data = [
{
name: "Jamestown",
population: 2047,
temperatures: [-34, 67, 101, 87]
},
{
name: "Awesome Town",
population: 3568,
temperatures: [-3, 4, 9, 12]
}
{
name: "Funky Town",
population: 1000000,
temperatures: [75, 75, 75, 75, 75]
}
];
function getItem(propertyName) {
// Return a function that retrieves that item, but don't execute the function.
// We'll leave that up to the method that is taking action on items in our
// array.
return function(item) {
return item[propertyName];
}
}
I Understand that JS allows functions to be passed as arguments because they are treated as “first-class objects" in JS, but I don't understand where that item argument would be coming from.
This is defining a function that will accept a parameter called item which can be used to return the propertyName element from the given item. It is the function that is then passed back to the caller of getItem. It would be used as follows:
var getName = getItem('name');
var result = getName(x);
Where x is a variable containing a property called 'name'
Maybe this helps a bit.
It utilized a partial application of the first parameter propertyName with Function.prototype.bind():
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Small example with your data and function:
function getItem(propertyName, item) {
return item[propertyName];
}
var data = [{ name: "Jamestown", population: 2047, temperatures: [-34, 67, 101, 87] }, { name: "Awesome Town", population: 3568, temperatures: [-3, 4, 9, 12] }, { name: "Funky Town", population: 1000000, temperatures: [75, 75, 75, 75, 75] }],
// this returns a function with only item as parameter
getName = getItem.bind(null, 'name');
document.write('<pre>' + JSON.stringify(data.map(getName), 0, 4) + '</pre>');
Related
Hey so I'm working on a JS project, and I came across an issue where I am trying to add/merge 2 objects together. So basically, there is a base object:
{age: 0,
lvl: 123,
xp: 321}
So we have this, and I have another object coming in with
{age: 12,
lvl: 21}
The result I want is
{age: 12,
lvl: 144,
xp: 321}
But that could be easily achieved with just individual property addition. However, I want to come to a point where I don't know what properties the object has, yet they are still added. Oh and the property type will for sure be a number. Any ideas?
Edit:
Ok, I see I mis worded some stuff. What I meant by me not knowing which properties it has, I meant that I know that the object may have one-all properties of the first object, just that I don't know which ones the second one has and does have.
Loop through the keys of the second object and add them to the first:
const first = {
age: 0,
lvl: 123,
xp: 321
};
const second = {
age: 12,
lvl: 21
};
for (const key in second) {
first[key] = (first[key] || 0) + second[key];
}
console.log(first);
Read more about for...in loops here.
Write a function that makes a copy of the first object and adds the keys in:
function addProperties(firstObj, secondObj) {
const newObj = Object.assign({}, firstObj);
for (let key of Object.keys(secondObj)) {
if (newObj.hasOwnProperty(key)) {
newObj[key] += secondObj[key];
} else {
newObj[key] = secondObj[key];
}
}
return newObj;
}
const first = {
age: 0,
lvl: 123,
xp: 321
};
const second = {
age: 12,
lvl: 21
};
const result = addProperties(first, second);
console.log(result);
i try to access this function in my Object with the console.log but i don't really understand why i can't access it!
I'm beginning Javascript but i'm really stuck with accessing functions in Object.
Thanks for the help
const hotel = {
name: "Grand Hotel",
location: "Stockholm",
pricePerNight: 2200,
roomBooked: 23,
totalRoom: 223,
roomAvailable: function(){
return this.totalRoom - this.roomBooked;
}
};
hotel.roomAvailable();
console.log(hotel.roomAvailable);
You're just missing the parentheses in the log function:
hotel.roomAvailable()
You are already invoking the function which will return the value. Just log the return value instead.
In your code you are just logging the definition of the function but not really invoking it.
const hotel = {
name: "Grand Hotel",
location: "Stockholm",
pricePerNight: 2200,
roomBooked: 23,
totalRoom: 223,
roomAvailable: function() {
return this.totalRoom - this.roomBooked;
}
};
var isRoomAvailable = hotel.roomAvailable();
console.log(isRoomAvailable);
Is this what you want?
const hotel = {
name: "Grand Hotel",
location: "Stockholm",
pricePerNight: 2200,
roomBooked: 23,
totalRoom: 223,
roomAvailable: function(){
return this.totalRoom - this.roomBooked;
}
};
console.log(hotel.roomAvailable());
I need to take an array objects that and map it so that the new array is just a simple array if each object's id.
So for example:
[
{id: 49, name: "Rest update test"},
{id: 12, name: "Rest test"}
]
would become:
[49, 12]
i have tried this so far:
myObject.map(object => object.id);
so my actual function that is not working is the following, when I view the console.log, it is showing the original object:
onSubmit() {
this.userForm.value.accountsToAdd.map(object => object.id);
console.log(this.userForm.value.accountsToAdd);
}
Assuming the given code does not work, then you need to assign the result of mapping.
Array#map does not mutate the original array but return a new one.
var array = [{ id: 49, name: "Rest update test" }, { id: 12, name: "Rest test" }],
ids = array.map(object => object.id);
console.log(ids);
I have the following code:
var gameController = {
scores: [20, 34, 55, 46, 77],
avgScore: 112,
players: [
{name: "Ruth", playerId: 100, age: 22},
{name: "Shawnee", playerId: 101, age: 21}
]
};
var appController = {
scores: [900, 845, 809, 950],
avgScore: null,
avg: function () {
var sumOfScores = this.scores.reduce(function (prev, cur, index, array) {
return prev + cur;
});
this.avgScore = sumOfScores / this.scores.length;
}
};
gameController.avgScore = appController.avg();
console.log(gameController.avgScore);
I tried to borrow the avg method defined in appController to do the calculation for gameController. I understand that after gameController.avgScore = appController.avg();, this keyword in avg method will still point to appController as avg method was invoked by appController so I expect avgScore in gameController should remain intact, but the output is undefined, why?
avg doesn't return anything, so it implicitly returns undefined. You are basically doing gameController.avgScore = undefined;.
If you want to apply the avg method to gameController, you could use .call:
appController.avg.call(gameController);
Better would probably be to have avg as a standalone function that accepts an array of numbers as input (argument) and returns the average.
Updated:
When assigning a function to an object the this keyword is set to the object when the function is invoked. This is true only for unbound function references. If the function reference is bound to another object you will have to use the Function.bind() method to ensure this is set to the correct object.
Answer
Rather than use call each time just assign the function to the object. When the function is call the this is set to the object
gameController.avg = appController.avg; // unbound function reference.
// now when you need to get the average for gameController
// just call its avg function
gameController.avg(); // this is automatically set to gameControler
Better still create the function outside the controllers and assign them at creation time.
// define the avg and refer it to the unbound function that you will share
var avg = function () {
var sumOfScores = this.scores.reduce(function (prev, cur, index, array) {
return prev + cur;
});
this.avgScore = sumOfScores / this.scores.length;
console.log(this.avgScore);
}
// create the objects as normal
var gameController = {
scores: [20, 34, 55, 46, 77],
avgScore: 112,
players: [
{name: "Ruth", playerId: 100, age: 22},
{name: "Shawnee", playerId: 101, age: 21}
],
avg:avg // avg is automatically bound to gameController when it is called
};
var appController = {
scores: [900, 845, 809, 950],
avgScore: null,
avg:avg // avg is automatically bound to appController when it is called
};
// or if you want to get really lazy.
var otherController = {
scores: [900, 900, 900, 900],
avgScore: null,
avg // avg is automatically bound to otherController when it is called
// and it is automatically named avg as well
};
appController.avg(); // 46.4
gameController.avg(); // 876
otherController.avg(); // 900
And there are over half a dozen other ways to achieve the same thing.
Is there a way to initialize a javascript object with an array of child objects in one line? How can I do the following in just on initialization line.
var obj = {doc: 100,
defaultrateid: 32,
rates: [],
};
obj.rates[31] = {rate: 101.00, name: "Rate 1"};
obj.rates[32] = {rate: 121.00, name: "Rate 2"};
Basically what I want is a single javascript object that has my user parameters. This object will be reused on multiple web forms. In the case of 'rates', the forms will have a dropdown to select a rate. The web forms have client side calculations that require the matching rate object based on the rate's unique id (e.g. 32).
I'm trying to use a associative array instead of having to do looping for finding a match based on unique value.
Seems a bit hacky:
obj = {
doc: 100,
defaultrateid: 32,
rates: (new Array(30)).concat([{
rate: 101.00,
name: "Rate 1"
}, {
rate: 121.00,
name: "Rate 2"
}])
};
EDIT:
Maybe you don't really need an array, you can use an object like this:
obj = {
doc: 100,
defaultrateid: 32,
rates: {
"31": {
rate: 101.00,
name: "Rate 1"
},
"32": {
rate: 121.00,
name: "Rate 2"
}
}
};
And you can still get the rates like obj.rates[31].
Do you mean like this?
var obj = {
doc: 100,
defaultrateid: 32,
rates: [{
rate: 101.00
}, {
rate: 121.00
}],
};
alert(obj.rates[1].rate);