I would like to implement a builder using closures in JavaScript. I feel it can be done, but am struggling to put it into code.
I have something like this but I feel there is probably a better solution leveraging something like partial application.
function Builder() {
this.spec = {};
}
Builder.prototype.withFoo = function(value) {
this.spec.foo = value;
return this;
};
Builder.prototype.withBar = function(value) {
this.spec.bar = value;
return this;
};
Builder.prototype.build = function() {
var result = {};
result.foo = this.spec.foo;
result.bar = this.spec.bar;
this.spec = {}; // This is to avoid accidentally using the same builder repeatedly.
return result;
};
var builder = new Builder();
builder.withFoo('foo value')
.withBar('foo value')
.build(); // { foo: 'foo value' , bar: 'bar value' }
Can anyone help me do this?
Edit: The key thing here is that I want the object to be instantiated lazily.
Here is an alternative approach:
function Builder(obj){
return obj;
}
This is called by Fowler and Martin the "Identity Builder" and is quite common in enterprise architecture. It has the advantage of supporting arbitrarily nested hierarchies of objects and sub objects and it is completely generic.
var myBuildObject = Builder({
spec: {
foo: foo,
bar: bar
}
});
It does so much more though, it can also easily specify arrays:
var myBuildObject = Builder({
spec: [....]
});
It can be extended and subclassed with more sophisticated builders that can in turn do return Builder.call(this, obj) after decorating it.
It can even specify getters/setters.
It is usual with a builder to be able to chain the calls together, so something like the below should do what you're after:
var builder = (function(){
var obj = {};
return {
withFoo: function(foo){
obj.foo = foo;
return this;
},
withBar: function(bar){
obj.bar = bar;
return this;
},
build: function(){
var rtn = obj;
obj = {}; // clear so you can use builder again
return rtn;
}
}
})();
var result = builder.withFoo("foo")
.withBar("bar")
.build();
console.log(result); // { foo: 'foo' , bar: 'bar' }
Having said that, I like to have an instance of the builder, so in all honesty I prefer your original (except with return this to return the current instance of the builder from the methods). So I'd personally go with:
function Builder() {
this.spec = {};
}
Builder.prototype.withFoo = function(value) {
this.spec.foo = value;
return this;
};
Builder.prototype.withBar = function(value) {
this.spec.bar = value;
return this;
};
Builder.prototype.build = function() {
return this.spec;
};
var result = new Builder()
.withFoo('foo value')
.withBar('foo value')
.build();
Note there is no need to clear out spec when callingbuild - a new instance of Builder will have a new instance of spec!
One simple way to invoke code lazily is partial application and currying in particular.
Let's say you have a Person type and it looks like this:
function Person(name, lastName, age, height){
return {
name: name,
lastName: lastName,
age: age,
height: height
};
}
var pete = Person("Pete", "Doe", 40, 6.4);
What we really want it to do - is to be able to specify only some of those properties initially and some later:
var namedJoeDoe = Person("Joe", "Doe"); // won't work today
var tallJoe = namedJoeDoe(40, 8.6); // one object
var shortJoe = namedJoeDoe(40, 4.3); // another object
We only create the object (and your real objects are probably larger at the very end. This is currying, and if we use Ramda's curry we can write it as such:
Person = R.curry(Person); // impl at src/curryN.js
We get exactly this functionality, quoting the docs:
Returns a curried equivalent of the provided function. The curried function has two unusual capabilities. First, its arguments needn't be provided one at a time. If f is a ternary function and g is R.curry(f), the following are equivalent:
g(1)(2)(3)
g(1)(2, 3)
g(1, 2)(3)
g(1, 2, 3)
That is, only when you've supplied all properties for a person will an instance be created.
Related
I'm looking for a fast and clean way to attach a couple of reflection methods on objects located inside an array, but I don't want to monkey-patch the objects. The objects themselves may be of varying sizes as they're returned from a dynamic JSON endpoint, thus not going down the route of ObjWrapper(obj) { this.foo = obj.foo; }.
I've come up with the following code, but I do feel there would be a more elegant way to achieve the same result. I would be happy to explore the use of Lodash's functions:
var objs = [{foo:'bar'}, {foo:'baz'}];
function ObjWrapper(obj){
var self = this;
// Inherit all the shallow object properties
Object.keys(obj).forEach(function(key){
self[key] = obj[key];
});
}
ObjWrapper.prototype.isBar = function() {
return this.foo === 'bar';
}
ObjWrapper.prototype.isBaz = function() {
return this.foo === 'baz';
}
objsWrapped = objs.map(function(obj){
return new ObjWrapper(obj);
});
objsWrapped.forEach(function(objWrapped){
console.log(objWrapped.isBar());
console.log(objWrapped.isBaz());
});
I'm not seeing a performance difference in this approach over using a static function to evaluate the object logic: http://jsperf.com/object-wrapping
For clarity, the question is; can this be written better?
First of all to your approach, though it is not quite a bad solution, but in a ObjWrapper constructor you modifes the ObjWrappers hidden class, and you will become the performance penalties. More about hidden classes.
Some options you have.
As you have already mentioned, monky-patch original objects.
Create a proxy object
function ObjProxy(obj) {
this.data = obj;
}
ObjProxy.prototype = {
isFoo () {
return this.data.foo === 'foo';
}
}
Merge two objects. Similar to your solution, but now we work with raw objects
var Methods = {
isFoo () {
return this.foo === 'foo'
}
};
var obj = {foo: 'foo'};
var objWrapper = Object.assign({}, obj, Methods);
Functions: Utility methods are also a good solution, as you can use them as filters.
function isFoo(obj) {
return obj.foo === 'foo';
}
// Or as an utility object
var Methods = {
isBar (obj) {
return obj.foo === 'bar';
}
}
objs.filter(isFoo).filter(Methods.isBar);
Fourth option has the best performance, und I think will suite here the most.
maybe you need to replace this implementation:
ObjWrapper.prototype.isBar = function()
{
return this.foo === 'bar';
}
with this one:
ObjWrapper.prototype.isType = function(type)
{
return this.foo === type;
}
then just call:
console.log(objWrapped.isType('bar'));
the parameter itself ('bar') can be replaced with any variable
I'm trying to find a javascript OOP approach, where the variables should be private (not accessible from the outside) using non-privileged methods.
The following example should demonstrate it:
var Person = (function() {
var _name;
var _surname;
var _personID;
function Person(name, surname, personID) {
_name = name;
_surname = surname;
_personID = personID;
}
Person.prototype.getName = function() {
return _name;
};
Person.prototype.getSurname = function() {
return _surname;
};
Person.prototype.getPersonID = function() {
return _personID;
};
return Person;
})();
//Testing
var max = new Person('Max', 'Smith', 2345);
max._name = 'John';
console.log(max.getName()); // Max
console.log(max.getSurname()); // Smith
console.log(max.getPersonID()); // 2345
It seems to fulfill the conditions, so max._name = 'John' does not change the value and the methods are still getting the private values (without using .this)
But, the problem is, that creating a further object is obviously the same object, it refers to the same values:
//Testing
var max = new Person('Max', 'Smith', 2345);
var max2 = new Person('Max2', 'Smith2', 2345);
console.log(max.getName()); // Max2
console.log(max.getSurname()); // Smith2
console.log(max.getPersonID()); // 2345
console.log(max2.getName()); // Max2
console.log(max2.getSurname()); // Smith2
console.log(max2.getPersonID()); // 2345
How can I create different objects without making the values public? Is it at all possible in Javascript?
Is it at all possible in Javascript?
No, it's not. Stop searching, you'll never find an approach.
Just use privileged methods, there's nothing wrong with them.
Maybe this is what you're looking for. I also include some code for animals to demonstrate how inheritance might be done. And actually, I think you can drop the 'new' keyword (though maybe it gets re-added behind the scenes, not sure).
http://plnkr.co/edit/6nW3DtqJWEu7fZ29GMOC?p=preview
var Person = (function(){
function Person(name, surname, personId){
var _name = name, _surname = surname, _personId = personId;
return Object.freeze({
getName: getName,
getSurname: getSurname,
getPersonID: getPersonID
});
function getName(){
return _name;
}
function getSurname(){
return _surname;
}
function getPersonID(){
return _personId;
}
}
return Person;
})();
var max = new Person('Max', 'Smith', 2345);
var max2 = Person('Max2', 'Smith2', 2346);
max._name = 'John';
console.log(max.getName()); // Max
console.log(max.getSurname()); // Smith
console.log(max.getPersonID()); // 2345
console.log(max2.getName()); // Max2
console.log(max2.getSurname()); // Smith2
console.log(max2.getPersonID()); // 2346
Edit: I'm not sure my solution qualifies as 'non-privileged' based on Douglas Crockford's definition. I do believe that page is outdated and I'm using his new syntax using Object.freeze() which means it is no longer possible to delete or alter the public methods.
Edit2: I shamelessly stole that syntax from The Better Parts. Give it a watch.
Just for the sake of curiosity, I was playing with prototypal inheritance and OOP inheritance in Javascript. Most results involve emulating 'Class' and 'extends' concepts with functions, while others use the prototype and constructors.
I wrote this code:
function Warrior(weaponName) {
var weapon = weaponName;
this.getWeapon = function() {
return weapon;
};
this.setWeapon = function(value) {
weapon = value;
};
this.displayInfo = function() {
return {
"weapon": this.getWeapon(),
};
};
}
function Archer() {
var accuracy = "86%";
this.parent = Archer.prototype; // Inheritance workaround
this.getAccuracy = function() {
return accuracy;
};
this.setAccuracy = function(value) {
accuracy = value;
};
this.displayInfo = function() {
var form = this.parent.displayInfo();
form.accuracy = this.getAccuracy();
return form;
};
}
Archer.prototype = new Warrior("bow");
var w = new Warrior("sword");
var a = new Archer();
console.log(w.displayInfo());
console.log(a.displayInfo());
I made this so when displaying the information from the Warrior class, it shows the object as
{ weapon: "sword" }
And when the information from Archer is shown, the object is:
{ weapon: "sword", accuracy: "86%" }
The "subclass" is taking information from the "superclass" and adding to it. Calling "getWeapon()" or "setWeapon" from Archer also works. The chain goes on without problems, even when I add a third class "Kyudoka" that extends "Archer" and has it's own properties as well.
But comparing to the more complex code I found while researching, I feel this could be a naive implementation (the "Inheritance workaround" line) and I'm missing something (considering that JS has a lot of subtlety).
This is a theorical question, I'm not using this code in any system.
There are mainly 3 kinds of inheritance in javascript, according to the book Javascript the Good Parts: Pseudoclassical, Prototypal and Functional.
The one you just posted would fit under the Pseudoclassical inheritance, where you emulate a Class behaviour using constructor functions.
I find more useful and flexible the Functional pattern, which allows you to protect your variables (make them private).
var constructor = function (spec, my) {
var that, other private instance variables;
my = my || {};
//Add shared variables and functions to my
that = a new object;
//Add privileged methods to that
return that;
}
Prototypal is basically having your objects inherit directly from other useful object, which would be something like having them (the useful objects) as your new object constructor prototype.
Object.beget = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
var a = {}
//Add shared variables to a
var b = Object.beget(a);
//Add new methods to b
That are many considerations to each of the patterns, for instance Crockford says in his book "The functional pattern has a great deal of flexibility. It requires less effort than the pseudoclassical pattern,
and gives us better encapsulation and information hiding and access to super methods.", but I've also seen articles arguing the other way around, such as this http://bolinfest.com/javascript/inheritance.php
EDIT ------
In case you might want to know different aproaches to reaching super methods, in the Functional pattern you can do the following:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function ( ) {
return method.apply(that, arguments);
};
});
var archer = function (spec, accuracy) {
var that = warrior(spec),
super_displayInfo = that.superior('displayInfo');
that.getAccuracy = function() {
return accuracy;
};
that.setAccuracy = function(value) {
accuracy = value;
};
that.displayInfo = function (n) {
var form = super_displayInfo()
form.accuracy = that.getAccuracy();
return form;
};
return that;
};
Put the functions on the prototype...
function Warrior(weaponName) {
this.weapon = weaponName;
}
Warrior.prototype = {
getWeapon : function() {
return this.weapon;
},
setWeapon : function(value) {
this.weapon = value;
},
displayInfo : function() {
return { "weapon" : this.getWeapon() };
}
};
//----------------------------------
function Archer(weaponName) {
Warrior.call(this, weaponName);
this.accuracy = "86%";
}
Archer.prototype = Object.create(Warrior.prototype);
Archer.prototype.constructor = Archer;
Archer.prototype.getAccuracy = function() {
return this.accuracy;
};
Archer.prototype.setAccuracy = function(value) {
this.accuracy = value;
};
Archer.prototype.displayInfo = function() {
return "weapon: " + this.getWeapon() + ", accuracy: " + this.getAccuracy();
};
//----------------------------------
var w = new Warrior("sword");
var a = new Archer("axe");
console.log(w.displayInfo()); // Object {weapon: "sword"}
console.log(a.displayInfo()); // weapon: axe, accuracy: 86%
Edit: fixed recursion
Considering object creation patterns with private properties, one way to do is :
function MyStack (){
var list = [],
index = 0;
this.push = function(val){
return list[index++] = val;
};
this.pop = function(){// ...}
}
var stack1 = new MyStack(); stack1.push(5);
var stack2 = new MyStack(); stack2.push(11);
Problem with this: Every instance of Stack has it's own copy of methods 'push' and 'pop'.
Another way for implementing constructor method is:
function MyStack(){
this.list = [];
this.index = 0;
}
MyStack.prototype = {
insert: function(val){
return this.list[this.index++] = val;
},
pop:function(){//...}
}
Problem here: We lose the privacy of list and index.
Is there a way, such that we can have both methods reuse among instances and privacy of properties ?
I understand that we can have this for methods that don't operate on any state of the object, but I am talking more about those methods that do operate on the state.
Yes. I've edited this code so it's actually fully functional as you had intended it to work. It seems a bit redundant to me, but, it does provide you the ability to provide a public interface, but to keep your variables private and control the way the user interacts with them.
function MyStack(){
var list = [];
var index = 0;
this.getIndex = function(){
return index;
}
this.setIndex = function(val){
index = val;
}
this.list = function(val){
if(val){
// setter if a value was provided. Illustrating how you can control
// index, which I assume is the point of having these things private
// to begin with
return list[this.setIndex(this.getIndex() + 1)] = val;
}
// always return list - acts like a getter
return list;
}
}
MyStack.prototype = {
insert: function(val){
return this.list(val);
},
pop:function(){}
}
var stack1 = new MyStack();
stack1.insert(5);
var stack2 = new MyStack();
stack2.insert(11);
You should check out John Resig's Simple Javascript Inheritance. It is a great read, and it has been extended to provide support for privates, aptly called Privates.js;
A constructor function may return any object (not necesserily this). One could create a constructor function, that returns a proxy object, that contains proxy methods to the "real" methods of the "real" instance object. This may sound complicated, but it is not; here is a code snippet:
var MyClass = function() {
var instanceObj = this;
var proxyObj = {
myPublicMethod: function() {
return instanceObj.myPublicMethod.apply(instanceObj, arguments);
}
}
return proxyObj;
};
MyClass.prototype = {
_myPrivateMethod: function() {
...
},
myPublicMethod: function() {
...
}
};
The nice thing is that the proxy creation can be automated, if we define a convention for naming the protected methods. I created a little library that does exactly this: http://idya.github.com/oolib/
I think in both approaches you mentioned, When ever object is created using constructor pattern the properties will get copied to its objects. This you mentioned for the 1st approach as the concern. I feel the same will be applied for the second approach also along with your concern in this approach.
We generally go to the second approach you mentioned when ever we want to extend the properties of "MyStack" to some other class.
Lets say i want to extend your class MyStack to MyTest like below
var dummy = function();
dummy.prototype = MyStack.prototype;
var MyTest = function(){
};
MyTest.prototype = new dummy(); // Assigning MyStack properties to MyTest
var obj = new MyTest();
I think the following code will make the question clear.
// My class
var Class = function() { console.log("Constructor"); };
Class.prototype = { method: function() { console.log("Method");} }
// Creating an instance with new
var object1 = new Class();
object1.method();
console.log("New returned", object1);
// How to write a factory which can't use the new keyword?
function factory(clazz) {
// Assume this function can't see "Class", but only sees its parameter "clazz".
return clazz.call(); // Calls the constructor, but no new object is created
return clazz.new(); // Doesn't work because there is new() method
};
var object2 = factory(Class);
object2.method();
console.log("Factory returned", object2);
A simpler, cleaner way with no "factories"
function Person(name) {
if (!(this instanceof Person)) return new Person(name);
this.name = name;
}
var p1 = new Person('Fred');
var p2 = Person('Barney');
p1 instanceof Person //=> true
p2 instanceof Person //=> true
Doesn't this work?
function factory(class_, ...arg) {
return new class_(...arg);
}
I don't understand why you can't use new.
If you really don't want to use the new keyword, and you don't mind only supporting Firefox, you can set the prototype yourself. There's not really any point to this though, since you can just use Dave Hinton's answer.
// This is essentially what the new keyword does
function factory(clazz) {
var obj = {};
obj.__proto__ = clazz.prototype;
var result = clazz.call(obj);
return (typeof result !== 'undefined') ? result : obj;
};
I guess browser independent solution would be better
function empty() {}
function factory(clazz /*, some more arguments for constructor */) {
empty.prototype = clazz.prototype;
var obj = new empty();
clazz.apply(obj, Array.prototype.slice.call(arguments, 1));
return obj;
}
Because JavaScript doesn't have classes, let me reword your question: How to create a new object based on an existing object without using the new keyword?
Here is a method that doesn't use "new". It's not strictly a "new instance of" but it's the only way I could think of that doesn't use "new" (and doesn't use any ECMAScript 5 features).
//a very basic version that doesn't use 'new'
function factory(clazz) {
var o = {};
for (var prop in clazz) {
o[prop] = clazz[prop];
}
return o;
};
//test
var clazz = { prop1: "hello clazz" };
var testObj1 = factory(clazz);
console.log(testObj1.prop1); //"hello clazz"
You could get fancy and set the prototype, but then you get into cross-browser issues and I'm trying to keep this simple. Also you may want to use "hasOwnProperty" to filter which properties you add to the new object.
There are other ways that use "new" but sort of hide it. Here is one that borrows from the Object.create function in JavaScript: The Good Parts by Douglas Crockford:
//Another version the does use 'new' but in a limited sense
function factory(clazz) {
var F = function() {};
F.prototype = clazz;
return new F();
};
//Test
var orig = { prop1: "hello orig" };
var testObj2 = factory(orig);
console.log(testObj2.prop1); //"hello orig"
EcmaScript 5 has the Object.create method which will do this much better but is only supported in newer browsers (e.g., IE9, FF4), but you can use a polyfill (something that fills in the cracks), such as ES5 Shim, to get an implementation for older browsers. (See John Resig's article on new ES5 features including Object.create).
In ES5 you can do it like this:
//using Object.create - doesn't use "new"
var baseObj = { prop1: "hello base" };
var testObj3 = Object.create(baseObj);
console.log(testObj3.prop1);
I hope that helps
Another way:
var factory = function(clazz /*, arguments*/) {
var args = [].slice.call(arguments, 1);
return new function() {
clazz.apply(this, args)
}
}
To answer the question more literally, i.e. how to have myClass() return new myClass()... It's not possible, and here's why...
You'd have to do it like this, to make sure that the class name exists and that you're capturing calls to myClass() (using apply functionality, from Proxy/trap/handler-land):
class A {
}
A.prototype.apply = function() {
return new A();
}
A(); //Error occurs here.
OR:
class B {
}
B.apply = function() {
return new B();
}
B(); //Error occurs here.
And the reason this doesn't work is the output when you try to evaluate either of the above: Uncaught TypeError: class constructors must be invoked with 'new'
Thus, JavaScript literally does not allow it, because you have declared it to be a class type. However, you can of course have a separately named function that creates a new instance for you, like in the answer above, or more simply:
class A {
}
//Note: a != A.
function a() {
return new A();
}
OR, another way to approach this problem is to not use a class, per-se, but a function or a regular JS object {}, like in the older days of JavaScript. Multiple other answers show how to do this.
What you could also do is use eval.
Of course there are security concerns with eval, but is it really different to any other dynamic instanciation?
await import("/path/to/module") //use this to dynamically load module if you like
let obj = `eval new ${classname}();`