So I am building an election script that assigns candidates to partys and electorates then assigns them their votes but I am so scrambled so if someone can help me understand what I'm doing, for instance this function here:
class Electorate {
constructor (newNames) {
this.name = newNames
this.allMyElectorates = []
this.addWinner = []
this.addPartyVotes = []
}
addElectorate (...newNames) {
for(let i=0;i<newNames.length;i++){
var newElectorate = new Electorate(newNames[i], this.addWinner,
this.addPartyVotes)
this.allMyElectorates.push(newElectorate)
return newElectorate
}
}
addWinner(...newNames){
theParty = myElection.findParty (partyName)
if (theParty == undefined){
myElection.addIndependant (cadidateName)
}else{
theCandidate = theParty.findCandidate (candidateName)
}if (theCandidate == undefined) {
theParty.addElectorateMP (candidateName, this)
}else{
theCandidate.setElectorate (this)}
}
function totalVotes(...newNumbers){
for(let i=0;i<newNumbers.length;i++){
var newTotalVotes = new totalVotes(newNumbers[i], this)
this.addPartyVotes.push(newTotalVotes)
return newTotalVotes
}
}
function addWinner(...newNames){
for(let i=0;i<newNumbers.length;i++){
var addWinner = new Winner(newNames[i], this)
this.addWinner.push(newWinner)
return addWinner
}
}
}
And this is what I'm trying to reference at the moment:
anElectorate = theElection.addElectorate('Auckland Central')
anElectorate.addWinner('KAYE, Nicola Laura', 'National Party')
anElectorate.addPartyVotes(329, 85, 10, 486, 3, 2, 6242, 553, 6101, 158,
12652, 1459, 7, 17, 53, 99)
I want to create a new function (totalVotes) using data collected from addPartyVotes (in the controller class) that has to to be called from other classes, it has it's variables and I'm pushing it out in an array then returning it so what am I doing wrong?
I've tried asking people in my class and the tutors but I feel like they just fob me off without giving me any real guidance, I'm an engineer not a programmer so this is very difficult to wrap my head around.
There is no single line or point of code which is breaking your program.
There are countless errors, and will simply not function.
Take a look at this example (JS ES5):
var Electorate = {
candidates: [],
init: function() {
this.candidates = [];
return this;
},
getCandidateByName: function(name) {
var filter_candidate_by_name = this.candidates.filter(function(d) {
return d.name === name;
})[0];
var index_of_candidate = this.candidates.indexOf(filter_candidate_by_name);
return this.candidates[index_of_candidate];
},
calculateWinner: function() {
var max_votes = Math.max.apply(Math, this.candidates.map(function(d) {
return d.votes.length;
}));
if (!max_votes || isNaN(max_votes)) return false;
var records_with_max_votes = this.candidates.filter(function(d) {
return d.votes.length === max_votes;
});
var result = {};
if (records_with_max_votes.length > 1) {
result.result = 'Tied';
result.candidates = records_with_max_votes;
var list_of_candidate_names = records_with_max_votes.map(function(d) {
return d.name;
}).join(', ');
result.explaination = 'Tied between ' + list_of_candidate_names + ', with a count of ' + max_votes + ' votes each';
} else if (records_with_max_votes.length === 1) {
result.result = 'Won';
result.candidate = records_with_max_votes[0];
result.explaination = records_with_max_votes[0].name + ' won with a count of ' + max_votes + ' votes';
}
return result;
}
};
var Voter = {
name: null,
age: null,
gender: null,
init: function(name, age, gender) {
if (!name || !age || !gender) return false;
this.name = name;
this.age = age;
this.gender = gender;
return this;
}
};
var Candidate = {
name: null,
votes: [],
init: function(name) {
this.name = name;
this.votes = [];
return this;
},
castVote: function(voter) {
this.votes.push(voter);
return this;
}
};
var electorate = Object.create(Electorate).init();
electorate.candidates.push(
Object.create(Candidate).init('Mr. John Smith'),
Object.create(Candidate).init('Mr. Adam John'),
Object.create(Candidate).init('Ms. Christina Brown')
);
electorate
.getCandidateByName('Mr. John Smith')
.castVote(Object.create(Voter).init('Maria Smith', 38, 'Female'))
.castVote(Object.create(Voter).init('John Doe', 118, 'Male'))
.castVote(Object.create(Voter).init('John Doe', 44, 'Male'));
electorate
.getCandidateByName('Ms. Christina Brown')
.castVote(Object.create(Voter).init('John Doe', 235, 'Male'))
.castVote(Object.create(Voter).init('John Doe', 34, 'Male'))
.castVote(Object.create(Voter).init('John Doe', 22, 'Male'));
console.log(electorate.calculateWinner());
You can see that it collects information and takes into account Candidates and Voters which can be created and added to the appropriate data location in the Electorate.
It can then go ahead after all votes are cast, and announce the selected winner or the tied winners.
My advice is to brush up on your Javascript knowledge, and try not using ES6 additions.
This is a great resource to brush up on Javascript (for all levels of experience): https://github.com/getify/You-Dont-Know-JS
Functions cannot take this as an argument.
A valid function would look like this:
function totalVotes ( vote ) {
return "something";
}
If you can share your entire script pertaining to the voting/election program, I could help guide you and your approach to writing effective code.
Related
I've recently started studying programming and JS, HTML, CSS.
Reading a book at the moment which includes the following snippet of code which i try to understand and modify for my own practice and attempts in understanding. But i really can't grasp what's going on.
Is there anyone that could please try and explain what's happening and why my modified snippet of code won't run - as it does look similar to part of the original one that does run fine.
First snippet attached is original one from book.
Second is mine which is built on parts of the prior one.
var validateDataForAge = function(data) {
person = data();
console.log(person);
if (person.age <1 || person.age > 99){
return true;
} else{
return false;
}
};
var errorHandlerForAge = function(error) {
console.log("Error while processing age");
};
function parseRequest(data,validateData,errorHandler) {
var error = validateData(data);
if (!error) {
console.log("no errors");
} else {
errorHandler();
}
}
var generateDataForScientist = function() {
return {
name: "Albert Einstein",
age : Math.floor(Math.random() * (100 - 1)) + 1,
};
};
//parse request
parseRequest(generateDataForScientist, validateDataForAge,
errorHandlerForAge);
var validateAge = function(age) {
person = age();
console.log(age);
}
validateAge(17);
I get following errormessage:
TypeError: age is not a function
at validateAge:2:12
at eval:7:1
at eval
at new Promise
Thankful for any help.
Regards,
Here is the code you are looking at. It expects data to be a function.
var validateDataForAge = function(data) {
person = data();
… and so it is (the one assigned to generateDataForScientist after it gets passed through a couple of other variables and function calls).
Here is your code:
var validateAge = function(age) {
person = age();
It expects age to be a function.
Here you pass it a value:
validateAge(17);
17 is a number, not a function.
The problem is here in this part of your code
var generateDataForScientist = function() {
return {
name: "Albert Einstein",
age : Math.floor(Math.random() * (100 - 1)) + 1, // <- problem
};
};
age is just a property of the object your returning and you are using age as a function in this code
var validateAge = function(age) {
person = age(); // <-- here ,age is not a function
console.log(age);
}
you need to chage the age property to be a function like this
var generateDataForScientist = function() {
return {
name: "Albert Einstein",
age : function (){ return Math.floor(Math.random() * (100 - 1)) + 1 },
};
};
consoling data inside parseRequest will log it as a function. But you need the property age. So replace validateData(data) with validateData(data());
var validateDataForAge = function(data) {
let person = data;
if (person.age < 1 || person.age > 99) {
return true;
} else {
return false;
}
};
var errorHandlerForAge = function(error) {
console.log("Error while processing age");
};
function parseRequest(data, validateData, errorHandler) {
console.log(data)
var error = validateData(data());
if (!error) {
console.log(error);
} else {
errorHandler();
}
}
var generateDataForScientist = function() {
return {
name: "Albert Einstein",
age: Math.floor(Math.random() * (100 - 1)) + 1,
};
};
//parse request
parseRequest(generateDataForScientist, validateDataForAge, errorHandlerForAge);
I need to be able to add a student and a grade. however, I am having a difficult time figuring out how to enter a grade. This is what I have so far. When I run the program like this I get: [ Student { name: 'Bob', grades: [], totalGrades: 0 } ] Any help would be appreciated!
The commented out section was an attempt at adding grades, however, I did not work at all.
function Student(name){
this.name = name;
this.grades = [];
this.totalGrades = function(){
this.totalGrades = 0;
this.grades.forEach(grade => {
this.totalGrade += grade;
})
}
}
function Students(){
this.students = [];
// this.grades = [];
/* this.addGrade = function(grade){
this.grades.push(grade);
}*/
this.addStudent = function(student){
this.students.push(student);
}
this.calcTotalGrades = function(){
this.students.forEach(student => {
student.totalGrades();
})
}
}
let students = new Students();
students.addStudent(new Student('Bob'));
students.calcTotalGrades();
console.log(students.students);
Try this function, as a method of your Students:
this.addGrade = function(student,grade) {
this.students.forEach(student => {
if(student.name === student)
student.grades.push(grade)
}
}
To add a new grade:
students.addGrade('Bob',10);
I'd come to a situation where I had to get the object value dynamically from an array having object keys coming from an api. I came to this approach by using eval.
class App extends React.Component {
constructor() {
super();
this.state = {
title: 'Developers',
descp: 'They are just amazing! JK',
names: ['title', 'descp']
}
}
getVal(objKey) {
let { title, descp } = this.state;
return eval(objKey);
}
render() {
let {names} = this.state;
return (
<div>
<h2>{this.getVal(names[0])}</h2>
<div>{this.getVal(names[1])}</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
The above code works correctly.
Another approach I found later:
render() {
let {names} = this.state;
return (
<div>
<h2>{this.state[names[0]]}</h2>
<div>{this.state[names[1]]}</div>
</div>
)
}
Outputs the same result. But my question is that if I use eval with the following case, is it a good approach to do so?
Eval should be avoided as it can be very dangerous. You can safely replace your eval call with accessing property via bracket notation.
getVal(objKey) {
if(this.state.hasOwnProperty(objKey)){
return this.state[objKey];
} else {
// handle missing property
}
}
Eval is generally avoided as it allows the client to insert and evaluate their own expressions in your code.
That being said, JavaScript being a client side language already allows full access to the user, so there isn't really a good reason not to use it.
As long as the user can only mess with their own session, i wouldn't worry. Security should be handled server side anyway so: Beware but don't simply ignore Eval.
EDIT 1 - Defending Eval
The comments pointed out some issues, mainly Performance/Optimization impact, which this answer explains in depth. Basically, since it's Just-In-Time compiling anyway, you don't really lose that much in terms of performance.
As for an example on a use case, here is a template example i whipped up, which also uses the controversial with statement:
var Template = /** #class */ (function () {
function Template(html) {
this.html = html;
}
Template.prototype.apply = function (params, returnDOMObject) {
if (params === void 0) { params = {}; }
if (returnDOMObject === void 0) { returnDOMObject = false; }
with (params) {
var html = eval('`' + this.html.replace(Template.regexes.encapsulated, function (n) {
return n
.replace(Template.regexes.start, '${')
.replace(Template.regexes.end, '}');
}) + '`');
}
if (returnDOMObject) {
return document.createRange().createContextualFragment(html);
}
return html;
};
Template.regexes = {
encapsulated: new RegExp('{{.*?}}', 'igm'),
start: new RegExp('\{{2,}', 'igm'),
end: new RegExp('\}{2,}', 'igm')
};
return Template;
}());
//TEST
var persons = [
{ name: "Peter", age: 25 },
{ name: "Ole", age: 55 },
];
var templates = [];
var container = document.body.appendChild(document.createElement("div"));
var leftBox = container.appendChild(document.createElement("div"));
var rightBox = container.appendChild(document.createElement("div"));
leftBox.style.width = rightBox.style.width = "50%";
leftBox.style.height = rightBox.style.height = "500px";
leftBox.style.cssFloat = rightBox.style.cssFloat = "left";
var leftList = leftBox.appendChild(document.createElement("select"));
leftBox.appendChild(document.createElement("br"));
var leftText = leftBox.appendChild(document.createElement("textarea"));
leftText.style.width = "100%";
leftText.style.resize = "vertical";
var rightOutput = rightBox.appendChild(document.createElement("div"));
function updateLists() {
leftList.innerHTML = '';
for (var i = 0; i < templates.length; i++) {
var template = templates[i];
var option = document.createElement("option");
option.value = option.innerHTML = template.name;
leftList.appendChild(option);
}
}
var h1Template = new Template("<h1>{{name}}</h1>");
var h2Template = new Template("<h2>{{age}} is no age!</h2>");
var pTemplate = new Template("<p>{{name}} may be {{age}}, but is still going strong!</p>\n<p>(When he's {{age*2}} though...)</p>");
var personTemplate = new Template("<p>\n{{ h1Template.apply(params) }}\n{{ h2Template.apply(params) }}\n{{ pTemplate.apply(params) }}\n</p>");
templates.push({ name: "personTemplate", template: personTemplate });
templates.push({ name: "h1Template", template: h1Template });
templates.push({ name: "h2Template", template: h2Template });
templates.push({ name: "pTemplate", template: pTemplate });
function updateOutput() {
rightOutput.innerHTML = '';
for (var pi = 0; pi < persons.length; pi++) {
var person = persons[pi];
rightOutput.appendChild(personTemplate.apply(person, true));
}
}
function leftTextChange() {
templates.find(function (val) { return val.name === leftList.value; }).template.html = leftText.value;
updateOutput();
}
function leftListChange() {
leftText.value = templates.find(function (val) { return val.name === leftList.value; }).template.html;
}
updateLists();
leftList.onchange = leftList.onkeyup = leftListChange;
leftText.onchange = leftText.onkeyup = leftTextChange;
leftListChange();
updateOutput();
Here the users input text is being interpreted live, while the user is watching. No security concerns, since it's all client side.
Working on a Javascript lesson and I'm stuck trying to figure out how to answer/understand how to complete this question wanted to know if anyone could help.
function Container(param) {
var person = {
firstName: 'Jimmy',
lastName: 'Smith',
get fullName() {
return this.firstName + ' ' + this.lastName;
},
set fullName (name) {
var words = name.toString().split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
}
}
// Attempting to clone private getter don't know how to access it.
function objectClone(person) {
var orginal = person //Trying to access the private method
var clone = function cloneObj { Object.assign({}, original); }
clone.prototype.spillSecret = function() { alert(this.getfullName()); }
;}
Use Object.assign to copy the normal properties, and then copy the special properties by hand after:
copy = Object.assign({}, original);
copy.year = original.year;
But this doesn't use a closure anywhere, so I'm not sure if it's what your tutorial is looking for.
var Person = function(person){
var name = 'John Doe';
function copy(){
var newPerson = Object.assign({}, person);
Object.defineProperty(newPerson, 'name', {
get: function() { return name; },
set: function(newName){ if(typeof newName !== 'string') {console.error('invalid name')} else name = newName},
enumerable: true,
configurable: true
});
return newPerson;
}
return copy();
};
var person1 = {
age: 20,
location: 'India'
}
var person2 = Person(person1);
var person3 = Person(person1);
person3.name = 1234; // invalid name
person3.name = 'Mr. India';
console.log(person1.name); // undefined
console.log(person2.name); // John Doe
console.log(person3.name); // Mr. India
In Douglas Crockford's JavaScript: The Good Parts he recommends that we use functional inheritance. Here's an example:
var mammal = function(spec, my) {
var that = {};
my = my || {};
// Protected
my.clearThroat = function() {
return "Ahem";
};
that.getName = function() {
return spec.name;
};
that.says = function() {
return my.clearThroat() + ' ' + spec.saying || '';
};
return that;
};
var cat = function(spec, my) {
var that = {};
my = my || {};
spec.saying = spec.saying || 'meow';
that = mammal(spec, my);
that.purr = function() {
return my.clearThroat() + " purr";
};
that.getName = function() {
return that.says() + ' ' + spec.name + ' ' + that.says();
};
return that;
};
var kitty = cat({name: "Fluffy"});
The main issue I have with this is that every time I make a mammal or cat the JavaScript interpreter has to re-compile all the functions in it. That is, you don't get to share the code between instances.
My question is: how do I make this code more efficient? For example, if I was making thousands of cat objects, what is the best way to modify this pattern to take advantage of the prototype object?
Well, you just can't do it that way if you plan on making lots of mammal or cat. Instead do it the old fashioned way (prototype) and inherit by property. You can still do the constructors the way you have above but instead of that and my you use the implicit this and some variable representing the base class (in this example, this.mammal).
cat.prototype.purr = function() { return this.mammal.clearThroat() + "purr"; }
I'd use another name than my for base access and store it in this in the cat constructor. In this example I used mammal but this might not be the best if you want to have static access to the global mammal object. Another option is to name the variable base.
Let me introduce you to Classical Inheritance that never uses prototype. This is a bad coding exercise but will teach you the real Classical Inheritance which always compared to prototypal inheritance:
Make a custructor:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){return "Hello! this is " + this.name;}
}
Make another cunstructor that inherits from it:
function Student(name, age, grade){
Person.apply(this, [name, age]);
this.grade = grade
}
Very simple! Student calls(applies) Person on itself with name and age arguments takes care of grade arguments by itself.
Now lets make an instance of Student.
var pete = new Student('Pete', 7, 1);
Out pete object will now contain name, age, grade and sayHello properties. It owns all those properties. They are not uplinked to Person through prototype. If we change Person to this:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){
return "Hello! this is " + this.name + ". I am " this.age + " years old";
}
}
pete will no recieve the update. If we call pete.sayHello, ti will return Hello! this is pete. It will not get the new update.
if you want privacy and you dont like protyping you may or may-not like this approach:
(note.: it uses jQuery.extend)
var namespace = namespace || {};
// virtual base class
namespace.base = function (sub, undefined) {
var base = { instance: this };
base.hierarchy = [];
base.fn = {
// check to see if base is of a certain class (must be delegated)
is: function (constr) {
return (this.hierarchy[this.hierarchy.length - 1] === constr);
},
// check to see if base extends a certain class (must be delegated)
inherits: function (constr) {
for (var i = 0; i < this.hierarchy.length; i++) {
if (this.hierarchy[i] == constr) return true;
}
return false;
},
// extend a base (must be delegated)
extend: function (sub) {
this.hierarchy.push(sub.instance.constructor);
return $.extend(true, this, sub);
},
// delegate a function to a certain context
delegate: function (context, fn) {
return function () { return fn.apply(context, arguments); }
},
// delegate a collection of functions to a certain context
delegates: function (context, obj) {
var delegates = {};
for (var fn in obj) {
delegates[fn] = base.fn.delegate(context, obj[fn]);
}
return delegates;
}
};
base.public = {
is: base.fn.is,
inherits: base.fn.inherits
};
// extend a sub-base
base.extend = base.fn.delegate(base, base.fn.extend);
return base.extend(sub);
};
namespace.MyClass = function (params) {
var base = { instance: this };
base.vars = {
myVar: "sometext"
}
base.fn = {
init: function () {
base.vars.myVar = params.myVar;
},
alertMyVar: function() {
alert(base.vars.myVar);
}
};
base.public = {
alertMyVar: base.fn.alertMyVar
};
base = namespace.base(base);
base.fn.init();
return base.fn.delegates(base,base.public);
};
newMyClass = new namespace.MyClass({myVar: 'some text to alert'});
newMyClass.alertMyVar();
the only downside is that because of the privacy scope you can only extend the virtual classes and not the instanceable classes.
here is an example of how i extend the namespace.base, to bind/unbind/fire custom events.
// virtual base class for controls
namespace.controls.base = function (sub) {
var base = { instance: this };
base.keys = {
unknown: 0,
backspace: 8,
tab: 9,
enter: 13,
esc: 27,
arrowUp: 38,
arrowDown: 40,
f5: 116
}
base.fn = {
// bind/unbind custom events. (has to be called via delegate)
listeners: {
// bind custom event
bind: function (type, fn) {
if (fn != undefined) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type].push(fn);
}
return this;
},
// unbind custom event
unbind: function (type) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type] = [];
return this;
},
// fire a custom event
fire: function (type, e) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' does not exist');
}
for (var i = 0; i < this.listeners[type].length; i++) {
this.listeners[type][i](e);
}
if(e != undefined) e.stopPropagation();
}
}
};
base.public = {
bind: base.fn.listeners.bind,
unbind: base.fn.listeners.unbind
};
base = new namespace.base(base);
base.fire = base.fn.delegate(base, base.fn.listeners.fire);
return base.extend(sub);
};
To proper use Javascript-prototype based inheritance you could use fastClass https://github.com/dotnetwise/Javascript-FastClass
You have the simpler inheritWith flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.inheritWith(function (base, baseCtor) {
return {
constructor: function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
},
purr: function() {
return this.clearThroat() + " purr";
},
getName: function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
And if you are very concerned about performance then you have the fastClass flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.fastClass(function (base, baseCtor) {
return function() {
this.constructor = function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
};
this.purr = function() {
return this.clearThroat() + " purr";
},
this.getName = function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
Btw, your initial code doesn't make any sense but I have respected it literally.
fastClass utility:
Function.prototype.fastClass = function (creator) {
var baseClass = this, ctor = (creator || function () { this.constructor = function () { baseClass.apply(this, arguments); } })(this.prototype, this)
var derrivedProrotype = new ctor();
if (!derrivedProrotype.hasOwnProperty("constructor"))
derrivedProrotype.constructor = function () { baseClass.apply(this, arguments); }
derrivedProrotype.constructor.prototype = derrivedProrotype;
return derrivedProrotype.constructor;
};
inheritWith utility:
Function.prototype.inheritWith = function (creator, makeConstructorNotEnumerable) {
var baseCtor = this;
var creatorResult = creator.call(this, this.prototype, this) || {};
var Derrived = creatorResult.constructor ||
function defaultCtor() {
baseCtor.apply(this, arguments);
};
var derrivedPrototype;
function __() { };
__.prototype = this.prototype;
Derrived.prototype = derrivedPrototype = new __;
for (var p in creatorResult)
derrivedPrototype[p] = creatorResult[p];
if (makeConstructorNotEnumerable && canDefineNonEnumerableProperty) //this is not default as it carries over some performance overhead
Object.defineProperty(derrivedPrototype, 'constructor', {
enumerable: false,
value: Derrived
});
return Derrived;
};
define utility:
Function.prototype.define = function (prototype) {
var extendeePrototype = this.prototype;
if (prototype)
for (var p in prototype)
extendeePrototype[p] = prototype[p];
return this;
}
[* Disclaimer, I am the author of the open source package and the names of the methods themselves might be renamed in future` *]