Can javascript constructor function and object.create be combined? - javascript

Update
If this is not possible, please feel free to provide an answer explaining why. I'd be happy to mark as it accepted.
I'd like to slightly simplify the following code (two steps for an object "declaration", I'd like to have one):
var Masher = function(opts) {
this._name = opts.name;
};
Masher.prototype = Object.create(Object.prototype, {
_name: { writable: true },
name: { get: function() { return this._name; }}
});
// Note: (new Masher({name: 'bar'})).name == 'bar'
I would to create the entire function prototype in one shot with the constructor function appearing somewhere in the Object.create. Perhaps, something like this:
var Basher = Object.create(Function.prototype, {
_name: { writable: true },
name: { get: function() { return this._name; }},
constructor: { value: function(opts) { this._name = opts.name; }}
});
However, when I call new Basher(), I get: 'TypeError: object is not a function'.
Although I realize I could do this with syntactic sugar (a helper library), my goals here are to keep things as simple as possible and pick up some understanding of the JS object, prototype, constructor internals. I've tried to read as much on this as possible: SO related questions, Crockford, Ben Nadel, Joost Diepenmaat.
Perhaps I haven't found the correct formulation, or I'm fighting the design philosophy of Object.create, or the language doesn't allow this. Perhaps, this is really just a stylistic thing, and therefore, a conceit.
Of course, I can live with the two step process (Masher). There's something about packaging it all in one shot that feels right (Basher).
Is there a way to do this? Thanks.

If you want to use the class-based approach where you can call a constructor function with new, you will always have two parts:
The constructor function itself (to initialise instances)
The prototype object (for shared properties)
If you don't want to drop the prototype entirely, there is no JavaScript syntax to do both the function creation and the prototype setup in one go (apart from the new ES6 class syntax, of course) while still maintaining the .prototype link from the function to the prototype object. Of course, a trivial helper function (doesn't need to be a complete library) would do:
function Class(p) {
return (p.constructor.prototype = p).constructor;
}
var Casher = Class({
constructor: function(opt) { this._name = opt.name },
get name() { return this._name }
});
var foo = new Casher({name:'bar'});
This patterns doesn't really have a lot to do with Object.create at all (except you want your prototype inherit from another one).
So yes, maybe you are trying to fight the philosophy of Object.create, which is to use only objects and derive other objects from these (read the Wikipedia article on it and make sure to check out some example from languages other than JS). You would not have a constructor, and not a new operator - rather you'd call a create method on your object:
var Proto = { // some helper methods (usually native in more prototype-focused languages)
clone: function() {
return Object.create(this);
},
create: function(opt) {
var derived = this.clone();
derived.init(opt);
return derived;
},
init: function(opt) {
Object.getOwnPropertyNames(opt).forEach(function(p) {
Object.defineProperty(this, p, Object.getOwnPropertyDescriptor(opt, p));
}, this);
}
};
var Pasher = Proto.create({ // "subclass" Proto
init: function(opt) {
if ("name" in opt) this._name = opt.name;
},
_name: "",
get name() { return this._name; }
});
var foo = Pasher.create({name:'bar'});

Object.create() returns an object, not a function, with a specific prototypal inheritance chain defined.
var Basher = Object.create(Function.prototype, {
_name: { writable: true },
name: { get: function() { return this._name; }},
constructor: { value: function(opts) { this._name = opts.name; }}
});
> undefined
Basher
> Object {_name: undefined, name: (...)}_name: undefinedconstructor: function (opts) { this._name = opts.name; }name: (...)get name: function () { return this._name; }__proto__: function Empty() {}
> typeof Basher
"object"
You can, however, combine Object.create() and constructor functions to let you reuse object literals as APIs, which makes the code look a bit cleaner:
var basherAPI = {
name: function () {
return this._name;
}
};
function Basher(name) {
var inst = Object.create(basherAPI);
// assign instance *state* here; the API is
// reusable but each object needs its own state
inst._name = name;
return inst;
}
var basher = new Basher('Tom');
basher.name() // Tom
EDIT: In this case, using the new keyword is purely convention; it has NO bearing on what happens within the constructor function. One could also write: var basher = Basher('Tom');.

