In Javascript, it seems like using property accessors is not all that common (unlike in other OO languages such as Java for example).
If I have a Person object with a name, defined as
function Person(name) {
this.name = name;
}
A person's name is not going to change, but I do want to be able to access it when needed, so I could do something like:
function Person(name) {
var name = name;
this.getName = function() {
return name;
}
}
Even in a dynamic language, I think the principles of using getters and setters apply the same way they do to statically typed OO languages (e.g. encapsulation, adding validation, restricting access, etc)
This question may get closed as subjective, but I'm curious as to why this behavior doesn't appear more often (e.g. Java developers would go crazy if everything was public).
Is there a "standard" way to do this in javascript? I've seen Object.defineProperty, but not all browsers support that.
Javascript has intercept-able property accessors:
http://ejohn.org/blog/javascript-getters-and-setters/
IMHO this is a far better solution to enforce the Uniform Access Principle than Java's more strict explicit getters, but that is also part of the simplicity and inflexibility of that language (Groovy for instance allows for similar interception).
I know my thoughts on the subject.
Getters and setters are evil.
Wait! Really! Bear with me a moment and let me explain.
Just using a method to get and set a value is .. well .. kinda pointless. It doesn't protect, not really, and what you put in is what you get out.
On the other hand, I'm rather fond of methods that put information in, then get information back out. BUT here is the magic part! It isn't the same information. Not directly.
function Person(name) {
this.getFullName = function() {return this.firstName + " " + this.lastName;};
this.setBirthday = function(date) { this.birthday = date; };
this.getAge = function() { /* Return age based on the birthday */ };
this.isOfLegalDrinkingAge function() { /* do your math here too */ };
}
But most of the time I'm just shoving static data in and getting static data out. What is the point of hiding it behind getters and setters?
As a secondary reason, dealing with the DOM and most host objects, you set properties. You don't play with getters and setters. Not using them fits the rest of the 'flavor' of what JS coders do.
I think the answer is that emulating classes in javascript is not the common practice, because the language is actually prototypal.
Although it is possible to create class like structures (as in your example), they are not really like java classes, and as a programmer, you end up fighting with the nuances.
If however, you embrace the prototypal nature of javascript, you are rewarded by a different, yet cohesive, and simple structure for the language.
It is not necessary to use getters and setters with prototypal structure, as you can simply set an object by, well, setting it to a value, and get it by, calling it as a value.
Javascript does not force you to write structured code, and does not stop you from doing so. I think the culture that has grown up around javascript has developed a good coding style, that is perfectly valid, and different from any other language I use.
I know this answer is not definitive, and conclusive, but hopefully there are some ideas in there that help you to find the anser you are looking for.
I apologize if I dont understand the question correctly, but self executing functions are one way to make members public/private
var Person = function(){
var _name = "Roger",
self = { getName : function (){ return _name; }};
return self;
}()
You can then access Person.getName() from anywhere , but not set _name.
This is what I used for local fields:
TYPE_DEFAULT_VALUE= {
number: 0,
string: "",
array: [],
object: {},
};
typeOf = function (object) {
if (typeof object === "number" && isNaN(object))
return NaN;
try {
return Object.prototype.toString.call(object).slice(8, -1).toLowerCase();
}
catch(ex) {
return "N/A";
};
};
getAccessor = function(obj, key, type, defaultValue) {
if (defaultValue === undefined)
defaultValue = TYPE_DEFAULT_VALUE[type] === undefined ? null : TYPE_DEFAULT_VALUE[type];
return {
enumerable: true,
configurable: true,
get: function () {
if (obj[key] === undefined)
obj[key] = defaultValue;
return obj[key];
},
set: function (value) {
if (typeOf(value) === type)
obj[key] = value;
},
};
}
LocalFields = function (fields, object) {
/**
* field properties
* {
* type: [ required ] ( number | string | array | object | ... ),
* defaultValue: [ optional ]
* }
*/
if (! fields)
throw "Too few parameters ...";
if (! object)
object = this;
var obj = this;
var fieldsAccessor = {};
for(key in fields){
field = fields[key];
fieldHandler = key[0].toUpperCase() + key.substr(1);
if(! field.type)
throw "Type not set for field: " + key;
fieldsAccessor[fieldHandler] = getAccessor(obj, fieldHandler, field.type, field.defaultValue)
}
Object.defineProperties(object, fieldsAccessor);
}
Now for each Class I can just call something like:
Person = function(){
new LocalFields({
id: { type: "number" },
name: { type: "string" },
}, this);
}
And then like VS getter and setter you'll call:
var alex = new Person();
alex.Name = "Alex Ramsi";
console.clear();
console.info(alex.Name);
Related
I've been trying to get my head around getters and setters and its not sinking in. I've read JavaScript Getters and Setters and Defining Getters and Setters and just not getting it.
Can someone clearly state:
What a getter and setter are meant to do, and
Give some VERY simple examples?
In addition to #millimoose's answer, setters can also be used to update other values.
function Name(first, last) {
this.first = first;
this.last = last;
}
Name.prototype = {
get fullName() {
return this.first + " " + this.last;
},
set fullName(name) {
var names = name.split(" ");
this.first = names[0];
this.last = names[1];
}
};
Now, you can set fullName, and first and last will be updated and vice versa.
n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"
Getters and Setters in JavaScript
Overview
Getters and setters in JavaScript are used for defining computed properties, or accessors. A computed property is one that uses a function to get or set an object value. The basic theory is doing something like this:
var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'
This is useful for automatically doing things behind-the-scenes when a property is accessed, like keeping numbers in range, reformatting strings, triggering value-has-changed events, updating relational data, providing access to private properties, and more.
The examples below show the basic syntax, though they simply get and set the internal object value without doing anything special. In real-world cases you would modify the input and/or output value to suit your needs, as noted above.
get/set Keywords
ECMAScript 5 supports get and set keywords for defining computed properties. They work with all modern browsers except IE 8 and below.
var foo = {
bar : 123,
get bar(){ return bar; },
set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;
Custom Getters and Setters
get and set aren't reserved words, so they can be overloaded to create your own custom, cross-browser computed property functions. This will work in any browser.
var foo = {
_bar : 123,
get : function( name ){ return this[ '_' + name ]; },
set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );
Or for a more compact approach, a single function may be used.
var foo = {
_bar : 123,
value : function( name /*, value */ ){
if( arguments.length < 2 ){ return this[ '_' + name ]; }
this[ '_' + name ] = value;
}
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );
Avoid doing something like this, which can lead to code bloat.
var foo = {
_a : 123, _b : 456, _c : 789,
getA : function(){ return this._a; },
getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};
For the above examples, the internal property names are abstracted with an underscore in order to discourage users from simply doing foo.bar vs. foo.get( 'bar' ) and getting an "uncooked" value. You can use conditional code to do different things depending on the name of the property being accessed (via the name parameter).
Object.defineProperty()
Using Object.defineProperty() is another way to add getters and setters, and can be used on objects after they're defined. It can also be used to set configurable and enumerable behaviors. This syntax also works with IE 8, but unfortunately only on DOM objects.
var foo = { _bar : 123 };
Object.defineProperty( foo, 'bar', {
get : function(){ return this._bar; },
set : function( value ){ this._bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;
__defineGetter__()
Finally, __defineGetter__() is another option. It's deprecated, but still widely used around the web and thus unlikely to disappear anytime soon. It works on all browsers except IE 10 and below. Though the other options also work well on non-IE, so this one isn't that useful.
var foo = { _bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this._bar; } );
foo.__defineSetter__( 'bar', function( value ){ this._bar = value; } );
Also worth noting is that in the latter examples, the internal names must be different than the accessor names to avoid recursion (ie, foo.bar calling foo.get(bar) calling foo.bar calling foo.get(bar)...).
See Also
MDN get, set,
Object.defineProperty(), __defineGetter__(), __defineSetter__()
MSDN
IE8 Getter Support
You'd use them for instance to implement computed properties.
For example:
function Circle(radius) {
this.radius = radius;
}
Object.defineProperty(Circle.prototype, 'circumference', {
get: function() { return 2*Math.PI*this.radius; }
});
Object.defineProperty(Circle.prototype, 'area', {
get: function() { return Math.PI*this.radius*this.radius; }
});
c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832
(CodePen)
Sorry to resurrect an old question, but I thought I might contribute a couple of very basic examples and for-dummies explanations. None of the other answers posted thusfar illustrate syntax like the MDN guide's first example, which is about as basic as one can get.
Getter:
var settings = {
firstname: 'John',
lastname: 'Smith',
get fullname() { return this.firstname + ' ' + this.lastname; }
};
console.log(settings.fullname);
... will log John Smith, of course. A getter behaves like a variable object property, but offers the flexibility of a function to calculate its returned value on the fly. It's basically a fancy way to create a function that doesn't require () when calling.
Setter:
var address = {
set raw(what) {
var loc = what.split(/\s*;\s*/),
area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);
this.street = loc[0];
this.city = area[0];
this.state = area[1];
this.zip = area[2];
}
};
address.raw = '123 Lexington Ave; New York NY 10001';
console.log(address.city);
... will log New York to the console. Like getters, setters are called with the same syntax as setting an object property's value, but are yet another fancy way to call a function without ().
See this jsfiddle for a more thorough, perhaps more practical example. Passing values into the object's setter triggers the creation or population of other object items. Specifically, in the jsfiddle example, passing an array of numbers prompts the setter to calculate mean, median, mode, and range; then sets object properties for each result.
Getters and setters really only make sense when you have private properties of classes. Since Javascript doesn't really have private class properties as you would normally think of from Object Oriented Languages, it can be hard to understand. Here is one example of a private counter object. The nice thing about this object is that the internal variable "count" cannot be accessed from outside the object.
var counter = function() {
var count = 0;
this.inc = function() {
count++;
};
this.getCount = function() {
return count;
};
};
var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());
If you are still confused, take a look at Crockford's article on Private Members in Javascript.
I think the first article you link to states it pretty clearly:
The obvious advantage to writing JavaScript in this manner is that you can use it obscure values that you don't want the user to directly access.
The goal here is to encapsulate and abstract away the fields by only allowing access to them thru a get() or set() method. This way, you can store the field/data internally in whichever way you want, but outside components are only away of your published interface. This allows you to make internal changes without changing external interfaces, to do some validation or error-checking within the set() method, etc.
Although often we are used to seeing objects with public properties without any access
control, JavaScript allows us to accurately describe properties. In fact, we can use
descriptors in order to control how a property can be accessed and which logic we can
apply to it. Consider the following example:
var employee = {
first: "Boris",
last: "Sergeev",
get fullName() {
return this.first + " " + this.last;
},
set fullName(value) {
var parts = value.toString().split(" ");
this.first = parts[0] || "";
this.last = parts[1] || "";
},
email: "boris.sergeev#example.com"
};
The final result:
console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";
console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko
You can define instance method for js class, via prototype of the constructor.
Following is the sample code:
// BaseClass
var BaseClass = function(name) {
// instance property
this.name = name;
};
// instance method
BaseClass.prototype.getName = function() {
return this.name;
};
BaseClass.prototype.setName = function(name) {
return this.name = name;
};
// test - start
function test() {
var b1 = new BaseClass("b1");
var b2 = new BaseClass("b2");
console.log(b1.getName());
console.log(b2.getName());
b1.setName("b1_new");
console.log(b1.getName());
console.log(b2.getName());
}
test();
// test - end
And, this should work for any browser, you can also simply use nodejs to run this code.
If you're referring to the concept of accessors, then the simple goal is to hide the underlying storage from arbitrary manipulation. The most extreme mechanism for this is
function Foo(someValue) {
this.getValue = function() { return someValue; }
return this;
}
var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
* to modify it -- hurrah, we have achieved encapsulation!
*/
myFoo.getValue();
If you're referring to the actual JS getter/setter feature, eg. defineGetter/defineSetter, or { get Foo() { /* code */ } }, then it's worth noting that in most modern engines subsequent usage of those properties will be much much slower than it would otherwise be. eg. compare performance of
var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.getValue();
vs.
var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.value;
What's so confusing about it... getters are functions that are called when you get a property, setters, when you set it.
example, if you do
obj.prop = "abc";
You're setting the property prop, if you're using getters/setters, then the setter function will be called, with "abc" as an argument.
The setter function definition inside the object would ideally look something like this:
set prop(var) {
// do stuff with var...
}
I'm not sure how well that is implemented across browsers. It seems Firefox also has an alternative syntax, with double-underscored special ("magic") methods. As usual Internet Explorer does not support any of this.
I was also somewhat confused by the explanation I read, because I was trying to add a property to an existing prototype that I did not write, so replacing the prototype seemed like the wrong approach. So, for posterity, here's how I added a last property to Array:
Object.defineProperty(Array.prototype, "last", {
get: function() { return this[this.length - 1] }
});
Ever so slightly nicer than adding a function IMHO.
You can also use __defineGetter__:
function Vector2(x,y) {
this.x = x;
this.y = y;
}
Vector2.prototype.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});
console.log(new Vector2(1,1).magnitude)
Or, if you prefer:
function Vector2(x,y) {
this.x = x;
this.y = y;
this.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});
}
console.log(new Vector2(1,1).magnitude)
But this function has been flagged as "legacy" recently, being dropped in favor of Object.defineProperty().
There's no example here with ES6 class (which is not even 'new' now, it's the norm):
class Student {
contructor(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
this.secretId = Math.random()
}
get fullName() {
return `${this.firstName} ${this.lastName}`; // this is backtick in js, u can check it out here: https://stackoverflow.com/a/27678299/12056841
}
set firstName(newFirstName) {
// validate that newFirstName is a string (and maybe limit length)
this.firstName = newFirstName
}
get studentId() { return this.secretId }
}
and no setter for secretId because we don't want anyone to change it.
** if secretId shouldn't be changed at all, a nice approach is to declare it as 'private' to this class by adding a '#' to it
(e.g: this.#secretId = Math.random(), and return this.#secretId
Update: about backing fields
You might need to rename your field - or your setter function but it makes more sense to me to change your field name. One option is like I mentioned above (using a # for declaring the field as 'private'). Another way is to just rename it (_firstName, firstName_...)
I've got one for you guys that might be a little ugly, but it does get'er done across platforms
function myFunc () {
var _myAttribute = "default";
this.myAttribute = function() {
if (arguments.length > 0) _myAttribute = arguments[0];
return _myAttribute;
}
}
this way, when you call
var test = new myFunc();
test.myAttribute(); //-> "default"
test.myAttribute("ok"); //-> "ok"
test.myAttribute(); //-> "ok"
If you really want to spice things up.. you can insert a typeof check:
if (arguments.length > 0 && typeof arguments[0] == "boolean") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "number") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "string") _myAttribute = arguments[0];
or go even crazier with the advanced typeof check: type.of() code at codingforums.com
I've been trying to get my head around getters and setters and its not sinking in. I've read JavaScript Getters and Setters and Defining Getters and Setters and just not getting it.
Can someone clearly state:
What a getter and setter are meant to do, and
Give some VERY simple examples?
In addition to #millimoose's answer, setters can also be used to update other values.
function Name(first, last) {
this.first = first;
this.last = last;
}
Name.prototype = {
get fullName() {
return this.first + " " + this.last;
},
set fullName(name) {
var names = name.split(" ");
this.first = names[0];
this.last = names[1];
}
};
Now, you can set fullName, and first and last will be updated and vice versa.
n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"
Getters and Setters in JavaScript
Overview
Getters and setters in JavaScript are used for defining computed properties, or accessors. A computed property is one that uses a function to get or set an object value. The basic theory is doing something like this:
var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'
This is useful for automatically doing things behind-the-scenes when a property is accessed, like keeping numbers in range, reformatting strings, triggering value-has-changed events, updating relational data, providing access to private properties, and more.
The examples below show the basic syntax, though they simply get and set the internal object value without doing anything special. In real-world cases you would modify the input and/or output value to suit your needs, as noted above.
get/set Keywords
ECMAScript 5 supports get and set keywords for defining computed properties. They work with all modern browsers except IE 8 and below.
var foo = {
bar : 123,
get bar(){ return bar; },
set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;
Custom Getters and Setters
get and set aren't reserved words, so they can be overloaded to create your own custom, cross-browser computed property functions. This will work in any browser.
var foo = {
_bar : 123,
get : function( name ){ return this[ '_' + name ]; },
set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );
Or for a more compact approach, a single function may be used.
var foo = {
_bar : 123,
value : function( name /*, value */ ){
if( arguments.length < 2 ){ return this[ '_' + name ]; }
this[ '_' + name ] = value;
}
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );
Avoid doing something like this, which can lead to code bloat.
var foo = {
_a : 123, _b : 456, _c : 789,
getA : function(){ return this._a; },
getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};
For the above examples, the internal property names are abstracted with an underscore in order to discourage users from simply doing foo.bar vs. foo.get( 'bar' ) and getting an "uncooked" value. You can use conditional code to do different things depending on the name of the property being accessed (via the name parameter).
Object.defineProperty()
Using Object.defineProperty() is another way to add getters and setters, and can be used on objects after they're defined. It can also be used to set configurable and enumerable behaviors. This syntax also works with IE 8, but unfortunately only on DOM objects.
var foo = { _bar : 123 };
Object.defineProperty( foo, 'bar', {
get : function(){ return this._bar; },
set : function( value ){ this._bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;
__defineGetter__()
Finally, __defineGetter__() is another option. It's deprecated, but still widely used around the web and thus unlikely to disappear anytime soon. It works on all browsers except IE 10 and below. Though the other options also work well on non-IE, so this one isn't that useful.
var foo = { _bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this._bar; } );
foo.__defineSetter__( 'bar', function( value ){ this._bar = value; } );
Also worth noting is that in the latter examples, the internal names must be different than the accessor names to avoid recursion (ie, foo.bar calling foo.get(bar) calling foo.bar calling foo.get(bar)...).
See Also
MDN get, set,
Object.defineProperty(), __defineGetter__(), __defineSetter__()
MSDN
IE8 Getter Support
You'd use them for instance to implement computed properties.
For example:
function Circle(radius) {
this.radius = radius;
}
Object.defineProperty(Circle.prototype, 'circumference', {
get: function() { return 2*Math.PI*this.radius; }
});
Object.defineProperty(Circle.prototype, 'area', {
get: function() { return Math.PI*this.radius*this.radius; }
});
c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832
(CodePen)
Sorry to resurrect an old question, but I thought I might contribute a couple of very basic examples and for-dummies explanations. None of the other answers posted thusfar illustrate syntax like the MDN guide's first example, which is about as basic as one can get.
Getter:
var settings = {
firstname: 'John',
lastname: 'Smith',
get fullname() { return this.firstname + ' ' + this.lastname; }
};
console.log(settings.fullname);
... will log John Smith, of course. A getter behaves like a variable object property, but offers the flexibility of a function to calculate its returned value on the fly. It's basically a fancy way to create a function that doesn't require () when calling.
Setter:
var address = {
set raw(what) {
var loc = what.split(/\s*;\s*/),
area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);
this.street = loc[0];
this.city = area[0];
this.state = area[1];
this.zip = area[2];
}
};
address.raw = '123 Lexington Ave; New York NY 10001';
console.log(address.city);
... will log New York to the console. Like getters, setters are called with the same syntax as setting an object property's value, but are yet another fancy way to call a function without ().
See this jsfiddle for a more thorough, perhaps more practical example. Passing values into the object's setter triggers the creation or population of other object items. Specifically, in the jsfiddle example, passing an array of numbers prompts the setter to calculate mean, median, mode, and range; then sets object properties for each result.
Getters and setters really only make sense when you have private properties of classes. Since Javascript doesn't really have private class properties as you would normally think of from Object Oriented Languages, it can be hard to understand. Here is one example of a private counter object. The nice thing about this object is that the internal variable "count" cannot be accessed from outside the object.
var counter = function() {
var count = 0;
this.inc = function() {
count++;
};
this.getCount = function() {
return count;
};
};
var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());
If you are still confused, take a look at Crockford's article on Private Members in Javascript.
I think the first article you link to states it pretty clearly:
The obvious advantage to writing JavaScript in this manner is that you can use it obscure values that you don't want the user to directly access.
The goal here is to encapsulate and abstract away the fields by only allowing access to them thru a get() or set() method. This way, you can store the field/data internally in whichever way you want, but outside components are only away of your published interface. This allows you to make internal changes without changing external interfaces, to do some validation or error-checking within the set() method, etc.
Although often we are used to seeing objects with public properties without any access
control, JavaScript allows us to accurately describe properties. In fact, we can use
descriptors in order to control how a property can be accessed and which logic we can
apply to it. Consider the following example:
var employee = {
first: "Boris",
last: "Sergeev",
get fullName() {
return this.first + " " + this.last;
},
set fullName(value) {
var parts = value.toString().split(" ");
this.first = parts[0] || "";
this.last = parts[1] || "";
},
email: "boris.sergeev#example.com"
};
The final result:
console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";
console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko
You can define instance method for js class, via prototype of the constructor.
Following is the sample code:
// BaseClass
var BaseClass = function(name) {
// instance property
this.name = name;
};
// instance method
BaseClass.prototype.getName = function() {
return this.name;
};
BaseClass.prototype.setName = function(name) {
return this.name = name;
};
// test - start
function test() {
var b1 = new BaseClass("b1");
var b2 = new BaseClass("b2");
console.log(b1.getName());
console.log(b2.getName());
b1.setName("b1_new");
console.log(b1.getName());
console.log(b2.getName());
}
test();
// test - end
And, this should work for any browser, you can also simply use nodejs to run this code.
If you're referring to the concept of accessors, then the simple goal is to hide the underlying storage from arbitrary manipulation. The most extreme mechanism for this is
function Foo(someValue) {
this.getValue = function() { return someValue; }
return this;
}
var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
* to modify it -- hurrah, we have achieved encapsulation!
*/
myFoo.getValue();
If you're referring to the actual JS getter/setter feature, eg. defineGetter/defineSetter, or { get Foo() { /* code */ } }, then it's worth noting that in most modern engines subsequent usage of those properties will be much much slower than it would otherwise be. eg. compare performance of
var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.getValue();
vs.
var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.value;
What's so confusing about it... getters are functions that are called when you get a property, setters, when you set it.
example, if you do
obj.prop = "abc";
You're setting the property prop, if you're using getters/setters, then the setter function will be called, with "abc" as an argument.
The setter function definition inside the object would ideally look something like this:
set prop(var) {
// do stuff with var...
}
I'm not sure how well that is implemented across browsers. It seems Firefox also has an alternative syntax, with double-underscored special ("magic") methods. As usual Internet Explorer does not support any of this.
I was also somewhat confused by the explanation I read, because I was trying to add a property to an existing prototype that I did not write, so replacing the prototype seemed like the wrong approach. So, for posterity, here's how I added a last property to Array:
Object.defineProperty(Array.prototype, "last", {
get: function() { return this[this.length - 1] }
});
Ever so slightly nicer than adding a function IMHO.
You can also use __defineGetter__:
function Vector2(x,y) {
this.x = x;
this.y = y;
}
Vector2.prototype.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});
console.log(new Vector2(1,1).magnitude)
Or, if you prefer:
function Vector2(x,y) {
this.x = x;
this.y = y;
this.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});
}
console.log(new Vector2(1,1).magnitude)
But this function has been flagged as "legacy" recently, being dropped in favor of Object.defineProperty().
There's no example here with ES6 class (which is not even 'new' now, it's the norm):
class Student {
contructor(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
this.secretId = Math.random()
}
get fullName() {
return `${this.firstName} ${this.lastName}`; // this is backtick in js, u can check it out here: https://stackoverflow.com/a/27678299/12056841
}
set firstName(newFirstName) {
// validate that newFirstName is a string (and maybe limit length)
this.firstName = newFirstName
}
get studentId() { return this.secretId }
}
and no setter for secretId because we don't want anyone to change it.
** if secretId shouldn't be changed at all, a nice approach is to declare it as 'private' to this class by adding a '#' to it
(e.g: this.#secretId = Math.random(), and return this.#secretId
Update: about backing fields
You might need to rename your field - or your setter function but it makes more sense to me to change your field name. One option is like I mentioned above (using a # for declaring the field as 'private'). Another way is to just rename it (_firstName, firstName_...)
I've got one for you guys that might be a little ugly, but it does get'er done across platforms
function myFunc () {
var _myAttribute = "default";
this.myAttribute = function() {
if (arguments.length > 0) _myAttribute = arguments[0];
return _myAttribute;
}
}
this way, when you call
var test = new myFunc();
test.myAttribute(); //-> "default"
test.myAttribute("ok"); //-> "ok"
test.myAttribute(); //-> "ok"
If you really want to spice things up.. you can insert a typeof check:
if (arguments.length > 0 && typeof arguments[0] == "boolean") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "number") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "string") _myAttribute = arguments[0];
or go even crazier with the advanced typeof check: type.of() code at codingforums.com
What is the best-practice to validate and/or preprocess a property before assigning it to an object in JavaScript?
The application for that would be to create an object and to guarantee that a specific property of it will always have a specific type or maybe do some preprocessing with it.
For example, if I create an object:
var obj = {
settings: {}
};
Then when I do something like:
obj.settings = "{foo: bar}";
It would automatically check the type of the assignment - if it is a string, it will try to parse it to an object; if it's an object, it will just assign it; else it will throw an error. This would protect the object's property against being assigned to "anything".
Also, does this make sense at all to do in JavaScript or am I just trying to have strong typed features in a language that is weak typed?
You can do this with Object.defineProperty:
var obj = {}
Object.defineProperty(obj, 'settings', {
set: function (x) {
if (typeof x === 'string') {
this._settings = JSON.parse(x)
} else {
this._settings = x
}
},
get: function () {
return this._settings
}
})
obj.settings = {foo: 'bar'}
console.log(obj.settings)
obj.settings = '{foo: "baz"}'
console.log(obj.settings)
However, if this is desirable depends on your specific use case. I frankly never used it so far. My recommendation is: don't get fancy :)
IMHO this is not strong typing, but the opposite as you are more dynamic. If you want strong typing you could try flow or TypeScript
A simple solution could be to use a getter/setter like below that gets triggered if a value is assigned to a property and how to process it :
let obj = {}
Object.defineProperty(obj, "settings", {
set: function (value) { // preprocess
this._value = value;
},
get: function () {
return "changed";
}
});
You could do this afterward:
obj.settings = "{foo: bar}";
Let me know if this makes any sense.
Reference:
MDN Reference: Object.defineProperty()
Coming from C#/PHP, I would like to have full getters/setters on the classes (functions) that I create with Javascript.
However, in much of the Javascript code I have encountered, getters and setters are not used, rather simple public variables.
I was pleased to find John Resig's article on getters and setters, but some comments on it which state that some browsers "do not support getters and setters" which is confusing to me since they are not a "feature" of Javascript but more of a simple pattern which uses basic Javascript syntax. This article was also written in 2007 so it could be outdated by now.
What is the current state of getters and setters in Javascript? Are they indeed "supported" by all browsers today (whatever that means)? Are they a useful programming pattern for Javascript or are Javascript classes (being functions) better off with public variables? Is there a better way to implement them than the following?
$(document).ready(function() {
var module = new Module('idcode');
module.set_id_code('new idcode');
module.set_title('new title');
$('body').html(module.get_id_code()+': '+module.get_title());
});
function Module(id_code, title) {
var id_code = id_code;
var title = title;
//id_code
this.get_id_code = function() {
return id_code;
}
this.set_id_code = function(value) {
id_code = value;
}
//title
this.get_title = function() {
return title;
}
this.set_title = function(value) {
title = value;
}
}
Firefox, Safari, Chrome and Opera (but not IE) all have the same non-standard getter and setter mechanism built in. ECMAScript 5 includes a different syntax that is currently making its way into browsers and will become the standard in future. IE 8 already has this feature, but only on DOM nodes, not regular native JavaScript objects. This is what the syntax looks like:
var obj = {};
Object.defineProperty(obj, "value", {
get: function () {
return this.val;
},
set: function(val) {
this.val = val;
}
});
You're missing the point, I think. (Or maybe the other answerers are missing the point.) ECMAScript provides a "behind-the-scenes" getter/setter mechanism, so that
x.foo = 3;
y = x.foo;
really translates into (sort of)
x.PutValue("foo",3);
y = x.GetValue("foo");
where PutValue and GetValue are unnamed, not directly accessible functions for setters and getters for properties. (See the ECMAScript standard, 3rd ed., section 8.7.1. and 8.7.2) The 3rd edition doesn't seem to explicitly define how users can set up custom getters and setter functions. Mozilla's implementation of Javascript did and still does, e.g. (this is in JSDB which uses Javascript 1.8):
js>x = {counter: 0};
[object Object]
js>x.__defineGetter__("foo", function() {return this.counter++; });
js>x.foo
0
js>x.foo
1
js>x.foo
2
js>x.foo
3
js>x.foo
4
The syntax is (or at least has been so far) browser-specific. Internet Explorer in particular is lacking, at least according to this SO question.
The 5th edition of the ECMAScript standard does seem to standardize on this mechanism. See this SO question on getters and setters.
edit: A more practical example, perhaps, for your purposes:
function makePrivateObject()
{
var state = 0;
var out = {};
out.__defineSetter__("foo", function(x) {});
// prevent foo from being assigned directly
out.__defineGetter__("foo", function() { return state; });
out.count = function() { return state++; }
return out;
}
js>x = makePrivateObject()
[object Object]
js>x.foo
0
js>x.foo = 33
33
js>x.foo
0
js>x.count()
0
js>x.count()
1
js>x.count()
2
js>x.foo
3
How about:
function Module(id_code, title) {
var id_code = id_code;
var title = title;
var privateProps = {};
this.setProperty = function(name, value) {
// here you could e.g. log something
privateProps[name] = value;
}
this.getProperty = function(name) {
return privateProps[name];
}
}
The getter and setter methods here act on a private object used to store properties that cannot be accessed from any other methods. So you could, for example, implement a setter (or getter) that logs or does ajax or whatever, whenever a property is modified (one of the purposes of getter/setter methods).
You can actually define setters and getters in javascript and not just mimick them. I think it works on every browser except IE8 and below.
$(document).ready(function() {
var module = new Module('idcode');
module.id = 'new idcode';
module.title = 'new title';
$('body').html(module.id + ': ' + module.title);
});
function Module(id, title) {
return {
id_code: id_code,
_title: title,
get id() {
return id_code;
},
set id(value) {
id_code = value;
},
get title() {
return _title;
},
set title(value) {
title = value;
}
}
};
I like this :
// Module
var Module = function() {
// prive getter/setter value
var __value;
// private getter/setter method
var _value = function() {
if(!arguments.length) return __value;
else __value = arguments[0];
};
// output/public
return {
value: _value
};
}
Getters and setters aren't features, but "design patterns" (code bloat in this case) for languages that don't support property syntax.
Since Javascript doesn't need getters and setters, you don't want to write them. Use the language features that are available to you and idioms that work great in one languages don't work so well in another.
One of my favorite quotes comes from Python's community:
We're all consenting adults here
when discussing why private variables and information hiding isn't needed.
The quote can be found here.
Learn what the language offers you and embrace its culture and rules.
One reliable, semantic way I've favored is to use setters and getters. For example, I created the following object:
var myComplexObject = {
changelog: {},
log: function(name, val) {
console.log("set " + name + " to " + val);
if (!this.changelog[name])
this.changelog[name] = [];
this.changelog[name].push(val);
},
set o (val) {
this.log("o", val);
},
get o () {
console.log("You will never know the true value!");
return 42;
}
}
In here, whenever you read or modify the value of o, the behavior is customized. Take, for example, the following line of code and its console output:
myComplexObject.o = "oxygen";
set o to oxygen
Then, in this example, attempting to read the value results in this:
var read = myComplexObject.o;
console.log(read);
You will never know the true value!
42
And, in this example, each new value you set is logged:
myComplexObject.o = "Oh no!";
console.log(myComplexObject.changelog.o);
set o to Oh no!
["oxygen", "Oh no!"]
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I'm sick of seeing dozens of different ways of doing object oriented programming in Javascript. Can anyone just tell me which technique I should use considering I want to work on a large scale project and I want my code to be future proof?
These are just a few quick guidelines I've come up with, if anyone else has anything meaningful to add, I've set this answer as a community wiki so it should be easy enough for you to edit.
Namespace your objects to ensure they will never conflict with third party JavaScript libraries.
window['Andrew']['JS'] = {
addEvent: function(el,evName) {/*Stuff*/},
Rectangle: function(width,height) {/*Stuff*/}
};
So then you would create a rectangle object by using:
var myRect = new Andrew.JS.Rectangle(14,11);
And then your code will never interfere with, or be interfered by anybody else's Rectangle.
Use a consistent naming strategy, specifically:
Object names should be capitalized, everything else (variables, functions) should begin with a lower case character i.e.
var myRect = new Andrew.JS.Rectangle(14,11);
document.write(myRect.getArea());
Ensure everything is meaningful, i.e. verbs for methods, nouns + adjectives for parameters.
Make sure all methods and parameters are relevant to the object they belong to. e.g.
In this example, the area of the rectangle can be converted to square feet using the method inSquareFeet().
myRect.getAreaObject().inSquareFeet();
Make sure inSquareFeet is a method of the object returned by getAreaObject() and not a method of Andrew.JS.Rectangle
Use constructors, or more specifically, try as hard as possible to make sure that an object doesn't need any further initialization to be used once it has been constructed, so instead of:
var Person = function()
{
this.name = "";
this.sayHello = function ()
{
alert(this.name + " says 'Hello!'");
return this;
}
}
var bob = new Person();
bob.name = "Bob Poulton";
bob.sayHello();
try:
var Person = function(name)
{
this.name = name;
this.sayHello = function ()
{
alert(this.name + " says 'Hello!'");
return this;
}
}
var bob = new Person("Bob Poulton");
bob.sayHello();
I always use John resig's:
http://ejohn.org/blog/simple-javascript-inheritance/
It's simple and doesn't require any frameworks to function.
Because you are working on a large scale project i would suggestion a javascript framework like mootools http://mootools.net/.
It has a good class and inheritance structure.
My ideal Object for OOP is like using an Instance method with prototypes:
Example:
var Users = function()
{
var _instance;
this.prototype.getUsername = function(){/*...*/}
this.prototype.getFirstname = function(){/*...*/}
this.prototype.getSecurityHash = function(){/*...*/}
/*...*/
/*Static Methods as such*/
return { /*Return a small Object*/
GetInstance : function()
{
if(_instance == null)
{
_instnance = new Users(arguments);
}
return _instnance; //Return the object
},
New: function()
{
_instnance = null; //unset It
return this.GetInstnace(arguments);
}
}
}
Then I would always use like:
Firstname = Users.GetInstance('Robert','Pitt').getFirstname();
Username = Users.GetInstance().getUsername(); //Returns the above object.
Me = Users.New('Robert',null); //Deletes the above object and creates a new instance.
Father = Users.New('Peter','Piper'); //New Object
Me.AddFather(Father); //Me Object.
And that's the kind of road i go down when it comes to building a JavaScript OO Style architecture.
just for your information, i think YUI provides few great tutorials on this topic
//Create and define Global NameSpace Object
( function(GlobalObject, $, undefined)
{
GlobalObject.Method = function()
{
///<summary></summary>
}
GlobalObject.Functionality = {};
}) (GlobalObject = GlobalObject || {}, jQuery);
//New object for specific functionality
( function(Events, $, undefined)
{
//Member Variables
var Variable; // (Used for) , (type)
// Initialize
Events.Init = function()
{
///<summary></summary>
}
// public method
Events.PublicMethod = function(oParam)
{
///<summary></summary>
///<param type=""></param>
}
// protected method (typically define in global object, but can be made available from here)
GlobalObject.Functionality.ProtectedMethod = function()
{
///<summary></summary>
}
// internal method (typically define in global object, but can be made available from here)
GlobalObject.InternalMethod = function()
{
///<summary></summary>
}
// private method
var privateMethod = function()
{
///<summary></summary>
}
}) (GlobalObject.Funcitonality.Events = GlobalObject.Funcitonality.Events || {}, jQuery )
// Reusable "class" object
var oMultiInstanceClass = function()
{
// Memeber Variables again
var oMember = null; //
// Public method
this.Init = function(oParam)
{
oMember = oParam;
for ( n = 1; i < oMemeber.length; i += 1 )
{
new this.SubClass.Init(oMember[i]); // you get the point, yeah?
}
}
this.Subclass = function()
{
this.Init = function() { }
}
}
The strength to this is that it initializes the Global object automatically, allows you to maintain the integrity of your code, and organizes each piece of functionality into a specific grouping by your definition.
This structure is solid, presenting all of the basic syntactical things you would expect from OOP without the key words.
There are even some ingenious ways to set up interfaces as well. If you choose to go that far, a simple search will give you some good tutorials and tips.
Even setting up intellisense is possible with javascript and visual studio, and then defining each piece and referencing them makes writing javascript cleaner and more manageable.
Using these three methods as needed by your situation helps keep the global namespace clean, keep your code organized and maintains separation of concerns for each object.. if used correctly. Remember, Object Oriented Design is of no use if you don't utilize the logic behind using objects!
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
return {
publicMethod: function() { alert(iAmAPrivateVariable); },
publicVariable: bar()
}
}
//usage
var thing = foo()
This is a functional approach, and has a great deal more going for it (such as encapsulation) then anything else you are going to see
In a general way, you shouldn't be doing OO in javascript, it isn't that great a language for it for a great many reasons. Think scheme with squiggly brackets and semi-colons, and you will start writing the language like the pros do. That being said, sometime OO is a better fit. In those cases, the above is typically the best bet
to bring inheritance into the mix
function parent() {
return { parentVariable: 2 };
}
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
me = parent();
me.publicMethod = function() { alert(iAmAPrivateVariable); };
me.publicVariable = bar();
return me;
}
This makes things a tad more complected, but accomplishes the desired end result while still taking a functional approach to OO concepts (in this case, using decorator functions instead of real inheritance). What I like about the whole approach is we are still really treating objects the way they are intended to be in this kind of language -- a property bag you can attach stuff to at will.
Another note is this is wildly different then what you will see most of the time in most of the jobs you will ever work at, and often is very hard to explain a) what is going on, and b) why it is a good idea to coworkers.
I use such a pattern and recommend to you to use it too:
function Person(firstname, lastname, age)
{
var self = this;
var _ = {};
// Private members.
var firstname = firstname;
var lastname = lastname;
var age = age || 'unknown';
// Private methods.
function first_letter_to_uppercase(str) {
return str.charAt(0).toUpperCase() + str.substr(1);
}
// Public members and methods.
_.get_age = function()
{
return age;
}
_.get_name = function()
{
return first_letter_to_uppercase(firstname) + ' ' +
first_letter_to_uppercase(lastname);
}
return _;
}
var p = new Person('vasya', 'pupkin', 23);
alert("It's " + p.get_name() + ', he is ' + p.get_age() + ' years old.')
You can try with a simple, usefull and quick object:
var foo = {
foo1: null,
foo2: true,
foo3: 24,
foo4: new Array(),
nameOfFunction1: function(){
alert("foo1");
},
nameOfFunction2: function(){
alert("foo2");
},
}
To use this, you have to create an instance of this object and use like a object in java:
foo.nameOfFunction2();
Also you can check this link to other solution: http://www.javascriptkit.com/javatutors/oopjs.shtml
I hope that answer your question.