How to assign JSON to a class recursively? - javascript

To modelize a family structure, I used the simple Person class, and I would be able to save a structure as text, and later go in the other way. But my class has different methods useful and indispensable to my code, I found the way for the first object, but how to continue in depth?
Depth here is 1, but it can go up to 6
let json = {"name":"SON","date":"2000-01-01T05:00:00.000Z","sex":"H",
"dad":{"name":"DAD","date":"2000-01-02T05:00:00.000Z","sex":"H","dad":null,"mom":null},
"mom":{"name":"MOM","date":"2000-01-03T05:00:00.000Z","sex":"F","dad":null,"mom":null}
};
class Person {
constructor(name, date, sexe) {
this.name = name;
this.date = date;
this.sexe = sexe;
this.dad = null;
this.mom = null;
}
doStuff(){
console.log(this.name);
}
}
let obj = Object.assign(new Person,json);
//OK
obj.doStuff();
//NOK 'obj.dad.doStuff is not a function' as 'dad' is not associated to Person
obj.dad.doStuff();

You can do it recursively, calling the same function that performs Object.assign on dad and mom if they are not null:
let json = {
"name": "SON", "date": "2000-01-01","sex": "H",
"dad": {
"name": "DAD","date": "2000-01-02","sex": "H", "dad": null,"mom": null
},
"mom": {
"name": "MOM","date": "2000-01-03","sex": "F","dad": null,
"mom" : { "name": "GRAMDA","date": "2000-01-02","sex": "F","dad": null,"mom": null }
}
};
class Person {
constructor(name, date, sexe) {
this.name = name;
this.date = date;
this.sexe = sexe;
this.dad = null;
this.mom = null;
}
doStuff() {
console.log(this.name);
}
}
function buildPersons(root) {
let obj = Object.assign(new Person, root);
if (obj.dad) obj.dad = buildPersons(obj.dad);
if (obj.mom) obj.mom = buildPersons(obj.mom);
return obj;
}
let obj = buildPersons(json);
obj.doStuff();
obj.dad.doStuff();
obj.mom.mom.doStuff();

Related

Create class which represents collection of Employees