I'm putting an answer in here, but I'm not sure this fully answers my question, so I won't be marking it as the answer as I don't believe I completely understand this part of the JS language.
The closest I believe I can get to this is the following:
var Lasher;
(Lasher = function (opts) {
this._name = opts.name;
}).prototype = Object.create(Object.prototype, {
_name: { writable: true },
name: { get: function() { return this._name; }},
});
This formulation exposes part of what is going on, something to which #Bergi alluded, albeit briefly. First, note that it does not answer my question as it still requires two steps (Variable declaration and then Value assignment). It does get to the heart of my stylistic issue, which is to co-locate all of the object's declaration code. It does this by capturing the anonymous function definition (constructor) in Lasher, then referencing the prototype property in order to assign it the prototype object (the rest of the "class" declaration).
Although grouped together as one computational unit, visually it's harder to parse and fairly ugly, quite frankly. Also, the anonymous function might even capture Lasher in its scope (I'm not sure).
Incidentally, I tried this flawed approach. It's one statement, although still a bit ugly:
(function Crasher(opts) {
this._name = opts.name;
}).prototype = Object.create(Object.prototype, {
_name: { writable: true },
name: { get: function() { return this._name; }},
});
Too bad it doesn't work. Crasher is scoped to the first () and doesn't live in the outer scope, which is why the earlier code had to declare Crasher as a variable in order to capture the anonymous function.
The thing is, Lasher is not really simpler than Masher (above) from a line count or readability perspective. So, the original formulation stands as the best (so far).
Also, although I understand why Object.create cannot be used as it creates an Object, I guess I don't understand how the internal JS interpreter creates functions vs. Objects. What I mean is, a Function is an Object, but I guess there's no way to create a function that can be returned directly from Object.create. That's the primary problem.
In addition, whatever is going on inside of the prototype assignment and the constructor assignment within that, adding a constructor property in the Object.create doesn't work. We can see that with this bit of code:
var Masher = function(){ console.log("default");};
Masher.prototype = Object.create(Object.prototype, {
_name: { writable: true },
name: { get: function() { return this._name; }},
constructor: { value: function(opts) {
console.log("ctor");
this._name = opts.name;
return this;
}}
});
// "new Masher()" outputs:
// default
// undefined
So, if I understand some of this correctly, function creation and prototype creation on top of that have some deep relationships within the JS interpreter/compiler and the language does not provide a means to do what I am trying to do.

Related

Unable to have get and set method in Object Constructor (not in class) in JavaScript? [duplicate]

