I want to add functions to JSON Objects, but I can't find function for assigning to all objects, only to one.
This code works with Arrays:
Object.defineProperty(Array.prototype, 'random', {
value: () => {
return this[Math.floor(Math.random() * this.length)];
},
});
I've also found this code:
const obj = {name: 'Bob'};
obj.fullName = function() { return this.name }
But that one only works for specific object, not all of them.
Is it event possible to write global functions for all JSON Objects, and if is, then how to do it?
You could add the function to Object.prototype. Note that this is not considered a very good practice because it could impact the rest of the code (like shown in the comments):
Object.prototype.fullName = function() { return this.name; };
const obj = { name: 'Bob' };
console.log(obj.fullName());
You should consider doing this instead:
const baseObject = { fullName: function() { return this.name; } };
const obj = Object.create(baseObject, { name: { value: 'Bob', writable: true } });
console.log(obj.fullName());
And if your target runtime (browser?) supports ECMAScript 6, you could also create a dedicated class for this:
class MyClass {
constructor(name) {
this.name = name;
}
fullName() { return this.name; }
}
const bob = new MyClass('Bob');
console.log(bob.fullName());
Finally, the class syntax for ECMAScript 5:
function MyClass(name) {
this.name = name;
}
MyClass.prototype.fullName = function() { return this.name; }
const bob = new MyClass('Bob');
console.log(bob.fullName());
Related
The JavaScript code below has a getter and setter for name using global symbols, and age_ using a dangling underscore.
JavaScript Code
function Human(name, age) {
this.name = name;
this.age_ = age;
}
Human.prototype.greet = function() {
console.log(`Hello ${this.name}! You are ${this.age} years old.`);
};
Human.prototype[Symbol.iterator] = function* () {
yield* Object.getOwnPropertyNames(this);
yield* Object.getOwnPropertySymbols(this);
};
Object.defineProperties(
Human.prototype,
{
name: {
get() {
return this[Symbol.for('name')];
},
set(value) {
this[Symbol.for('name')] = value;
},
},
age: {
get() {
return this.age_;
},
set(value) {
this.age_ = value;
},
},
},
);
let mary = new Human('Mary Smith', 18);
mary.greet();
console.dir(mary);
let john = new Human('John Doe', 25);
john.greet();
console.dir(john);
Console Output
I want to know is there any performance drawbacks to using global symbols for a getter and setter methods because I find it much cleaner code.
I am trying to achieve knockout observe computed behavior in vanila js
In react, you will have both these variables on state and compute the fullname
How can we achieve the same in vanila js
function person(firstname,lastname) {
this.firstname = firstname;
this.lastname = lastname;
this.fullName = `${this.firstname}${this.lastname}`
}
var person1 =new person("abc","k");
Object.defineProperty(person,'firstname',{
get: () => {
return person1['firstname'];
},
set: (name) => {
person1['firstname'] = name;
}
});
Object.defineProperty(person,'lastname',{
get: () => {
return person1['lastname'];
},
set: (name) => {
person1['lastname'] = name;
}
});
Object.defineProperty(person,'fullName',{
get: () => {
return `${person1['firstname']}-${person1['lastname']}`;
}
});
console.log(person1.firstname, "firstnmae");
person1.firstname ="sah";
console.log(person1.lastname, "lastname");
console.log(person1.fullName, "fullname");
Look at this code:
var person = {
firstname: 'abc',
lastname: 'k'
};
Object.defineProperty(person,'fullName',{
get: function() {
return `${this['firstname']}-${this['lastname']}`;
}
});
var person1 = Object.create( person );
console.log(person1.firstname, "firstnmae");
person1.firstname ="sah";
console.log(person1.lastname, "lastname");
console.log(person1.fullName, "fullname");
there's no need defining firstname and lastname by .defineProperty because those setter and getter will work by default as you wrote them.
you should use this syntax, as it's easier to read/maintain afterward, otherwise, if you would like to stick to that constructor syntax, here you go:
var person = function() {};
Object.defineProperty(person,'firstname',{
value: 'abc',
writable: true
});
Object.defineProperty(person,'lastname',{
value: 'k',
writable: true
});
Object.defineProperty(person,'fullName',{
get: function() {
return `${this['firstname']}-${this['lastname']}`;
}
});
var person1 = Object.create( person );
console.log(person1.firstname, "firstnmae");
person1.firstname ="sah";
console.log(person1.lastname, "lastname");
console.log(person1.fullName, "fullname");
I think you need more investigation about Object.create() and MDN is the best place.
arrow-functions have lexical this, be careful!
this syntax maybe clarifies some points about Object.create() for you:
var person = function() {};
person.prototype.firstname = 'abc';
person.prototype.lastname = 'k';
Object.defineProperty(person.prototype,'fullName',{
get: function() {
return `${this['firstname']}-${this['lastname']}`;
}
});
var person1 = Object.create( person.prototype );
console.log(person1.firstname, "firstnmae");
person1.firstname ="sah";
console.log(person1.lastname, "lastname");
console.log(person1.fullName, "fullname");
Iām transforming data I receive from an API. The frontend requires some calculations to be displayed.
What is the proper way to handle the data transformation?
Should I be defining a property to the object being passed? If so, why
Is this a good use case to use setters and getters or would that be unnecessary?
const dogData = {
dog_name: "filo",
born_time: 1530983852,
coat_color: "brown"
};
class Dog {
constructor(data) {
//do I need to set this.dog to the data object, what's the benefit of doing so?
this.dog = data;
this.name = this.dog.dog_name;
// vs
this.name = data.dog_name;
//Should I use setters and getters?
this.color = this.dog.coat_color;
// vs
this._color = this.dog.coat_color;
this.age = this.calculateAge();
}
calculateAge() {
return Date.now().getTime() - this.dog.born_time;
}
//Is this a good case where I should using getters to access the properties or would that be superfluous?
//should I be setting the properties with setters in this case?
get color() {
return this._color;
}
}
const dog = new Dog(dogData)
Your don't need to make a copy of data into your class.
You can assign the class fields directly (using object destructuring to be more readable).
const data = {
dog_name: 'filo',
born_time: 1530983852,
coat_color: 'brown'
}
class Dog {
// Directly assign values
constructor({ dog_name, born_time, coat_color }) {
this.name = dog_name
this.bornAt = born_time
this.color = coat_color
}
// Getter for computed properties
get age() {
return Date.now() - this.bornAt
}
}
const dog = new Dog(data)
Getters are needed only for computed property (dynamic or formatted values).
Good exemple:
class Person {
constructor({ firstname, lastname }) {
this.firstname = firstname
this.lastname = lastname
}
get fullname() {
return `${this.firstname} ${this.lastname}`
}
}
class Dog {
constructor(data) {
const {
dog_name: name,
born_time: age,
coat_color: color
} = data;
Object.assign(this, {
name,
age,
color
});
}
}
const dogData = {
dog_name: "filo",
born_time: 1530983852,
coat_color: "brown"
};
const dog = new Dog(dogData);
console.log(dog.name);
Q:
Shall I nevertheless throw in a possible read only approach? ā Peter Seliger
A:
It wouldn't hurt. I appreciate the different approaches. ā Matthew Moran
... here we go ...
// module start ... e.g. file: "Dog.js"
// locally scoped helper function
function calculateAge(dateOfBirth) {
return (Date.now() - dateOfBirth);
}
/*export default */class Dog {
constructor(initialValue) {
Object.defineProperties(this, {
valueOf: { // just in order to hint what `initialValue` might still be good for.
value: function () {
return Object.assign({}, initialValue);
}
},
name: {
value: initialValue.dog_name,
enumerable: true
},
color: {
value: initialValue.coat_color,
enumerable: true
},
age: {
get() {
return calculateAge(initialValue.born_time);
},
enumerable: true,
}
});
}
}
// module end.
// test
const dogData = {
dog_name: "filo",
born_time: 1530983852,
coat_color: "brown"
};
const dog = new Dog(dogData);
console.log('Object.keys(dog) : ', Object.keys(dog));
console.log('dog.valueOf() : ', dog.valueOf());
console.log('dog.age : ', dog.age);
console.log('dog.name : ', dog.name);
console.log('dog.color : ', dog.color);
console.log('(dog.age = 298146912) : ', (dog.age = 298146912) && dog.age);
console.log('(dog.name = "spot") : ', (dog.name = "spot") && dog.name);
console.log('(dog.color = "black") : ', (dog.color = "black") && dog.color);
.as-console-wrapper { max-height: 100%!important; top: 0; }
var Person = {
name: "jana",
getName: function(callBack) {
callBack();
console.log("** "+this.name);
}
}
var anotherPerson = { name: "prabu"}
I have 2 objects. I need "anotherPerson" to be bound with the Person object. Also, I want to send parameter as a function.
I have tried below methods, but its not working
Person.getName.apply(anotherPerson, function(){})
Person.getName.apply(anotherPerson)(function(){})
Use call to pass an arbitrary number of arguments to your function, or apply to pass an array of arguments:
var Person = {
name: "jana",
getName: function(callBack) {
callBack();
console.log("** " + this.name);
}
}
var anotherPerson = {
name: "prabu"
}
Person.getName.call(anotherPerson, function () {})
Person.getName.apply(anotherPerson, [function () {}])
Have you tried Object.assign ? Like so
var Person = {
name: "jana",
getName: function(callBack) {
callBack();
console.log("** " + this.name);
}
}
var anotherPerson = {
name: "prabu"
}
Object.assign(Person, anotherPerson).getName(alert)
You can use arrow function and return the name parameter to assign value to getName.
var Person = {
name: "jana",
getName: (obj) =>obj.name
}
var anotherPerson = {
name: "prabu"
}
Person.getName(anotherPerson);
console.log(Person);
How do I get access to the properties or method of the main object, from sub-obiect level two (sub3). If possible I would like to avoid solutions chaining return this.
Obj = function () {};
Obj.prototype = {
name: 'name',
main: function(){
console.log(this.name);
},
subobject: {
sub2: function () {
console.log(this);
},
sub3: function () {
console.log(this.name); // How access to Obj.name ??
}
}
}
o = new Obj();
o.main(); // return name
o.subobject.sub2(); // return subobject
o.subobject.sub3(); // return undefined
With your current syntax, you can't. Because for sub2 and sub3, the this variable is Obj.prototype.subobject.
You have multiple choice:
The obvious one: don't use a suboject.
Create subobject, sub2 and sub3 in the constructor
Obj = function() {
var self = this;
this.subobject = {
sub1: function() { console.log(self); }
}
}
Use bind at each call:
o.subobject.sub2.bind(o)();