I have abstract Class AbstractEmployee and two concrete sub-classes FixedSalaryEmployee and PerHourSalaryEmployee which inherit from AbstractEmployee and override its abstract getSalary method with correct implementation for given employye type.
First implementation FixedSalaryEmployee - Employee with fixed salary. Where average monthly salary is equal to employee the value of salary in JSON data.
Second implementation PerHourSalaryEmployee- Employee with per-hour salary. Where hour rate is equal to the value of salary in JSON data, working day has 8 hours and month has 20.88 working days in average.
And create Collection class which is able to work with employees of different types.
The main question is how to сreate EmployeeCollection class which represents collection of Employees:
Constructor should accept data from JSON file and create instances of corresponding classes based on type field.
id should be generated in a format id<number> e.g. (id0, id1 etc. for each item in collection)
Items in collection should be sorted by the next rules:
Sort all employees in descending order of average monthly salary.
If average monthly salary of employees is equal use employee name instead.
Need use ES5!
//AbstractEmployee.js
var AbstractEmployee = function(id, name, salary) {
if (this.constructor === AbstractEmployee) {
throw new Error("Can't instantiate abstract class!");
}
this.id = id;
this.name = name;
this.salary = salary;
if(typeof(object.id) !== 'string' || typeof(object.name) !== 'string' || typeof(object.salary) !== 'number'){
throw new Error("Wrong param passed!");
}
};
AbstractEmployee.prototype.getSalary = function() {
throw new Error('Method getSalary() must be implemented');
}
//PerHourSalaryEmployee.js
var AbstractEmployee = require('./AbstractEmployee.js')
var PerHourSalaryEmployee = function(id, name, salary) {
AbstractEmployee.apply(this, arguments)
this.id = 'id' + id;
this.name = name;
this.salary = salary * 20.88 * 8;
};
PerHourSalaryEmployee.prototype.getSalary = function() {
return this.salary;
}
module.exports = PerHourSalaryEmployee
//FixedSalaryEmployee.js
var AbstractEmployee = require('./AbstractEmployee.js')
var FixedSalaryEmployee = function(id, name, salary) {
AbstractEmployee.apply(this, arguments);
this.id = 'id' + id;
this.name = name;
this.salary = salary;
};
FixedSalaryEmployee.prototype.getSalary = function() {
return this.salary;
}
module.exports = FixedSalaryEmployee
employees-collection.json
[{
"type": "per-hour",
"salary": 10,
"name": "Anna"
},
{
"type": "per-hour",
"salary": 8,
"name": "Bob"
},
{
"type": "fixed",
"salary": 8000,
"name": "Dany"
},
{
"type": "fixed",
"salary": 8000,
"name": "Clara"
},
{
"type": "fixed",
"salary": 1000,
"name": "Egor"
}]
As was already commented, a half baked AbstractEmployee function used merely as a function based mixin does not make real sense.
A pure old school (it was asked for / limited to ES5-syntax) inheritance approach is much better suitable.
And one actually does not even need a BaseEmployee constructor since the features of a FixedSalaryEmployee type are totally equal to the ones of a BaseEmployee type, and the PerHourSalaryEmployee type differs only in the internal/initial computation of its salary property(, but one never knows what the future still might bring) ...
function orderBySalaryDescendingAndNameAscending(a, b) {
return (b.salary - a.salary) || a.name.localeCompare(b.name);
}
// employee factory.
function createTypeDependedEmployeeVariant(rawData, idx) {
const { type, name, salary } = rawData;
const employee = (type === 'per-hour')
? new PerHourSalaryEmployee(String(idx), name, salary)
: new FixedSalaryEmployee(String(idx), name, salary)
// employee.type = type;
return employee;
}
// employee list factory.
function createOrderedListOfVariousEmployeeInstances(arr) {
return arr
.map(createTypeDependedEmployeeVariant)
.sort(orderBySalaryDescendingAndNameAscending);
}
const jsonDataList = [{
"type": "per-hour",
"salary": 10,
"name": "Anna"
}, {
"type": "per-hour",
"salary": 8,
"name": "Bob"
}, {
"type": "fixed",
"salary": 8000,
"name": "Dany"
}, {
"type": "fixed",
"salary": 8000,
"name": "Clara"
}, {
"type": "fixed",
"salary": 1000,
"name": "Egor"
}];
console.log(
createOrderedListOfVariousEmployeeInstances(jsonDataList)
.map(({ id, name, salary }) => ({ id, name, salary }))
);
console.log(
createOrderedListOfVariousEmployeeInstances(jsonDataList)
.map(item => item.getSalary())
);
console.log(
createOrderedListOfVariousEmployeeInstances(jsonDataList)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
function BaseEmployee(id, name, salary) {
if (
(typeof id !== 'string') ||
(typeof name !== 'string') ||
(typeof salary !== 'number') ||
!Number.isFinite(salary)
) {
throw new TypeError('Wrong parameter(s) passed!');
}
this.id = 'id' + id;
this.name = name;
this.salary = salary;
}
BaseEmployee.prototype.getSalary = function() {
return this.salary;
}
</script>
<script>
function PerHourSalaryEmployee (id, name, salary) {
// super call.
BaseEmployee.apply(this, arguments);
this.salary = (salary * 20.88 * 8);
};
// extend superclass.
PerHourSalaryEmployee.prototype = Object.create(BaseEmployee.prototype);
// prevent super constructor from being the sub-classed constructor.
PerHourSalaryEmployee.prototype.constructor = PerHourSalaryEmployee;
</script>
<script>
function FixedSalaryEmployee(id, name, salary) {
// super call.
BaseEmployee.apply(this, arguments);
};
// extend superclass.
FixedSalaryEmployee.prototype = Object.create(BaseEmployee.prototype);
// prevent super constructor from being the sub-classed constructor.
FixedSalaryEmployee.prototype.constructor = FixedSalaryEmployee;
</script>
The most optimized Employee-class code-base would/could look like the below provided code. There is no difference in its usage with the above provided factories in comparison to the above code base which features the additional BaseEmployee ...
function checkEmployeeArguments(id, name, salary) {
if (
(typeof id !== 'string') ||
(typeof name !== 'string') ||
(typeof salary !== 'number') ||
!Number.isFinite(salary)
) {
throw new TypeError('Wrong parameter(s) passed!');
}
}
function FixedSalaryEmployee(id, name, salary) {
checkEmployeeArguments(id, name, salary);
this.id = 'id' + id;
this.name = name;
this.salary = salary;
}
FixedSalaryEmployee.prototype.getSalary = function() {
return this.salary;
}
function PerHourSalaryEmployee (id, name, salary) {
// super call.
FixedSalaryEmployee.apply(this, arguments);
this.salary = (salary * 20.88 * 8);
};
// extend superclass.
PerHourSalaryEmployee.prototype = Object.create(FixedSalaryEmployee.prototype);
// prevent super constructor from being the sub-classed prototype constructor.
PerHourSalaryEmployee.prototype.constructor = PerHourSalaryEmployee;

how to get an object from a closure?

How to get an object from a closure, that's confusion with me, here is the question:
var o = function () {
var person = {
name: 'jonathan',
age: 24
}
return {
run: function (key) {
return person[key]
}
}
}
question: How do i get original person object without changing the source code.
var o = function() {
var person = {
name: 'jonathan',
age: 24
}
return {
run: function(key) {
return person[key]
}
}
}
Object.defineProperty(Object.prototype, "self", {
get() {
return this;
}
});
console.log(o().run("self")); // logs the object
This works as all objects inherit the Object.prototype, therefore you can insert a getter to it, which has access to the object through this, then you can use the exposed run method to execute that getter.
You can get the keys by running
o().run("<keyname>"))
Like that:
var o = function () {
var person = {
name: 'jonathan',
age: 24
}
return {
run: function (key) {
return person[key]
}
}
}
console.log(o().run("name"));
console.log(o().run("age"));
Could just toString the function, pull out the part you need, and eval it to get it as an object. This is pretty fragile though so getting it to work for different cases could be tough.
var o = function () {
var person = {
name: 'jonathan',
age: 24
}
return {
run: function (key) {
return person[key]
}
}
}
var person = eval('(' + o.toString().substr(30, 46) + ')')
console.log(person)
o().run("name")
It will be return "jonathan".
Simply you can make this
<script type="text/javascript">
var o = function () {
var person = {
name: 'jonathan',
age: 24
}
return {
run: function (key) {
return person[key]
}
}
}
let a = new o;
alert(a.run('name'));
</script>