I recently read about the fact that there is a possibility of defining getters/setters in JavaScript. It seems extremely helpful - the setter is a kind of 'helper' which can parse the value to be set first, before actually setting it.
For example, I currently have this code:
var obj = function(value) {
var test = !!value; // 'test' has to be a boolean
return {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new obj(true);
This code always converts value to a boolean. So if you code instance.test = 0, then instance.test === false.
However, for this to work you have to actually return an object, which means that the new instance is not of type obj but just is a plain object. This means that changing the prototype of obj has no effect on instances. For example, this does not work - instance.func is undefined:
obj.prototype.func = function() { console.log(this.value); };
because instance is not of type obj. To get the prototype functions work, I guess I should not return a plain object, but rather not return anything so that instance would just be of type obj, like a regular constructor works.
The problem then is how to implement getters/setters? I can only find articles describing how to add these to an object, not as being part of the constructor of a custom type.
So how do I implement getters/setters in the constructor so as to be able to both use getters/setters and extending the prototype?
You can't do that.
You can set setter/getters for properties of objects though. I advice you use ES5 Object.defineProperties though. of course this only works in modern browsers.
var obj = function() {
...
Object.defineProperties(this, {
"test": {
"get": function() { ... },
"set": function() { ... }
}
});
}
obj.prototype.func = function() { ... }
var o = new obj;
o.test;
o.func();
Usually you want class methods. The answer by #Raynos on May 7, 2011 gets the job done, but it defines an instance method, not a class method.
The following illustrates a class definition with a the getter and setter being part of the class. This definition is a lot like the answer by #Raynos, but with two differences in the code: (1) The "defineProperties()" action has been moved out of the constructor. (2) The argument to "defineProperties()"as been changed from the instance object "this", to the constructor's prototype object.
function TheConstructor(side) {
this.side = side;
}
Object.defineProperties(TheConstructor.prototype, {
area: {
get: function() { return this.side * this.side; }
,set: function(val) { this.side = Math.sqrt(val); }
}
});
// Test code:
var anInstance = new TheConstructor(2);
console.log("initial Area:"+anInstance.area);
anInstance.area = 9;
console.log("modified Area:"+anInstance.area);
Which produces these results:
initial Area:4
modified Area:9
Although usually the distinction between class versus instance
definition is just a matter of style, there is a purpose to
good style, and there is a case where the distinction matters:
the memoized getter. The purpose for a memoized getter is
described here: Smart/self-overwriting/lazy getters
Define the getter at the class level when the memoized value is to
pertain to the entire class. For example, a configuration file
should be read only once; the resulting values should then apply
for the duration of the program. The following sample code
defines a memoized getter at the class level.
function configureMe() {
return 42;
}
Object.defineProperties(TheConstructor.prototype, {
memoizedConfigParam: {
get: function() {
delete TheConstructor.prototype.memoizedConfigParam;
return TheConstructor.prototype.memoizedConfigParam = configureMe();
}
,configurable: true
}
});
// Test code:
console.log("memoizedConfigParam:"+anInstance.memoizedConfigParam);
Produces:
memoizedConfigParam:42
As can be seen in the example, memoized getters have the
characteristic that the getter function deletes itself,
then replaces itself with a simple value that
(presumably) will never change.
Note that 'configurable' must be set to 'true'.
Define the getter at the instance level when the memoized value
depends upon the contents of instance. The definition moves
inside the constructor, and the object of attention is 'this'.
function TheConstructorI(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
return this.memoizedCalculation = this.expensiveOperation();
}
,configurable: true
}
});
}
TheConstructorI.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instance2 = new TheConstructorI(2);
var instance3 = new TheConstructorI(3);
console.log("memoizedCalculation 2:"+instance2.memoizedCalculation);
console.log("memoizedCalculation 3:"+instance3.memoizedCalculation);
Produces:
memoizedCalculation 2:8
memoizedCalculation 3:27
If you want to guarantee (rather than presume) that the memoized
value will never be changed, the 'writable' attribute needs to
be changed. That makes the code a bit more complicated.
function TheConstructorJ(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
Object.defineProperty( this, 'memoizedCalculation'
,{ value : this.expensiveOperation()
,writable : false
});
return this.memoizedCalculation;
}
,configurable: true
}
});
}
TheConstructorJ.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instanceJ = new TheConstructorJ(2);
console.log("memoizedCalculation:"+instanceJ.memoizedCalculation);
instanceJ.memoizedCalculation = 42; // results in error
Produces:
memoizedCalculation:8
>Uncaught TypeError: Cannot assign to read only property 'memoizedCalculation' of object '#<TheConstructorJ>'
The OP's original question, from March 7, 2011, presented basic
getter and setter syntax, noted that it worked on an object but
not on 'this', and asked how to define getters and setters within
a constructor. In addition to all the examples above, there is
also a "cheap-shot" way of doing it: create a new object within
the constructor, like the OP did, but then assign the object to
be a member within 'this'. So, the original code would look like
this:
var MyClass = function(value) {
var test = !!value; // 'test' has to be a boolean
this.data = {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new MyClass(true);
// But now 'data' is part of the access path
instance.data.test = 0;
console.log(instance.data.test);
Produces:
false
Believe it or not, I have actually run into situations where
this "cheap-shot" is the best solution. Specifically, I used this
technique when I had records from several tables encapsulated within
a single class, and wanted to present a unified view as though
they were a single record called 'data'.
Have fun.
IAM_AL_X
Update for ES6 -- have a look at section 19.3.1 of Alex Rauschmayer's book Exploring ES6 http://exploringjs.com/es6/ch_maps-sets.html#sec_weakmaps-private-data which demonstrates how to use WeakMaps with getters and setters to hold private data. Combining with section 16.2.2.3 http://exploringjs.com/es6/ch_classes.html#leanpub-auto-getters-and-setters would result in something like
# module test_WeakMap_getter.js
var _MyClassProp = new WeakMap();
class MyClass {
get prop() {
return _MyClassProp.get( this );
}
set prop(value) {
_MyClassProp.set( this, value );
}
}
var mc = new MyClass();
mc.prop = 5 ;
console.log( 'My value is', mc.prop );
$ node --use_strict test_WeakMap_getter.js
My value is 5
function Obj(value){
this.value = !!value;
}
Obj.prototype = {
get test () {
return this.value;``
},
set test (value) {
this.value = !!this.value;
}
};
var obj = new Obj(true);
I know this might be extremely late but I figured out a different way to accomplish what you want and for the sake of people, like myself, googling for an answer to this here it is.
function Constructor(input){
this.input = input;
}
Object.__defineGetter__.call(Constructor.prototype, "value", function(){
return this.input * 2;
});
var test = new Constructor(5);
alert(test.value) // 10
I've tested this in chrome, safari, mobile safari, firefox and they all work (latest versions of course)
#Alex I see it as more option and more power, programming is art, #Nat share his finding with us, and for that I thank him. Maybe someone want to do it that way.
I'm sure the setter version is the same but just changing that g to a s.
i.g:
function Constructor(input){
this.input = input;
}
Object.__defineGetter__.call(Constructor.prototype, "value", function(){
return this.input * 2;
});
Object.__defineSetter__.call(Constructor.prototype, "bar", function(foo){
return this.input *= foo;
});
var test = new Constructor(5);
console.log(test.value); // 10
test.bar = 5;
console.log(test.input); //25
With that said, this feature is deprecated, advices to not to use in production coding.

Creating javascript functions when needed

I'm trying to determine the performance implications of some javascript. In our application, a form contains a number of widgets. Not all widgets are used on every page or a widget might be used more than once. I've been thinking about a model similar to the following (note that the actual script is a lot more complicated, I've simplified it to be brief):
var widget = {
type1: function(args) {
function getName() {
return this._name;
}
return (widget.type1 = function(args) {
return {
_name: args.name,
getName: getName
};
})(args);
}
}
My thought is that the first time the widget.type1 function is called, it will initialize all the code needed for a widget.type1. Any subsequent widget.type1 would then use the functions. I know that I could do something like this:
var widget = {
type1: function(args) {
return {
_name: args.name,
getName: function getName() {
return this._name;
}
};
}
}
But then each type1 object would have it's own copy of a function that does the same thing, which I would assume would use more memory (I've tested in browser debugging tools that o1.getName != o2.getName).
I could just write out the script for the types of widgets that are on the current page from the server, but then I don't benefit from caching a single js file and I don't want to put each widget in its own js file because then it would have to download them all separately.
Will this result in problems? Would/should this perform as I think? Other thoughts?
Edit
I think I should explain my reasoning. My thought (which could be erroneous) is that the first time a widget is used, it would initialize the logic used by the widget. For instance, if I never create a type1 widget, there's no need to add a bunch of functions to the prototype of the type1 widget. The code I wrote was highly simplified. There may be 500+ lines of code used by that widget, and I'm not actually using a getName function, that was just an example. If the widget isn't used, it wouldn't need that logic at all. It also keeps functions only used by that widget out of the global scope.
I'm currently using objects and adding functions to the prototype of that object (e.g. MyType.prototype.whatever = function(){ ... }), but the thought occurred to me that if I never create an object of MyType, why bother initializing the prototype of MyType?
Another way to do what I'm thinking, this time using object prototypes (again, there might be 300 functions added to the prototype of type1. The idea I'm asking is if it makes any sense at all to not go ahead and add them to the prototype of type1 if a type1 is never created):
var widget = {
_type1Init: function()
{
widget.type1.prototype.getName = function() {
return this._name;
}
widget._type1Init = function(){} //So calling again won't do anything.
},
type1: function(args) {
widget._type1Init();
this._name = args.name;
}
}
if(*someCondition*)
var obj = new widget.type1({ name: "hello world" }); // If an object is created, it gets initilized, otherwise it won't.
Maybe you should consider:
function type1(argObj){
// use arguments Array for all arguments - you have Object notation
this._name = argObj.name;
// not sure why you need this function
this.getName = function(){
return this._name;
}
}
function widget(){
this.type1 = type1;
}
I'm not really sure what you want to achieve, but I think this is a case for prototype
var widget = {
type1: function(args) {
this._name = args.name;
}
};
widget.type1.prototype.getName = function() {
return this._name;
}
var w1 = new widget.type1({ name: 'Alice' });
console.log(w1.getName());
var w2 = new widget.type1({ name: 'Bob' });
console.log(w2.getName());
See JSFiddle
Personally, I'd consider... not necessarily a whole restructure, but if your module/widget has:
a) known "private static" functions (utilities or stateless transformers) that you want to reuse
b) functions which must operate on instance-specific state
Then you're in the market for an IIFE.
{
widget_1 : (function () {
var private_static_method = function (a, b, c) {
}; // no access to instance-based, closure state, unless passed as arguments
return function (d, e, f) {
// d, e and f are currently private, instance-based values (closure-scope)
this.public_method = function () { // this is copied per-instance
// has full access to d, e, f
return private_static_function(d, e, f);
};
this.g = d;
};
}())
}
widget_1 is the returned function.
The constructor which is widget_1 now has private-static access (closure) to whatever is INSIDE the wrapping function, but OUTSIDE of the constructor.
So there's only one copy, with the caveat that the static functions have no sight into any private state (closure) of any instance.
Moreover, taking this one step further would indeed allow you to break up your JS into individual files (which you could build back into one file safely) and have your object work exactly the same way on the other side.
// core-file.js
var my_widgets = {};
// widget-1.js
(function (core) {
var private_static_method = function () { };
// ...
core.widget_1 = function (d, e, f) { };
}(my_widgets));
You can then recombine all of your files and access them just like before, on the other side.
var widget_1a = new my_widgets.widget_1(a, b, c);
If you have absolutely no private state, then rather than the "private static" stuff above, what you can do inside of your IIFE is define a constructor function, and add prototypes to it (these are "public-static", with no access to private state).
widget_1 : (function () {
var Widget_1 = function (d, e, f) { this.g = d; };
Widget_1.prototype.add_one = function () { this.g += 1; };
return Widget_1;
)())
var w1 = new my_widgets.widget_1(x, y, z);
w1.add_one();
w1.g; // == x+1
A combination of enclosed utility functions, enclosed per-instance state, extended prototype functions, et cetera, will allow you to do everything you want, from lowering memory-footprint (I hope you have thousands of these before worrying about this), to chaining together super-secure (higher-memory-usage) objects.
note although doing crazy closure stuff might be secure, client-side code (or, more-especially, the http(s?) bridge between the worlds is very much not...
If a widget is used more than once, than the object/prototype model will conserve memory.
something like this:
var wid = {}
wid.objInit=function(p) { this.p=p }
wid.objInit.prototype.doit=function(){ return this.p + ' it'}
wid.init=function(arg){
var w = new wid.objInit(arg)
return w
}
The prototype is written once, placed into memory once and each object instance can call it.
var w = wid.init('do')
console.log( w.doit() )
var w2 = wid.init('do')
console.log( w2.doit() )

reusable javascript objects, prototypes and scope

MyGlobalObject;
function TheFunctionICanUseRightAwaySingleForAllInstansesAndWithoutInstanse() {
function() {
alert('NO CONSTRUCTOR WAS CALLED');
}
};
The Long-named function must be callable from MyGlobalObject, which in turn must be available as a global (to window) variable in all times after script was loaded. It should support extensibility in accordance with latest standards.
I'm at architectural dilemma of how to built JS base for an application (almost 100% JS).
We need an object i.e. window.MyObject (like a module, like jQuery) so
It can be created with
VAR1
var MyGlobalObjConstructor = function(){
this.GlobalFunctionInObject = function(){
alert('called with MyGlobalObj.GlobalFunctionInObject()');
}
};
window.MyGlobalObj = new MyGlobalObjConstructor();
Is MyGlobalObj extensible? Can I create child objects, which will inherit current state of MyGlobalObj (extended functions/properties MyGlobalObj.NewFunc e.g.)? What is the main difference between using prototype (VAR3)?
By GlobaldFunction I mean single instance for all initialized/instantiated (possibly instantializable) instances..
Or with
VAR2
var MyGlobalObj = {
GlobalFunctionInObject: function...
GlobalFunctionInObject2: function...
};
MyGlobalObj.GlobalFunctionInObject();
// here I lose all hierarchy elements, no prototype,
// can I use GlobalFunctionInObject2 in GlobalFunctionInObject?
Or with
VAR3
var MyGlobalConstuctor = function(){} // already 'well-formed' object
MyGlobalConstuctor.prototype.GlobalFunctionInObject = function...
};
var MyGlobalObj = new MyGlobalConstuctor();
// so I'm sceptical to NEW, because I have ALREADY wrote my functions
// which I expect to be in memory, single instance of each of them,
// so creating MyObject2,3,4 with NEW MyGC() makes no sense to me.
// DO I REALLY HAVE TO USE "MyGlobalConstuctor.prototype." FOR EACH FUNCTION?!!!!
What's the difference defining MyGlobalObj as a function and as an object (result of func or VAR2)?
OR VAR4?
I see in Chrome Debugger both prototype and __proto__ special fields. I've read that that's OK, but why are they not saved in a single prototype?
So, what is the correct/optimal way to implement window.MyObject, so one could MyObject.MyFunction(); What are the differences (pro/contra) of variants 1 2 and 3?
Variation 1 - Mixin
function SomeType() {
var priv = "I'm private";
this.publ = "I'm public";
this.action = function() {
return priv + this.publ;
};
}
var obj = new SomeType();
With this method you are creating a new object every time you call new SomeType(), creating all its methods and adding all this method to the new object. Every time you create an object.
Pros
It looks like classical inheritance so it's easy to understand to Java-C#-C++-etc people.
It can have private variables per instance since you have one function closure per each object you create
It allows multiple inheritance, also known as Twitter-mixins or functional mixins
obj instanceof SomeType will return true
Cons
It consumes more memory as more objects you create because with each object you are creating a new closure and creating each of it's methods again.
Private properties are private, not protected, subtypes can't access them
No easy way to know if a object has some Type as superclass.
Inheritance
function SubType() {
SomeType.call(this);
this.newMethod = function() {
// can't access priv
return this.publ;
};
}
var child = new SubType();
child instanceof SomeType will return false there is no other way to know if child has SomeType methods than look if it has them one by one.
Variation 2 - Object literal with prototyping
var obj = {
publ: "I'm public",
_convention: "I'm public too, but please don't touch me!",
someMethod: function() {
return this.publ + this._convention;
}
};
In this case you are creating a single object. If you are going to need only one instance of this type it can be the best solution.
Pros
It's quick and easy to understand.
Performant
Cons
No privacy, every property is public.
Inheritance
You can inherit a object prototyping it.
var child = Object.create(obj);
child.otherMethod = function() {
return this._convention + this.publ;
};
If you are on a old browser you will need to garantee Object.create works:
if (!Object.create) {
Object.create = function(obj) {
function tmp() { }
tmp.prototype = obj;
return new tmp;
};
}
To know if a object is a prototype of another you can use
obj.isPrototypeOf(child); // true
Variation 3 - Constructor pattern
UPDATE: This is the pattern ES6 classes are sugar syntax of. If you use ES6 classes you are following this pattern under the hood.
class SomeType {
constructor() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
someMethod() {
return this.publ + this._convention;
}
}
class SubType extends SomeType {
constructor() {
super(/* parent constructor parameters here */);
this.otherValue = 'Hi';
}
otherMethod() {
return this._convention + this.publ + this.otherValue;
}
}
function SomeType() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
SomeType.prototype.someMethod = function() {
return this.publ + this._convention;
};
var obj = new SomeType();
You can re-assign the prototype insteadd of adding each method if you are not inheriting and remember to re-assign the constructor property:
SomeType.prototype = {
constructor: SomeType,
someMethod = function() {
return this.publ + this._convention;
}
};
Or use _.extend or $.extend if you have underscore or jquery in your page
_.extend(SomeType.prototype, {
someMethod = function() {
return this.publ + this._convention;
}
};
The new keyword under the hood simply does this:
function doNew(Constructor) {
var instance = Object.create(Constructor.prototype);
instance.constructor();
return instance;
}
var obj = doNew(SomeType);
What you have is a function than has no methods; it just has a prototype property with a list of functions, the new operator means to create a new object and use this function's prototype (Object.create) and constructor property as initializer.
Pros
Performant
Prototype chain will allow you to know if a object inherits from some type
Cons
Two-step inheritance
Inheritance
function SubType() {
// Step 1, exactly as Variation 1
// This inherits the non-function properties
SomeType.call(this);
this.otherValue = 'Hi';
}
// Step 2, this inherits the methods
SubType.prototype = Object.create(SomeType.prototype);
SubType.prototype.otherMethod = function() {
return this._convention + this.publ + this.otherValue;
};
var child = new SubType();
You may think it looks like a super-set of Variation 2... and you'll be right. It's like variation 2 but with a initializer function (the constructor);
child instanceof SubType and child instanceof SomeType will return both true
Curiosity: Under the hood instanceof operator does is
function isInstanceOf(obj, Type) {
return Type.prototype.isPrototypeOf(obj);
}
Variation 4 - Overwrite __proto__
When you do Object.create(obj) under the hood it does
function fakeCreate(obj) {
var child = {};
child.__proto__ = obj;
return child;
}
var child = fakeCreate(obj);
The __proto__ property modifies directly the object's hidden [Prototype] property. As this can break JavaScript behaviour, it's not standard. And the standard way is preferred (Object.create).
Pros
Quick and performant
Cons
Non-standard
Dangerous; you can't have a hashmap since the __proto__ key can change the object's prototype
Inheritance
var child = { __proto__: obj };
obj.isPrototypeOf(child); // true
Comment questions
1. var1: what happens in SomeType.call(this)? Is 'call' special function?
Oh, yes, functions are objects so they have methods, I will mention three: .call(), .apply() and .bind()
When you use .call() on a function, you can pass one extra argument, the context, the value of this inside the function, for example:
var obj = {
test: function(arg1, arg2) {
console.log(this);
console.log(arg1);
console.log(arg2);
}
};
// These two ways to invoke the function are equivalent
obj.test('hi', 'lol');
// If we call fn('hi', 'lol') it will receive "window" as "this" so we have to use call.
var fn = obj.test;
fn.call(obj, 'hi', 'lol');
So when we do SomeType.call(this) we are passing the object this to function SomeCall, as you remember this function will add methods to object this.
2. var3: With your "REALLY define properties" do you mean if I use them in functions? Is it a convention? Because getting this.newProperty without it being defined at the same level with other member functions is not a problem.
I mean any property your object will have that is not a function must be defined on the constructor, not on the prototype, otherwise you will face one of the more confusing JS problems. You can see it here, but it's outside of the focus of this question.
3. Var3: what happens if I don't re-assign constructor?
Actually you might not see the difference and this is what makes it a dangerous bug. Every function's prototype object has a constructor property so you can access the constructor from an instance.
function A() { }
// When you create a function automatically, JS does this:
// A.prototype = { constructor: A };
A.prototype.someMethod = function() {
console.log(this.constructor === A); // true
this.constructor.staticMethod();
return new this.constructor();
};
A.staticMethod = function() { };
It's not a best practice because not everybody knows about it, but sometimes it helps. But if you reassign the prototype...
A.prototype = {
someMethod = function() {
console.log(this.constructor === A); // false
console.log(this.constructor === Object); // true
this.constructor.staticMethod();
return new this.constructor();
}
};
A.prototype is a new object, a instance of Object than prototypes Object.prototype and Object.prototype.constructor is Object. Confusing, right? :P
So if you overwrite the prototype and don't reset the "constructor" property, it will refer to Object instead of A, and if you try to use the "constructor" property to access some static method you may get crazy.
I usually settle with returning an object with functions as properties:
var newCat = function (name) {
return {name: name, purr: function () {alert(name + ' purrs')}};
};
var myCat = newCat('Felix');
myCat.name; // 'Felix'
myCat.purr(); // alert fires
You can have inheritance by calling the newCat function and extend the object you get:
var newLion = function (name) {
var lion = newCat(name);
lion.roar = function () {
alert(name + ' roar loudly');
}
return lion;
}
If you want a global cats object:
var cats = (function () {
var newCat = function (name) {
return {
name: name,
purr: function () {
alert(name + ' is purring')
}
};
};
return {
newCat: newCat
};
}());
Now you can call:
var mySecondCat = cats.newCat('Alice');

javascript property accessors

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);

