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
I'm designing an OOP inheritance pattern for many applications I'm building. Javascript has many ways of doing this, but I stumbled on a pattern I really like. But now I'm struggling with the need for a separation of classes and instances.
I have a base object called Root. And it has a main method called inherit. To create a new object you use
var Person = Root.inherit({
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
Then to create an "instance" you would
var sally = Person.inherit({
name : "sally",
height : "5'6"
});
sally can .talk() and she can walk() and she has a .name and a .height
You can make more people the same way.
If you want a constructor you use
var Person = Root.inherit({
_construct : function() {
// do things when this object is inherited from
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
It also has the ability to have init, when the object is first defined in code (singletons use this)
var Person = Root.inherit({
_init : function() {
// called at runtime, NOT called if an object is inherited from me
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
So as you can see, everything uses .inhert(). There are no classes and no instances really. Everything is an instance of something. The only real problem I found so far is that there is no concept of "type", but you can always just check for a method if you need to. Also you can't protect a 'class', as a 'class' can be changed during execution if the developer accidentally changed it, or meant to change it.
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
No there's no need since Javascript is a Prototypal based language, meaning that classes are not involved. You are just creating clones of the objects.
http://en.wikipedia.org/wiki/Prototype-based_programming
As far as the concept of type, the type is object.
A good read for more info about this would be Javascript Patterns by Stoyan Stefanov he has several different creational patterns that address your concerns, including examples that implement Design Patterns from the gang of four's design patterns.
http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
Not really, if you're happy with it, it's fine.
The more normal form of JavaScript inheritance does much the same thing. You'll frequently see structures like this (severely cut down for brevity):
function Base() {
}
Base.prototype.foo = function() {
};
function Derived() {
}
Derived.prototype = new Base();
...and of course, new Base() is also how you create instances of Base. So your system is quite similar.
Again, the above is a sketch, not a full example. For one thing, usually you'd see construction and initialization separated out, so you don't literally see Derived.prototype = new Base() so much as something that creates an object with Base's prototype but without actually calling Base (which Derived would do later), but you get the idea. Granted that statement somewhat weakens the similarity with your system, but I don't think it breaks it at all.
At the end of the day, it's all about objects (instances), which are either used directly (your sally) or indirectly by providing features to other objects (Person, Root) by cloning or by setting them up as the prototype of the other object.
Javascript's inheritance is prototypical which means everything object is an instance. You actually have to do extra work to get the classical inheritance.
This is how I work in javascript
// this is class
function person(){
// data is member variable
this.name = null;
this.id = null;
//member functions
this.set_name = _set_name;
this.get_name = _get_name;
this.set_id = _set_id;
this.get_id = _get_id;
function _set_name(name){
this.name = name;
}
function _get_name(name){
return this.name;
}
function _set_id(id){
this.id = id;
}
function _get_id(id){
return this.id;
}
}
// this is instance
var yogs = new person();
yogs.set_id(13);
yogs.set_name("yogs");
hope it may help
Start with some basic object...
// javascript prototypes - callback example - javascript objects
function myDummyObject () {
that = this;
} // end function myDummyObject ()
// begin dummy object's prototype
myDummyObject.prototype = {
that : this,
// add a simple command to our dummy object and load it with a callback entry
say : function () {
var that = this;
console.log('speaking:');
that.cb.run("doSay");
}
} // end myDummyObject proto
extend with a sub prototype..
// here we addon the callback handler... universally self sufficient object
var cb = {
that : this, // come to papa ( a link to parent object [ myDummyObject ] )
jCallback : new Array(new Array()), // initialize a javascript 2d array
jCallbackID : -1, // stores the last callback id
add: function(targetFnc, newFunc) {
var that = this;
var whichID = that.jCallbackID++;
// target, addon, active
that.jCallback[that.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': whichID };
return whichID; // if we want to delete this later...
}, // end add
run: function(targetFnc) {
var that = this;
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['targetFunc'] == targetFnc && that.jCallback[i]['active'] == true )
that.jCallback[i]['newFunc'](); // run callback.
}, // end run
remove: function (whichID) {
var that = this;
console.log('removing:' + whichID);
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['id'] == whichID )
that.jCallback[i]['newFunc'](); // run callback.
} // end remove
}
// add the object to the dummy object...
myDummyObject.prototype.cb = cb;
Example:
var testing = new myDummyObject();
testing.cb.add('doSay', function () { console.log('test: 213123123'); } );
// test remove...
var testid = testing.cb.add('doSay', function () { console.log('test: 12sad31'); } );
testing.cb.remove(testid);
testing.cb.add('doSay', function () { console.log('test: asdascccc'); } );
testing.cb.add('doSay', function () { console.log('test: qweqwe'); } );
testing.cb.add('doSay', function () { console.log('test: d121d21'); } );
testing.cb.add('doSay', function () { console.log('test: wwww'); } );
testing.say();
This always seemed the easiest for me to understand... Just create a new instance of the inherited class and then loop through its variables and methods and add them to the main one.
var myPerson = new Person()
var myPerson.firstName = 'john';
var myPerson.lastName = 'smith';
var myPerson.jobTitle = 'Programmer';
var Person = function(){
//Use this to inherit classes
this._extendedClass = new Person_Job();
for(var i in this._extendedClass){
this[i] = this._extendedClass[i];
}
delete this._extendedClass;
this.firstName = '';
this.lastName = '';
}
var Person_Job = function() {
this.jobTitle = '';
}
I would like to make an object's structure immutable, preventing its properties from being subsequently replaced. The properties need to be readable, however. Is this possible?
I'm sure there are no language features (along the lines of final in Java and readonly in C#) to support this but wondered whether there might be another mechanism for achieving the same result?
I'm looking for something along these lines:
var o = {
a: "a",
f: function () {
return "b";
}
};
var p = o.a; // OK
o.a = "b"; // Error
var q = o.f(); // OK
o.f = function () { // Error
return "c";
};
ECMAScript 5 will have seal() and freeze(), but there's no good way to do this with current JavaScript implementations.
Source.
the best thing you can do is hide your properties inside of a closure.
var getMap = function(){
var hidden = "1";
return {
getHidden : function() { return hidden; }
}
}
var f = getMap ();
alert(f.getHidden());
I took a stab at it. In the above code you will need to not just return hidden but copy it into a new object perhaps. maybe you can use jquery's extend to do this for you, so you will be returning a new object, not the reference. This may be completely wrong though =)
Using var in an object constructor will create a private variable. This is essentially a closure. Then you can create a public function to access/modify it. More information and examples available on Private Members in Javascript by Douglas Crockford.
As mkoryak said, you can create a closure to hide properties
function Car(make, model, color) {
var _make = make, _model = model, _color = color;
this.getMake = function() {
return _make;
}
}
var mycar = new Car("ford", "mustang", "black");
mycar.getMake(); //returns "ford"
mycar._make; //error
Okay, so there's been already a couple of answers suggesting you return an object with several getters methods. But you can still replace those methods.
There's this, which is slightly better. You won't be able to replace the object's properties without replacing the function completely. But it's still not exactly what you want.
function Sealed(obj) {
function copy(o){
var n = {};
for(p in o){
n[p] = o[p]
}
return n;
}
var priv = copy(obj);
return function(p) {
return typeof p == 'undefined' ? copy(priv) : priv[p]; // or maybe copy(priv[p])
}
}
var mycar = new Sealed({make:"ford", model:"mustang", color:"black"});
alert( mycar('make') ); // "ford"
alert( mycar().make ); // "ford"
var newcopy = mycar();
newcopy.make = 'volkwagen';
alert( newcopy.make ); // "volkwagen" :(
alert( mycar().make ); // still "ford" :)
alert( mycar('make') ); // still "ford" :)
You can now force a single object property to be frozen instead of freezing the whole object. You can achieve this with Object.defineProperty and the parameter writable: false
var obj = {
"first": 1,
"second": 2,
"third": 3
};
Object.defineProperty(obj, "first", {
writable: false,
value: 99
});
In this example, obj.first now has its value locked to 99.
A nasty gotcha in javascript is forgetting to call new on a function meant to be instantiated, leading to this being bound to a different object (usually the global) instead of a fresh one. One workaround I read about is to check for it explicitly in the function-constructor using the following idiom:
function SomeConstructor(x, y, ...) {
// check if `this` is created with new
if ( !(this instanceof arguments.callee) )
return new SomeConstructor(x, y, ...);
// normal initialization code follows
Now new SomeConstructor(...) and SomeConstructor(...) are equivalent.
I'd like to simplify this by creating a wrapper function factory(fn) that does the first two lines and then delegates to the wrapped function fn. This would be used like:
SomeConstructor = factory(function (x, y, ...) {
// normal initialization code follows
})
My first attempt was:
function factory(fn) {
return function() {
if ( !(this instanceof arguments.callee) ) {
return new arguments.callee.apply(this, arguments);
}
fn.apply(this, arguments);
}
}
but it fails with "Function.prototype.apply called on incompatible [object Object]". The second attempt was:
function factory(fn) {
return function() {
if ( !(this instanceof arguments.callee) ) {
var tmp = new arguments.callee();
arguments.callee.apply(tmp, arguments);
return tmp;
}
fn.apply(this, arguments);
}
}
This sort of works but it may call the wrapped function twice: once with no arguments (to create a new instance) and once with the passed arguments for the actual initialization. Apparently this is fragile and inefficient but I can't figure out a way to do it with a single call. Is this possible ?
EDIT: Based on bobince's approach, here's a similar one that does the trick:
function factory(init) {
var run_init = true;
function constr() {
if ( !(this instanceof constr) ) {
run_init = false;
var tmp = new constr();
run_init = true;
init.apply(tmp, arguments);
return tmp;
}
if (run_init)
init.apply(this, arguments);
}
return constr;
}
As for whether this is something that should be encouraged or not, that's debatable. I come from a Python background and I think of new as just noise (Java) or wart (Javascript), but I may be missing something.
This simply encourages a bad-habit shortcut that relies far too heavily on the implementation of the class to "fix" the calling code.
If this is a problem, don't just let it slide, throw an error message.
You can pass a unique value into the constructor for the first call (with new) that signifies you don't want the initialiser called yet:
var _NOINIT= {};
function factory(init) {
function constr() {
if (!(this instanceof constr)) {
var inst= new constr(_NOINIT);
init.apply(inst, arguments);
return inst;
}
if (arguments[0]!==_NOINIT)
init.apply(this, arguments);
}
return constr;
}
Note I've used a named inline function for the constructor because arguments.callee will be going away in ECMAScript Fifth Edition's ‘strict’ mode.
However if you're using a class factory, I suggest making the initialiser function a member of the class, rather than being passed in. That way, you can subclass a base class and have the subclass inherit the initialiser, which is normal behaviour in class-based languages. eg.:
Function.prototype.makeSubclass= function() {
function constr() {
var that= this;
if (!(this instanceof constr))
that= new constr(_NOINIT);
if (arguments[0]!==_NOINIT && '_init' in that)
that._init.apply(that, arguments);
return that;
}
if (this!==Object)
constr.prototype= new this(_NOINIT);
return constr;
};
var Shape= Object.makeSubclass();
Shape.prototype._init= function(x, y) {
this.x= x;
this.y= y;
};
var Point= Shape.makeSubclass();
// inherits initialiser(x, y), as no need for anything else in there
var Circle= Shape.makeSubclass()
Circle.prototype._init= function(x, y, r) {
Shape.prototype._init.call(this, x, y);
this.r= r;
};
Of course you don't have to put that into the Function prototype... it's a matter of taste, really. As is allowing constructors without new.
Personally I prefer to throw an error rather than silently make it work, to try to discourage bare-constructor-calling, since this is a mistake elsewhere and may make the code slightly less clear.
Your "factory" function could be written in this way:
function factory(fn, /* arg1, arg2, ..., argn */) {
var obj = new fn(), // Instantiate using 'new' to preserve the prototype chain
args = Array.prototype.slice.call(arguments, 1); // remove fn argument
fn.apply(obj, args); // apply the constructor again, with the right arguments
return obj;
}
// Test usage:
function SomeConstructor (foo, bar) {
this.foo = foo;
this.bar = bar;
}
SomeConstructor.prototype.test = true;
var o = factory(SomeConstructor, 'foo', 'bar');
// will return: Object foo=foo bar=bar test=true, and
o instanceof SomeConstructor; // true
However, the new operator is not bad, I would not encourage you to avoid it, I would recommend you to stick with a proper naming convention, constructor functions identifiers in PascalCase, all other identifiers in camelCase, and also I highly recommend you to use JsLint it will help you to detect that kind of mistakes early.
I dislike your mixing of arguments.callee and the function's identifier. Also, you are dumbing down the original problem. You should have used apply to begin with so as not to make the helper (factory) function seem even better than it really is.
What should have been done to begin with:
function SomeConstructor(x, y, ...) {
// check if `this` is created with new
if ( !(this instanceof arguments.callee) )
return new arguments.callee.apply (this, arguments);
// normal initialization code follows
Another issue with factory is that it defeats the function's length property.
while 'new' is a good thing, and I don't endorse trying to do away with language features, check out this code I played with a while ago: (note, this is not a complete solution for you, but rather something to build into your code)
function proxy(obj)
{
var usingNew = true;
var obj_proxy = function()
{
if (usingNew)
this.constructor_new.apply(this, arguments);
};
obj_proxy.prototype = obj.prototype;
obj_proxy.prototype.constructor_new = obj.prototype.constructor;
obj_proxy.createInstance = function()
{
usingNew = false;
var instance = new obj_proxy();
instance.constructor_new.apply(instance, arguments);
usingNew = true;
return instance;
}
return obj_proxy;
}
to test it out, create a function foo like this:
function foo(a, b) { this.a = a; }
and test it:
var foo1 = proxy(foo);
var test1 = new foo1(1);
alert(test1 instanceof foo);
var test2 = foo1.createInstance(2);
alert(test2 instanceof foo);
EDIT: removed some code not relevant for this.
If you are interested in dealing with the inability to use apply with new, one could use
Function.prototype.New = (function () {
var fs = [];
return function () {
var f = fs [arguments.length];
if (f) {
return f.apply (this, arguments);
}
var argStrs = [];
for (var i = 0; i < arguments.length; ++i) {
argStrs.push ("a[" + i + "]");
}
f = new Function ("var a=arguments;return new this(" + argStrs.join () + ");");
if (arguments.length < 100) {
fs [arguments.length] = f;
}
return f.apply (this, arguments);
};
}) ();
Example:
var foo = Foo.New.apply (null, argArray);
Here is some broilerplate code I've come up with as a code-template for object factory in AngularjS. I've used a Car/CarFactory as an example to illustrate. Makes for simple implementation code in the controller.
<script>
angular.module('app', [])
.factory('CarFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Car = function(color) {
// initialize instance properties
angular.extend(this, {
color : null,
numberOfDoors : null,
hasFancyRadio : null,
hasLeatherSeats : null
});
// generic setter (with optional default value)
this.set = function(key, value, defaultValue, allowUndefined) {
// by default,
if (typeof allowUndefined === 'undefined') {
// we don't allow setter to accept "undefined" as a value
allowUndefined = false;
}
// if we do not allow undefined values, and..
if (!allowUndefined) {
// if an undefined value was passed in
if (value === undefined) {
// and a default value was specified
if (defaultValue !== undefined) {
// use the specified default value
value = defaultValue;
} else {
// otherwise use the class.prototype.defaults value
value = this.defaults[key];
} // end if/else
} // end if
} // end if
// update
this[key] = value;
// return reference to this object (fluent)
return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default values
this.Car.prototype.defaults = {
color: 'yellow',
numberOfDoors: 2,
hasLeatherSeats: null
};
// instance factory method / constructor
this.Car.prototype.instance = function(params) {
return new
this.constructor()
.set('color', params.color)
.set('numberOfDoors', params.numberOfDoors)
.set('hasFancyRadio', params.hasFancyRadio)
.set('hasLeatherSeats', params.hasLeatherSeats)
;
};
return new this.Car();
}) // end Factory Definition
.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:
// numberOfDoors, and hasLeatherSeats
$scope.car1 = CarFactory
.instance({
color: 'red'
})
;
// second car, is blue, has 3 doors,
// uses class default for hasLeatherSeats
$scope.car2 = CarFactory
.instance({
color: 'blue',
numberOfDoors: 3
})
;
// third car, has 4 doors, uses class default for
// color and hasLeatherSeats
$scope.car3 = CarFactory
.instance({
numberOfDoors: 4
})
;
// sets an undefined variable for 'hasFancyRadio',
// explicitly defines "true" as default when value is undefined
$scope.hasFancyRadio = undefined;
$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,
// uses class default for hasLeatherSeats
$scope.car4 = CarFactory
.instance({
color: 'purple'
numberOfDoors: 4
});
// and then explicitly sets hasLeatherSeats to undefined
$scope.hasLeatherSeats = undefined;
$scope.car4.hasLeatherSeats.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});
</script>
the only thing that worked for me involves dumbing down the implementation. it's ugly but works (both with and without operator new):
var new_ = function (cls)
{
var constructors = [
function ()
{
return new cls();
}
, function ($0)
{
return new cls($0);
}
, function ($0, $1)
{
return new cls($0, $1);
}
, function ($0, $1, $2)
{
return new cls($0, $1, $2);
}
, // up to a chosen limit
];
return function ()
{
return constructors[arguments.length].apply(
this
, arguments
);
}
}
edit to react to comments
I have way-below-average tolerance to repetitive code, and this code hurt to write, but the functions in constructors need to be separate if arguments.length is to mean something in the real constructor function. consider a variant with a single new wrapper:
var new_ = function (cls)
{
// arbitrary limit
var constructor = function ($0, $1, $2)
{
return new cls($0, $1, $2);
};
return function ()
{
return constructor.apply(
this
, arguments
);
}
}
var gen = new_(function ()
{
print(
arguments.length
+ " "
+ Array.prototype.toSource.call(arguments)
);
});
gen("foo") // 3 ["foo", undefined, undefined]
gen("foo", "bar") // 3 ["foo", "bar", undefined]
gen("foo", "bar", "baz") // 3 ["foo", "bar", "baz"]
the parameter list can be arbitrarily wide, but arguments.length doesn't lie only in the special case.
I've been using this solution with the upper limit of 10 arguments for a few years, and I don't remember ever running into the limit. the risk that it'll ever happen is rather low: everybody knows that functions with many parameters are a no-no, and javascript has a better interface for the desired functionality: packing parameters into objects.
so, the only limit is the width of the parameter list, and this limit seems to be purely theoretical. other than that, it supports completely arbitrary constructors, so I'd say it's very general.