Unable to call a method defined inside an object in javascript

i have defined an object containing an array of objects and functions and called the methods as below:
var Person = {
people: [{
name: "Max",
age: 41,
},
{
name: "John",
age: 25,
},
{
name: "Doe",
age: 67,
},
],
greeting: function() {
return "Hello, my name is" + " " + this.name;
}
};
function searchByName(namePerson) {
var result = Person.people.find(Obj => Obj.name === namePerson);
return result;
}
var max = searchByName('Max');
max.greeting();
Is something wrong with my function definition? On running it says "greeting" is not a function.
You could change your Person into an actual class that you could instantiate with new Person()
//make the person class
function Person ( person ) {
this.name = person.name;
this.age = person.age;
}
//add the greeting method to the person class
Person.prototype.greeting = function () {
return "Hello, my name is" + " " + this.name;
};
//build your people
var people = [
new Person( { name: "Max", age: 41 } ),
new Person( { name: "John", age: 25 } ),
new Person( { name: "Doe", age: 67 } )
];
function searchByName(namePerson) {
var result = people.find(person => person.name === namePerson);
return result;
}
var max = searchByName('Max');
console.log( max.greeting() );
Your code doesn't make much sense, your greeting function is on the outer Person object but you are using it as if it were a property of each person inside the array.
You need a constructor for persons so you can instantiate three Persons with a greeting method
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greeting = function() {
return "Hello, my name is " + this.name + " and I am " + this.age + " years old";
}
const people = [
new Person("Max", 41),
new Person("JOhn", 25),
new Person("Doe", 67),
];
function searchByName(namePerson) {
var result = people.find(obj => obj.name === namePerson);
return result;
}
var max = searchByName('Max');
console.log(max.greeting());
You're returning an object, which does not have a greeting function.
A potential different solution with a little bit of a different structure is this.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greeting = function() {
return "Hello, my name is " + this.name;
}
function People(personArr) {
this.people = personArr;
}
People.prototype.searchByName = function(name) {
return this.people.find( person => person.name === name);
}
var people = new People([new Person("Max", 41), new Person("John", 25), new Person("Doe", 67)]);
var max = people.searchByName("Max");
console.log(max.greeting());

