Reputation: 37909
This probably has a prior answer, but I haven't been able to find it.
I have some code that gets data from a database and returns an entity such as:
var customer1 = {first: "Greg", last: "Gum"};
How do I add a getter to this object so that I can call a FullName getter:
var theFullName = customer1.fullName;
What I don't understand is the difference between adding a getter to an object, and adding a getter to a "class" so that it becomes available to all future objects of that type. The thing is that the code that creates the object is a black box, so I don't really have access to that code. I don't know the best way to resolve this.
Upvotes: 3
Views: 759
Reputation: 14777
If you just want to define the property on the object literal that has been returned, simply use Object.defineProperty:
var cdata = {first: 'Foo', last: 'Bar'}
Object.defineProperty(cdata, 'fullName', {
get: function() { return this.first + ' ' + this.last; }
});
console.log(cdata.fullName); // Foo Bar
However, if you want to create a new object from the returned literal, one method would be:
function Customer(data) {
var k;
for (k of Object.keys(data)) {
Object.defineProperty(this, k, {
value: data[k]
});
}
Object.defineProperty(this, 'fullName', {
get: function() { return this.first + ' ' + this.last; }
});
}
var cdata = {first: 'Foo', last: 'Bar'};
var customer = new Customer(cdata);
console.log(customer.fullName); // Foo Bar
But a more memory efficient method is:
function Customer(data) {
var k;
for (k of Object.keys(data)) {
Object.defineProperty(this, k, {
value: data[k]
});
}
}
Customer.prototype = {
get fullName() {
return this.first + ' ' + this.last;
}
};
var cdata = {first: 'Foo', last: 'Bar'};
var customer = new Customer(cdata);
console.log(customer.fullName); // Foo Bar
The first Customer
definition adds an instance property fullName
which will consume memory for each instance of Customer
that is created. The second definition defines the fullName
property as a prototype property, thus saving a small amount of memory.
Upvotes: 7
Reputation: 35491
One way you can solve this is to create your own wrapper class Customer
that wraps the received object and adds the getter.
Furthermore, you want to add the getter on the prototype of your Costumer
class so that it is only defined once and available for all future instances. Something like:
function Customer(c) {
this.firstName = c.first;
this.lastName = c.last;
}
Customer.prototype.getFullName = function() {
return this.firstName + " " + this.lastName;
}
And you will use it like:
var c = getCustomerFromBlackBox();
var customer = new Customer(c);
If you are using ES6, then you can take advantage of its more robust syntax:
class Customer {
constructor(c) {
this.firstName = c.first;
this.lastName = c.last;
}
fullName() {
return this.firstName + " " + this.lastName;
}
}
Based on your comment that you want to edit the received object itself, well then you can do just that:
var c = getCustomerFromBlackBox();
if(typeof c === 'object' && c !== null) { // make sure c is an object
c.getFullName = function() { // add a getter
return this.first + " " + this.last;
}
}
Do note that this will add the getter code to every object you receive and thus will take more memory.
Also, since you don't know how this object is created, you might want to add checks to make sure first
and last
strings to actually exist and perhaps add specific values in case they don't.
EDIT:
Since you said in your comment that you know that your first
and last
names will never change, and that you want a property rather than a getter function, you can literally just add this property each time you read a customer:
var c = getCustomerFromBlackBox();
c.fullName = c.first + " " + c.last; // Can also add same checks to make sure c is an object and c.first and c.last are strings
Again, this is added to every object and has a similar memory overhead as adding a direct getter function (and not on the prototype)
A good approach that I missed is using Object.defineProperty as shown in James Sumner's answer.
Object.defineProperty(c, 'fullName', {
get: function() { return this.first + " " + this.last; }
});
This approach adds the property directly on the object (not the prototype) and additionally makes the property immutable meaning you cannot accidentally delete it.
Upvotes: 0
Reputation: 13211
EDIT: You are looking for this:
var customer1 = {first: "Greg", last: "Gum"};
Object.defineProperty(customer1, "fullName", {
get: function() { return this.first + ' ' + this.last; }
});
var theFullName = customer1.fullName;
A more general aproach:
function addGetter(obj, name, func) {
Object.defineProperty(obj, name, {
get: func
});
}
var customer1 = {first: "Greg", last: "Gum"};
addGetter(customer1, "fullName", function() { return this.first + ' ' + this.last; } )
var theFullName = customer1.fullName;
You could even protoype Object to do sth like customer1.getter("fullName", function() { return this.first + ' ' + this.last; } )
OLD: I have a nice way of doing it with TypeScript, it compiles to this JavaScript:
var Customer = (function () {
function Customer(first, last) {
this.first = first;
this.last = last;
}
Object.defineProperty(Customer.prototype, "fullName", {
get: function () { return this.first + " " + this.last; },
enumerable: true,
configurable: true
});
return Customer;
})();
var customer1 = new Customer("Greg", "Gum");
var theFullName = customer1.fullName;
However the TypeScript looks way nicer:
class Customer {
first: string
last: string
constructor(first: string, last: string) {
this.first = first
this.last = last
}
get fullName() { return this.first + " " + this.last }
}
var customer1 = new Customer("Greg", "Gum")
var theFullName = customer1.fullName
You can play with it here
Upvotes: 3
Reputation: 5061
You have to create a constructor to use prototypal inheritance in JavaScript.
E.g. like below. Check JS Fiddle.
var customer1Data = {first: "Greg", last: "Gum"};
var Customer = function(customerData ) {
this.first = customer1Data.first;
this.last = customer1Data.last;
}
Customer.prototype.fullName = function() {
return this.first + ' '+this.last;
}
var customer1 = new Customer(customer1Data );
Upvotes: 0