Converting class to function - javascript

I'm making a real time app and want to convert this class code to a function.
Would the function below be the equivalent? And from what anyone can see, would there be a benefit to keeping it a class as opposed to a function?
class IdeaService {
constructor() {
this.ideas = [];
}
async find() {
return this.ideas;
}
async create(data) {
const idea = {
id: this.ideas.length,
text: data.text,
tech: data.tech,
viewer: data.viewer
};
idea.time = moment().format('h:mm:ss a');
this.ideas.push(idea);
return idea;
}
}
FUNCTION
function ideaService() {
let ideas = [];
async find() {
return ideas;
}
async create(data) {
const idea = {
id: ideas.length,
text: data.text,
tech: data.tech,
viewer: data.viewer
}
idea.time = moment().formate('h:mm:ss a');
ideas.push(idea);
return idea;
}
}

try this
let IdeaService = (function() {
let ideas = [];
async function find() {
return ideas;
}
async function create(data) {
const idea = {
id: ideas.length,
text: data.text,
tech: data.tech,
viewer: data.viewer
};
idea.time = moment().format('h:mm:ss a');
ideas.push(idea);
return idea;
}
return {
find,
create
}
})();
EDIT! If youd like this module to NOT be instantiated upon this file running remove the (); at the end. so the function would be:
IdeaService = (function() {
});
and to instantiate it would be:
let ideaService = IdeaService();

Related

JavaScript Syntax III: Why is my code throwing undefined on the ratings?

so I am currently working on a project on Code Academy, I am not certain why is it showing undefined. Although I've watched the walk through video, the project is named Build a Library. Here's my entire code:
I am still confused regarding JavaScrip, so please bear with me. Thank you for those who will answer!
class Media {
constructor(title) {
this._title = title;
this._ratings = [];
this._isCheckedOut = false;
}
get title() {
return this._title;
}
get isCheckedOut() {
return this._isCheckedOut;
}
get ratings() {
return this._ratings;
}
set isCheckedOut(value) {
this._isCheckedOut = value;
}
toggleCheckOutStatus() {
this._isCheckedOut = !this._isCheckedOut;
}
getAverageRating() {
let ratingsSum = this.ratings.reduce((accumulator, rating) => accumulator + rating);
}
addRating(value) {
this.ratings.push(value);
}
}
class Book extends Media {
constructor(author, title, pages) {
super(title);
this._author = author;
this._pages = pages;
}
get author() {
return this._author;
}
get pages() {
return this._pages;
}
}
class Movie extends Media {
constructor(director, title, runTime) {
super(title);
this._director = director;
this._runTime = runTime;
}
get director() {
return this._director;
}
get runTime() {
return this._runTime;
}
}
const historyOfEverything = new Book("Bill Bryson", "A Short History of Nearly Everything", 544);
historyOfEverything.toggleCheckOutStatus();
console.log(historyOfEverything.isCheckedOut);
historyOfEverything.addRating(4);
historyOfEverything.addRating(5);
historyOfEverything.addRating(5);
console.log(historyOfEverything.getAverageRating());
const speed = new Movie("Jan de Bont", "Speed", 116);
speed.toggleCheckOutStatus();
console.log(speed.isCheckedOut);
speed.addRating(1);
speed.addRating(1);
speed.addRating(5);
console.log(speed.getAverageRating());
because you are not returning anything from the getAverageRating function,
you should add : return ratingsSum/this.ratings.length if i understood what you want to do , so the whole function will be something like this:
getAverageRating() {
let ratingsSum = this.ratings.reduce(
(accumulator, rating) => accumulator + rating
);
return ratingsSum/this.ratings.length
}

Converting Calories Tracking application to ES6 Classes