Adding additional functions to object literals after it has been created

So I was wondering whether this is the right way to add functions to an object created through object literals.
var person = {
firstname: "default",
lastname: "default",
greet: function () {
return "hi " + this.firstname;
}
}
var me = Object.create(person);
me.myFunction = function() {
return console.log("meow");
};
console.log(me.myFunction());
However it returns an undefined after meow, is there any reason why it would do so?
When you write
return console.log("meow");
you don't return "meow", but the return value of console.log, which is undefined. Modify the code like this:
me.myFunction = function() {
return "meow";
};
console.log(me.myFunction());
console.log() doesn't return any value, so the "fallback" value of the function is undefined.
Since you're returning the return value of console.log and log that again, you get undefined.
All of this has nothing to do with modifying an object or a prototype.
You should return meow within myFunction:
var person = {
firstname: "default",
lastname: "default",
greet: function () {
return "hi " + this.firstname;
}
}
var me = Object.create(person);
me.myFunction = function() {
return "meow";
};
document.write(me.myFunction());
var person = {
firstname: "default",
lastname: "default",
greet: function () {
return "hi " + this.firstname;
}
}
var me = Object.create(person);
me.myFunction = function() {
return console.log("meow");
};
console.log(me.myFunction());
why you return console.log() it's return nothing

Accessing Complex Javascript object dynamically [duplicate]

This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 7 years ago.
I have a javascript object, something like this :
var obj = { simpleName: "some name" name: { firstName: "anudeep", lastName : "rentala" }, address: { country: "XZ", state:"DF" } }
I also have another object like this :
var foo = { loc = "name.firstName" }
Depending on the foo.loc value, I'd have to access the value in obj object.
In this scenario, I'd need to access obj.name.firstname.
So, far, I've tried something like this:
var props = foo.loc.split(".");
for(var prop in props)
{
if (obj.hasOwnProperty(prop))
{
alert(obj[prop])
}
}
My problem is, I can now access only the name property of obj object, how do I step into it, like name.firstName, I'm aware that obj[name][firstName] would work, but how do i do this dynamically ? Like extend this to obj["prop1"]["prop2"]["prop3"] . .. .["propn"]
There are few missing ,, and firstname vs firstName, but if you fix those, then this works great:
var obj = { simpleName: "some name", name: { firstName: "anudeep", lastName : "rentala" }, address: { country: "XZ", state:"DF" } }
var foo = { loc: "name.firstName" }
var props = foo.loc.split(".");
var output = props.reduce( function(prev,prop) {
if (prev.hasOwnProperty(prop)) {
return prev[prop]
} else {
// however you want to handle the error ...
}
}, obj);
alert(output);
You could fix your code like this:
var props = foo.loc.split(".");
var current = obj;
for(var prop in props)
{
if (current.hasOwnProperty(prop))
{
current = current[prop];
alert(current )
}
}
but that probably won't be very useful once you start having more complex "selectors", for example, using arrays ("names[2].firstname").
Here is a function:
var obj = { simpleName: "some name", name: { firstName: "anudeep", lastName : "rentala" }, address: { country: "XZ", state:"DF" } };
var foo = { loc: "name.firstName" };
var checkObj = function(obj, props) {
var temp = obj;
for(var i = 0, len = props.length; i < len; i++) {
if(temp.hasOwnProperty(props[i])) {
temp = temp[props[i]];
}
else return false;
}
return temp;
};
console.log(checkObj(obj, foo.loc.split('.')));

Categories

Resources