Getter/setter in constructor

I recently read about the fact that there is a possibility of defining getters/setters in JavaScript. It seems extremely helpful - the setter is a kind of 'helper' which can parse the value to be set first, before actually setting it.
For example, I currently have this code:
var obj = function(value) {
var test = !!value; // 'test' has to be a boolean
return {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new obj(true);
This code always converts value to a boolean. So if you code instance.test = 0, then instance.test === false.
However, for this to work you have to actually return an object, which means that the new instance is not of type obj but just is a plain object. This means that changing the prototype of obj has no effect on instances. For example, this does not work - instance.func is undefined:
obj.prototype.func = function() { console.log(this.value); };
because instance is not of type obj. To get the prototype functions work, I guess I should not return a plain object, but rather not return anything so that instance would just be of type obj, like a regular constructor works.
The problem then is how to implement getters/setters? I can only find articles describing how to add these to an object, not as being part of the constructor of a custom type.
So how do I implement getters/setters in the constructor so as to be able to both use getters/setters and extending the prototype?
You can't do that.
You can set setter/getters for properties of objects though. I advice you use ES5 Object.defineProperties though. of course this only works in modern browsers.
var obj = function() {
...
Object.defineProperties(this, {
"test": {
"get": function() { ... },
"set": function() { ... }
}
});
}
obj.prototype.func = function() { ... }
var o = new obj;
o.test;
o.func();
Usually you want class methods. The answer by #Raynos on May 7, 2011 gets the job done, but it defines an instance method, not a class method.
The following illustrates a class definition with a the getter and setter being part of the class. This definition is a lot like the answer by #Raynos, but with two differences in the code: (1) The "defineProperties()" action has been moved out of the constructor. (2) The argument to "defineProperties()"as been changed from the instance object "this", to the constructor's prototype object.
function TheConstructor(side) {
this.side = side;
}
Object.defineProperties(TheConstructor.prototype, {
area: {
get: function() { return this.side * this.side; }
,set: function(val) { this.side = Math.sqrt(val); }
}
});
// Test code:
var anInstance = new TheConstructor(2);
console.log("initial Area:"+anInstance.area);
anInstance.area = 9;
console.log("modified Area:"+anInstance.area);
Which produces these results:
initial Area:4
modified Area:9
Although usually the distinction between class versus instance
definition is just a matter of style, there is a purpose to
good style, and there is a case where the distinction matters:
the memoized getter. The purpose for a memoized getter is
described here: Smart/self-overwriting/lazy getters
Define the getter at the class level when the memoized value is to
pertain to the entire class. For example, a configuration file
should be read only once; the resulting values should then apply
for the duration of the program. The following sample code
defines a memoized getter at the class level.
function configureMe() {
return 42;
}
Object.defineProperties(TheConstructor.prototype, {
memoizedConfigParam: {
get: function() {
delete TheConstructor.prototype.memoizedConfigParam;
return TheConstructor.prototype.memoizedConfigParam = configureMe();
}
,configurable: true
}
});
// Test code:
console.log("memoizedConfigParam:"+anInstance.memoizedConfigParam);
Produces:
memoizedConfigParam:42
As can be seen in the example, memoized getters have the
characteristic that the getter function deletes itself,
then replaces itself with a simple value that
(presumably) will never change.
Note that 'configurable' must be set to 'true'.
Define the getter at the instance level when the memoized value
depends upon the contents of instance. The definition moves
inside the constructor, and the object of attention is 'this'.
function TheConstructorI(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
return this.memoizedCalculation = this.expensiveOperation();
}
,configurable: true
}
});
}
TheConstructorI.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instance2 = new TheConstructorI(2);
var instance3 = new TheConstructorI(3);
console.log("memoizedCalculation 2:"+instance2.memoizedCalculation);
console.log("memoizedCalculation 3:"+instance3.memoizedCalculation);
Produces:
memoizedCalculation 2:8
memoizedCalculation 3:27
If you want to guarantee (rather than presume) that the memoized
value will never be changed, the 'writable' attribute needs to
be changed. That makes the code a bit more complicated.
function TheConstructorJ(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
Object.defineProperty( this, 'memoizedCalculation'
,{ value : this.expensiveOperation()
,writable : false
});
return this.memoizedCalculation;
}
,configurable: true
}
});
}
TheConstructorJ.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instanceJ = new TheConstructorJ(2);
console.log("memoizedCalculation:"+instanceJ.memoizedCalculation);
instanceJ.memoizedCalculation = 42; // results in error
Produces:
memoizedCalculation:8
>Uncaught TypeError: Cannot assign to read only property 'memoizedCalculation' of object '#<TheConstructorJ>'
The OP's original question, from March 7, 2011, presented basic
getter and setter syntax, noted that it worked on an object but
not on 'this', and asked how to define getters and setters within
a constructor. In addition to all the examples above, there is
also a "cheap-shot" way of doing it: create a new object within
the constructor, like the OP did, but then assign the object to
be a member within 'this'. So, the original code would look like
this:
var MyClass = function(value) {
var test = !!value; // 'test' has to be a boolean
this.data = {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new MyClass(true);
// But now 'data' is part of the access path
instance.data.test = 0;
console.log(instance.data.test);
Produces:
false
Believe it or not, I have actually run into situations where
this "cheap-shot" is the best solution. Specifically, I used this
technique when I had records from several tables encapsulated within
a single class, and wanted to present a unified view as though
they were a single record called 'data'.
Have fun.
IAM_AL_X
Update for ES6 -- have a look at section 19.3.1 of Alex Rauschmayer's book Exploring ES6 http://exploringjs.com/es6/ch_maps-sets.html#sec_weakmaps-private-data which demonstrates how to use WeakMaps with getters and setters to hold private data. Combining with section 16.2.2.3 http://exploringjs.com/es6/ch_classes.html#leanpub-auto-getters-and-setters would result in something like
# module test_WeakMap_getter.js
var _MyClassProp = new WeakMap();
class MyClass {
get prop() {
return _MyClassProp.get( this );
}
set prop(value) {
_MyClassProp.set( this, value );
}
}
var mc = new MyClass();
mc.prop = 5 ;
console.log( 'My value is', mc.prop );
$ node --use_strict test_WeakMap_getter.js
My value is 5
function Obj(value){
this.value = !!value;
}
Obj.prototype = {
get test () {
return this.value;``
},
set test (value) {
this.value = !!this.value;
}
};
var obj = new Obj(true);
I know this might be extremely late but I figured out a different way to accomplish what you want and for the sake of people, like myself, googling for an answer to this here it is.
function Constructor(input){
this.input = input;
}
Object.__defineGetter__.call(Constructor.prototype, "value", function(){
return this.input * 2;
});
var test = new Constructor(5);
alert(test.value) // 10
I've tested this in chrome, safari, mobile safari, firefox and they all work (latest versions of course)
#Alex I see it as more option and more power, programming is art, #Nat share his finding with us, and for that I thank him. Maybe someone want to do it that way.
I'm sure the setter version is the same but just changing that g to a s.
i.g:
function Constructor(input){
this.input = input;
}
Object.__defineGetter__.call(Constructor.prototype, "value", function(){
return this.input * 2;
});
Object.__defineSetter__.call(Constructor.prototype, "bar", function(foo){
return this.input *= foo;
});
var test = new Constructor(5);
console.log(test.value); // 10
test.bar = 5;
console.log(test.input); //25
With that said, this feature is deprecated, advices to not to use in production coding.

Categories

Resources