I managed to recreate a MVC calorie tracker app from a course and I am trying to convert it to ES6 classes now.
I am a little stuck in understanding how to call the methods in the Module inside the Controller to return the items I need.
class Item {
constructor() {
this.data = {
items: [{
name: 'Salad',
calories: 200,
id: 0
},
{
name: 'Eggs',
calories: 500,
id: 1
}],
totalCalories: 0,
currentItem: null
}
};
getItems() {
return this.data.items
};
logData = () => {
console.log(data.items);
};
}
class App {
constructor(Item, UI) {
this.Item = Item;
this.UI = UI;
}
init() {
const items = Item.getItems();
UI.populateItemList(items)
}
}
const application = new App(new Item(), new UI())
When I try to call Item.logData() in the console it gives me TypeError: this.data is undefined.
I researched online and it seems that the method I declared is for the constructor only. How would I go about declaring methods that I'll use in the Controller or in any other class, just like I did below by returning a method out of the constructor?
What Im trying to convert initially looks like this:
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.name = name;
this.id = id;
this.calories = calories;
}
const data = {
items: StorageCtrl.getStorage(),
totalCalories: 0,
currentItem: null
}
return {
getItems: function () {
return data.items
},
logData: function () {
return data;
}
}
const App = (function (ItemCtrl, StorageCtrl, UICtrl) {
return {
init: function () {
const items = ItemCtrl.getItems();
UICtrl.populateItems(items);
}
}
})(ItemCtrl, StorageCtrl, UICtrl);
App.init();
You need to initialise the controller first:
class App {
constructor(Item, UI) {
this.item = new Item();
this.UI = new UI();
}
init() {
const items = this.item.getItems();
this.UI.populateItemList(items)
}
}

Typescript, problem with "this" inside arrow functions and rxjs

im trying to push to an array inside a subscrive method of rxjs using => but the variable that is an array outside changes into an object inside so i cannot use .push
#Component({
selector: 'devices_status-panel',
templateUrl: './devices.component.html',
styleUrls: ['./devices.component.scss']
})
export class DevicesComponent implements OnInit {
public rows = Array<any>();
public columns = [
{ date: 'Fecha' },
{ deviceId: 'Equipo' },
{ error: 'Estado' },
{ statusType: 'Evento'},
{ location: 'Localidad'},
{ ip: 'Ip' },
{ version: 'Version' },
{ unencriptedMessage: 'Mensaje'}
];
constructor(private devicesData: DevicesData) {
console.log("0")
console.log(this.rows)
this.getDeviceState();
}
getDeviceState(){
this.devicesData.getStatePipe()
.subscribe(([deviceState, info]) => {
console.log("1")
console.log(this.rows)
Object.keys(deviceState).forEach((key1) => {
const thisState: DeviceState = deviceState[key1];
console.log("2")
console.log(this.rows)
Object.keys(thisState.status).forEach((key2) => {
console.log("3")
console.log(this.rows)
const status: Status = thisState.status[key2];
if (status){
const eventGroupArray: Array<Array<DeviceEvent>> = status.deviceStatus;
eventGroupArray.forEach((eventArray) => {
eventArray.forEach((event) => {
const state: StateArray = {
date: event.date,
deviceId: event.deviceId,
error: status.error,
ip: event.ip,
statusType: event.statusType,
unencriptedMessage: event.unencriptedMessage,
version: event.version,
location: null
};
if (info.info[thisState.id]){
state.location = info.info[thisState.id];
}else{
state.location = "Desconocida"
}
console.log(this.rows)
console.log(typeof this.rows)
this.rows.push(state);
});
});
}
});
});
});
console.log(this.rows)
}
}
As you can see i added logs inside subscribe and just before the function call, this is an array outside and an object inside
I tried to solve it myself but i cant find where is the problem, any help is appreciated
Thanks
You haven't shown us what the log statements reveal, but if they show something different, the only reason that will happen is that something is assigning to this.rows between the time you log it prior to subscribing and the time the subscription happens, like this example using setTimeout:
const foo = {
example() {
this.rows = [];
console.log(1, this.rows);
setTimeout(() => {
console.log(2, this.rows);
}, 100);
}
};
foo.example();
foo.rows = {};
this inside the arrow function will be the same as it was outside, because that's how arrow functions work. So if this.rows is changing, it's because something is changing it.
It might be a closure problem. Try to add
getDeviceState(){
const _that = this;
.
.
.code...
_that.rows.push(state);
}

Executing a function in a loop in javascript asynchronously- where to place defer.resolve?

I come from java/python background and new to javascript. I need to create a product list with the description of its children as well included in a jsonarray.
parent_list:
[{ children: [ 100714813, 100712694 ],
sp: '89.10',
weight: '1 ltr',
pack_type: 'Carton',
brand: 'Real',
p_desc: 'Fruit Power Juice - Orange' }]
Now for every parent I need to again iteratively fetch the children details by connecting to the database and finally have the result consolidated in a single jsonarray. But when I execute the below code, the control doesn't wait for fetching the children data( which makes sense as its being called asynchronously!), the result I get is a jsonarray that contains data only for the parents that have no children.
exports.productDetailsQuery = function(options) {
var AEROSPIKE_NAMESPACE = '';
var AEROSPIKE_SET = 'products';
var PD_KEY_VERSION_NUMBER = '1';
var defer = sails.Q.defer();
var results = options.results;
var parent_list = [];
var finalData = [];
var productKeys = results.map(
function(x){
return {
ns: AEROSPIKE_NAMESPACE,
set: AEROSPIKE_SET,
key: "pd.v" + PD_KEY_VERSION_NUMBER + '.' + 'c' + options.city_id + '.' + x.sku.toString()
}
}
);
var status = require('aerospike').status;
var breakException = {};
// Read the batch of products.
sails.aerospike.batchGet(productKeys, function (err, results) {
if (err.code === status.AEROSPIKE_OK) {
for (var i = 0; i < results.length; i++) {
switch (results[i].status) {
case status.AEROSPIKE_OK:
parent_list.push(results[i].record);
break;
case status.AEROSPIKE_ERR_RECORD_NOT_FOUND:
console.log("NOT_FOUND - ", results[i].keys);
break;
default:
console.log("ERR - %d - ", results[i].status, results[i].keys);
}
}
parent_list.forEach(function(parent){
var children = parent['children'];
console.log(children)
if(children){
var childKeys = children.map(function(child){
return {
ns: AEROSPIKE_NAMESPACE,
set: AEROSPIKE_SET,
key: "pd.v" + PD_KEY_VERSION_NUMBER + '.' + 'c' + options.city_id + '.' + child.toString()
}
});
sails.aerospike.batchGet(childKeys, function(err, childData){
if(err.code === status.AEROSPIKE_OK){
console.log('this called')
var entry = {};
entry['primary_prod'] = parent;
entry['variants'] = childData;
finalData.push(entry);
}
});
}
else{
var entry = {};
entry['primary_prod'] = parent;
finalData.push(entry);
}
});
defer.resolve(finalData);
} else {
defer.reject(err);
}
});
return defer.promise;
}
I need finalData to be like:
[{"primary_prod":{ children: [ 100714813, 100712694 ],
sp: '89.10',
weight: '1 ltr',
pack_type: 'Carton',
brand: 'Real',
p_desc: 'Fruit Power Juice - Orange' },
"variants":[{child_data},{child_data}]}, ...........]
Would really appreciate any help as to how to make it work.Is there a specific pattern to handle such cases?
Thanks!
What you have written is along the right lines but only the outer batchGet() is promisified. Because there's no attempt to promisify the inner batchGet(), it doesn't contribute to the finally returned promise.
Your overall pattern might be something like this ...
exports.productDetailsQuery = function(options) {
return sails.aerospike.batchGetAsync(...).then(results) {
var promises = results.filter(function(res) {
// Filter out any results that are not `AEROSPIKE_OK`
...
}).map(function(parent) {
// Map the filtered results to an array of promises
return sails.aerospike.batchGetAsync(...).then(function(childData) {
...
});
});
// Aggregate the array of promises into a single promise that will resolve when all the individual promises resolve, or will reject if any one of the individual promises rejects.
return sails.Q.all(promises);
});
}
... where batchGetAsync() is a promisified version of batchGet().
The fully fleshed-out the code will be longer but can be kept reasonably concise, and readable, by first defining a couple of utility functions. You might end up with something like this :
// utility function for making a "key" object
function makeKey(obj) {
return {
ns: '', //AEROSPIKE_NAMESPACE
set: 'products', //AEROSPIKE_SET
key: 'pd.v1.c' + options.city_id + '.' + obj.toString()
}
}
// promisified version of batchGet()
function batchGetAsync(obj) {
var defer = sails.Q.defer();
batchGet(obj, function(err, results) {
if(err.code === status.AEROSPIKE_OK) {
defer.resolve(results);
} else {
defer.reject(err);
}
});
return defer.promise;
}
var status = require('aerospike').status;
// Main routine
exports.productDetailsQuery = function(options) {
return batchGetAsync(options.results.map(makeKey)).then(results) {
var promises = results.filter(function(res) {
if (res.status === status.AEROSPIKE_OK) {
return true;
} else if(status.AEROSPIKE_ERR_RECORD_NOT_FOUND) {
console.log("NOT_FOUND - ", res.keys);
} else {
console.log("ERR - %d - ", res.status, res.keys);
}
return false;
}).map(function(parent) {
var entry = { 'primary_prod': parent },
children = parent['children'];
if(children) {
return batchGetAsync(children.map(makeKey)).then(function(childData) {
entry.variants = childData;
return entry;
});
} else {
return entry;
}
});
return sails.Q.all(promises);
});
}
With the new ES6 plus async stuff and babel its simpler. You can npm i -g babel npm i babel-runtime then compile and run the following with babel test.js --optional runtime --stage 2 | node:
import {inspect} from 'util';
let testData = [
{ id: 0, childIds: [1,2]},
{ id: 1, childIds:[] },
{ id: 2, childIds:[] }
];
function dbGet(ids) {
return new Promise( r=> {
r(ids.map((id) => { return testData[id];}));
});
}
async function getChildren(par) {
let children = await dbGet(par.childIds);
par.children = children;
}
async function getAll(parentIds) {
let parents = await dbGet(parentIds);
for (let p of parents) {
await getChildren(p);
}
return parents;
}
async function test() {
var results = await getAll([0]);
console.log(inspect(results,{depth:3}));
}
test().then(f=>{}).catch( e=> {console.log('e',e)});

OO(object-oriented) javascript

I've a fair amount of experience with JavaScript, and for this new project I'm on (cms for blog with notions of profitability) I thought I'd step it up and write the JavaScript in an MVC fashion. I've been using a bit of backbone and underscore, but it isn't clicking mentally. any way, I've written a bit of code to handle some events/effects but it just doesn't work. If anyone could sort me out I'd really appreciate it.
// Semi Perfect grade 0 JS - Golden age
//partial View Objects | Events
var pshare_dock = {
actor: $("#share_dock"),
drag: function () {
this.actor.draggable();
}
}
pshare_dock.expand = function () {
this.actor.dblclick(function () {
$(this).toggleClass("share_close");
});
}
var pmenu = {
hover: function () {
$("ul.drop li.drop").hover(function () {
$(this).find('ul').fadeIn(1);
}, function () {
$(this).find('ul').hide();
})
},
navigate: function () {
$("a.ajx").click(function (e) {
var link;
var container = $("#content_pane");
e.preventDefault();
link = $(this).attr("href") + "#content_pane";
container.load(link);
})
}
}
var pcontent_pane = {}
var ppost = {}
var pdatabase_entry = {}
//Views
var Homepage = function () {
this.share_dock = function () {
new pshare_dock();
}
this.menu = function () {
new pmenu();
}
this.content_pane = function () {
new pcontent_pane();
}
this.posts = function () {
new ppost();
}
}
//Controller
var GoldenAgeRouter = Backbone.Router.extend({
routes: {
"!/": "defaultRoute",
"*actions": "defaultRoute"
},
defaultRoute: function (actions) {
var homeView = function () {
new Homepage();
}
}
})
$(document).ready(function () {
var Golden_age = function () {
new Homepage();
}
})
the question is essentially what all is wrong with this?
You're wrapping your instantiations in an anonymous function but not invoking them:
var Golden_age = new Homepage(); // Invoked.
var Golden_age = function(){ new Homepage(); } // Stored function, not invoked.

Categories

Resources