Learning Javascript I am finding different ways for creating objects. Seems that the way forward is using Object.create()
It's pretty hard to find a solid answer on best practises for using Object.create() as even the specific Object.create() articles seem to do things slightly different.
What I want to do is create multiple objects with their own encapsulated data.
I like to use encapsulation and what seems to work for me is something like
function Foo() {
var message = "Hello";
return {
bar:bar
}
function bar(){
return message;
}
}
World = (function(){
var obj = Foo();
var tank = Object.create(obj);
return {
baz:baz
}
function baz(){
alert(tank.bar());
}
})();
Running World.baz() works as expected but I am still not sure if I am doing this right.
All answers will be appreciated, thanks.
Generally in javascript you want to create objects like so:
var obj = {};
obj.someProperty = 'someValue';
obj.someOtherProperty = 'someOtherValue';
Or, you could use object literal notation, like this:
var obj = {
someProperty: 'someValue',
someOtherProperty: 'someOtherValue'
};
The Object.create function is an interesting one. Yes, it does create an empty object, but it isn't like the objects defined above. Instantiating and object with Object.create will give the new empty object inheritance up to the parameter you give the Object.create function. For instance, if we define an object as:
var actions = {
shout: function(message){
console.log(message.toUpperCase() + '!');
}
}
And then create a new object with Object.create():
var newObject = Object.create(actions); // creates a new object: newObject = {};
newObject will not contain any of it's own properties, but it will be able to access the properties of the parent actions object. After defining those object, try this out:
newObject.hasOwnProperty('shout'); // returns false
newObject.shout('Hello!'); // logs 'HELLO!!'
This example just goes to show how inheritance works from the newly created object to it's parent. This can be extremely useful, but make sure you specifically want that behavior before creating objects with Object.create-- otherwise, better be safe and use one of the two other methods above.
Hope that helps!
Edit:
Alternatively, if you're just trying to create many separate instances of the same object, you can create a constructor and invoke it with the new keyword, like this:
var Tank = function(speed, durability){
this.speed = speed;
this.durability = durability;
this.location = 0;
this.shoot = function(){
console.log('Pew pew');
};
this.move = function(){
this.location += speed;
};
}
var myTank = new Tank(5, 15); // creates new tank with speed 5 and durability 15,
// that also has all the default properties and methods,
// like location, shoot, and move.
var yourTank = new Tank(7, 12); // instantiates a different tank that myTank, with it's
// own speed and durability properties, but also has the
// default location, shoot, and move properties/ methods
var enemyTank = new Tank(10, 25);// instantiates yet another, unique tank with it's own
// unique values for speed and durability, but again with
// the default location, shoot, and move properties/methods
Try this approach for creating javaScript objects that encapsulating data. As you can see each instance of Foo has its own properties and state.
var Foo = function() {
var Foo = function Foo(customMessage) {
this.message = customMessage || "Hello";
}
Foo.prototype.message;
Foo.prototype.bar = function(){
return this.message;
}
return Foo;
}();
var tank1 = new Foo();
var tank2 = new Foo("Goodbye");
alert(tank1.bar());
alert(tank2.bar());
I would suggest using constructors to encapsulate data. If you really need to use Object.create(), you need to create a constructor-prototype system with Object.create(). However, in any case, you're just calling .bar() from the result of Foo() in the .baz() method of World. That does not mean World should point to the result of Foo().
Object.prototype.__construct = function() {
//This is the default constructor from any new object. We change it to change the constructor of objects as we go along. We could make no __construct method on Object.prototype because it doesn't do anything, so we're not going to call it, but we're going to define it anyway since we want all objects to have a __construct method, even if they don't define a new one on top of the default.
};
//Object.prototype is our default object. We add methods to object to change the prototype of objects as we go along.
var Foo = {}; //Any object that doesn't inherit from anything must inherit from Object.prototype. We do this by just setting it to {} (or new Object()).
//If we're going to define a new constructor, we need to call it _after_ we've defined it.
Foo.__construct = function() {
var message = "Hello!";
this.bar = function() {
return message;
}
};
Foo.__construct();
Foo.bar() //returns "Hello!"
//Note that message is encapsulated and _cannot_ be accessed through Foo itself.
var World = {}; //World _does not_ point to Foo. It simply calls a method of Foo in one of its methods.
World.__construct = function() {
//Now, if the method of Foo we're going to call in the method of World is going to alter Foo, then we should make a copy of Foo using Object.create(). The method we're going to call isn't _actually_ going to alter Foo, but it's good practice to make a copy because it _could_ if we made it so.
var obj = Object.create(Foo);
//Because Foo has been constructed and obj is a copy of Foo, we don't need to construct obj. We only need to construct an object if we define a new constructor property.
this.baz = function() {
alert(obj.bar());
};
};
World.__construct();
World.baz() //alerts "Hello!"
//Note that obj is encapsulated within World. obj points to Foo, but again, World _does not_ point to Foo.
Related
I'm not sure if the Title actually made any sense but however I'm trying to set a functions prototype to "sub classes" prototype.
For coming example;
What I try to do is : I have a user and paidUser . paidUser is subclass ofuser
User Factory function :
function userCreator(name, score) {
this.name = name;
this.score = score;
}
userCreator.prototype.sayName = function(){console.log("hi");}
userCreator.prototype.increment = function(){this.score++;}
And I can create a new user with new keyword. so far so good.
const user1 = new userCreator("Phil", 5);
Now , coming to Subclassing . (accountBalance is just a silly property special for paidUser for my example)
function paidUserCreator(paidName, paidScore, accountBalance){
userCreator.call(this, paidName, paidScore);
this.accountBalance = accountBalance;
}
now I want to set prototype of my userCreator as the prototype of paidUserCreator Factory Function
The following line works perfectly, but I don't understand it quite. Object.create function is supposed to created an empty object and that empty objects __proto__ must be the given parameter.
paidUserCreator.prototype =Object.create(userCreator.prototype);
paidUserCreator.prototype.increaseBalance = function(){
this.accountBalance++;
}
Another point what I don't understand is :
Why the following line doesn't work ?
Object.setPrototypeOf(paidUserCreator, userCreator.prototype);
For completion :
const paidUser1 = new paidUserCreator("Katarina", 4, 12);
PS: Yes I know the Class keyword is much cleaner and nicer to read but I want to learn how to do it in this way.
Starting with the last question:
Why the following line doesn't work ?
Object.setPrototypeOf(paidUserCreator, userCreator.prototype);
It will, but you need to set the prototype of paidUserCreator.prototype not the function paidUserCreator so that when an instance looks for something on the paidUserCreator.prototype and doesn't find it, it will look to userCreator.prototype.
function userCreator(name, score) {
this.name = name;
}
userCreator.prototype.sayName = function() {
console.log("hi");
}
function paidUserCreator(paidName, paidScore, accountBalance) {
userCreator.call(this, paidName, paidScore);
}
Object.setPrototypeOf(paidUserCreator.prototype, userCreator.prototype);
let p = new paidUserCreator("Mark", 98, 200.5)
p.sayName()
paidUserCreator.prototype = Object.create(userCreator.prototype) is similar. Object.create makes a new object and sets it's prototype to point to the object passed in. When you do this you are replacing paidUserCreator.prototype with a new object that is prototype linked to userCreator.prototype. One caveat with this is that if there is anything on paidUserCreator.prototype that you need it will be lost because you are replacing the whole object, not just setting the prototype.
Here's an example where that might bite you:
function userCreator(name, score) {
this.name = name;
}
userCreator.prototype.sayName = function(){console.log("hi");}
function paidUserCreator(paidName, paidScore, accountBalance){
userCreator.call(this, paidName, paidScore);
}
// points to the paidUserCreator function
console.log(paidUserCreator.prototype.constructor)
// replace protoype with new object
paidUserCreator.prototype = Object.create(userCreator.prototype);
// now paidUserCreator.prototype has no constructor property
// so it defers to paidUserCreator
console.log(paidUserCreator.prototype.constructor)
Javascript 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new in the code below with Object.create?
var UserA = function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
}
UserA.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();
(Assume MY_GLOBAL.nextId exists).
The best I can come up with is:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();
There doesn't seem to be any advantage, so I think I'm not getting it. I'm probably being too neo-classical. How should I use Object.create to create user 'bob'?
With only one level of inheritance, your example may not let you see the real benefits of Object.create.
This methods allows you to easily implement differential inheritance, where objects can directly inherit from other objects.
On your userB example, I don't think that your init method should be public or even exist, if you call again this method on an existing object instance, the id and name properties will change.
Object.create lets you initialize object properties using its second argument, e.g.:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
As you can see, the properties can be initialized on the second argument of Object.create, with an object literal using a syntax similar to the used by the Object.defineProperties and Object.defineProperty methods.
It lets you set the property attributes (enumerable, writable, or configurable), which can be really useful.
There is really no advantage in using Object.create(...) over new object.
Those advocating this method generally state rather ambiguous advantages: "scalability", or "more natural to JavaScript" etc.
However, I have yet to see a concrete example that shows that Object.create has any advantages over using new. On the contrary there are known problems with it. Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used:
var Animal = {
traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!
This occurs because Object.create(...) advocates a practice where data is used to create new objects; here the Animal datum becomes part of the prototype of lion and bird, and causes problems as it is shared. When using new the prototypal inheritance is explicit:
function Animal() {
this.traits = {};
}
function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();
var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4
Regarding, the optional property attributes that are passed into Object.create(...), these can be added using Object.defineProperties(...).
Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.
For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one method:-
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.
For initialisation without an init method the following Crockford mod could be used:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.
TL;DR:
new Computer() will invoke the constructor function Computer(){} for one time, while Object.create(Computer.prototype) won't.
All the advantages are based on this point.
Sidenote about performance: Constructor invoking like new Computer() is heavily optimized by the engine, so it may be even faster than Object.create.
You could make the init method return this, and then chain the calls together, like this:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
return this;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init('Bob');
Another possible usage of Object.create is to clone immutable objects in a cheap and effective way.
var anObj = {
a: "test",
b: "jest"
};
var bObj = Object.create(anObj);
bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
// now bObj is {a: test, b: gone, c: brand}
Notes: The above snippet creates a clone of an source object (aka not a reference, as in cObj = aObj). It benefits over the copy-properties method (see 1), in that it does not copy object member properties. Rather it creates another -destination- object with it's prototype set on the source object. Moreover when properties are modified on the dest object, they are created "on the fly", masking the prototype's (src's) properties.This constitutes a fast an effective way of cloning immutable objects.
The caveat here is that this applies to source objects that should not be modified after creation (immutable). If the source object is modified after creation, all the clone's unmasked properties will be modified, too.
Fiddle here(http://jsfiddle.net/y5b5q/1/) (needs Object.create capable browser).
I think the main point in question - is to understand difference between new and Object.create approaches. Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
In code example provided in question it isn't big deal, but in next example it is:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
As side effect result will be:
[ undefined, 'James' ]
because of Guest.prototype = new SiteMember();
But we don't need to execute parent constructor method, we need only make method getName to be available in Guest.
Hence we have to use Object.create.
If replace Guest.prototype = new SiteMember();
to Guest.prototype = Object.create(SiteMember.prototype); result be:
[ 'James' ]
Sometimes you cannot create an object with NEW but are still able to invoke the CREATE method.
For example: if you want to define a Custom Element it must derive from HTMLElement.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
The advantage is that Object.create is typically slower than new on most browsers
In this jsperf example, in a Chromium, browser new is 30 times as fast as Object.create(obj) although both are pretty fast. This is all pretty strange because new does more things (like invoking a constructor) where Object.create should be just creating a new Object with the passed in object as a prototype (secret link in Crockford-speak)
Perhaps the browsers have not caught up in making Object.create more efficient (perhaps they are basing it on new under the covers ... even in native code)
Summary:
Object.create() is a Javascript function which takes 2 arguments and returns a new object.
The first argument is an object which will be the prototype of the newly created object
The second argument is an object which will be the properties of the newly created object
Example:
const proto = {
talk : () => console.log('hi')
}
const props = {
age: {
writable: true,
configurable: true,
value: 26
}
}
let Person = Object.create(proto, props)
console.log(Person.age);
Person.talk();
Practical applications:
The main advantage of creating an object in this manner is that the prototype can be explicitly defined. When using an object literal, or the new keyword you have no control over this (however, you can overwrite them of course).
If we want to have a prototype The new keyword invokes a constructor function. With Object.create() there is no need for invoking or even declaring a constructor function.
It can Basically be a helpful tool when you want create objects in a very dynamic manner. We can make an object factory function which creates objects with different prototypes depending on the arguments received.
You have to make a custom Object.create() function. One that addresses Crockfords concerns and also calls your init function.
This will work:
var userBPrototype = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
function UserB(name) {
function F() {};
F.prototype = userBPrototype;
var f = new F;
f.init(name);
return f;
}
var bob = UserB('bob');
bob.sayHello();
Here UserB is like Object.create, but adjusted for our needs.
If you want, you can also call:
var bob = new UserB('bob');
While Douglas Crockford used to be a zealous advocate of Object.create() and he is basically the reason why this construct actually is in javascript, he no longer has this opinion.
He stopped using Object.create, because he stopped using this keyword altogether as it causes too much trouble. For example, if you are not careful it can easily point to the global object, which can have really bad consequences. And he claims that without using this Object.create does not make sense anymore.
You can check this video from 2014 where he talks at Nordic.js:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
new and Object.create serve different purposes. new is intended to create a new instance of an object type. Object.create is intended to simply create a new object and set its prototype. Why is this useful? To implement inheritance without accessing the __proto__ property. An object instance's prototype referred to as [[Prototype]] is an internal property of the virtual machine and is not intended to be directly accessed. The only reason it is actually possible to directly access [[Prototype]] as the __proto__ property is because it has always been a de-facto standard of every major virtual machine's implementation of ECMAScript, and at this point removing it would break a lot of existing code.
In response to the answer above by 7ochem, objects should absolutely never have their prototype set to the result of a new statement, not only because there's no point calling the same prototype constructor multiple times but also because two instances of the same class can end up with different behavior if one's prototype is modified after being created. Both examples are simply bad code as a result of misunderstanding and breaking the intended behavior of the prototype inheritance chain.
Instead of accessing __proto__, an instance's prototype should be written to when an it is created with Object.create or afterward with Object.setPrototypeOf, and read with Object.getPrototypeOf or Object.isPrototypeOf.
Also, as the Mozilla documentation of Object.setPrototypeOf points out, it is a bad idea to modify the prototype of an object after it is created for performance reasons, in addition to the fact that modifying an object's prototype after it is created can cause undefined behavior if a given piece of code that accesses it can be executed before OR after the prototype is modified, unless that code is very careful to check the current prototype or not access any property that differs between the two.
Given
const X = function (v) { this.v = v };
X.prototype.whatAmI = 'X';
X.prototype.getWhatIAm = () => this.whatAmI;
X.prototype.getV = () => this.v;
the following VM pseudo-code is equivalent to the statement const x0 = new X(1);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
X.prototype.constructor.call(x0, 1);
Note although the constructor can return any value, the new statement always ignores its return value and returns a reference to the newly created object.
And the following pseudo-code is equivalent to the statement const x1 = Object.create(X.prototype);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
As you can see, the only difference between the two is that Object.create does not execute the constructor, which can actually return any value but simply returns the new object reference this if not otherwise specified.
Now, if we wanted to create a subclass Y with the following definition:
const Y = function(u) { this.u = u; }
Y.prototype.whatAmI = 'Y';
Y.prototype.getU = () => this.u;
Then we can make it inherit from X like this by writing to __proto__:
Y.prototype.__proto__ = X.prototype;
While the same thing could be accomplished without ever writing to __proto__ with:
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
In the latter case, it is necessary to set the constructor property of the prototype so that the correct constructor is called by the new Y statement, otherwise new Y will call the function X. If the programmer does want new Y to call X, it would be more properly done in Y's constructor with X.call(this, u)
new Operator
This is used to create object from a constructor function
The new keywords also executes the constructor function
function Car() {
console.log(this) // this points to myCar
this.name = "Honda";
}
var myCar = new Car()
console.log(myCar) // Car {name: "Honda", constructor: Object}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // true
console.log(myCar.constructor) // function Car() {}
console.log(myCar.constructor === Car) // true
console.log(typeof myCar) // object
Object.create
You can also use Object.create to create a new object
But, it does not execute the constructor function
Object.create is used to create an object from another object
const Car = {
name: "Honda"
}
var myCar = Object.create(Car)
console.log(myCar) // Object {}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // ERROR
console.log(myCar.constructor) // Anonymous function object
console.log(myCar.constructor === Car) // false
console.log(typeof myCar) // object
I prefer a closure approach.
I still use new.
I don't use Object.create.
I don't use this.
I still use new as I like the declarative nature of it.
Consider this for simple inheritance.
window.Quad = (function() {
function Quad() {
const wheels = 4;
const drivingWheels = 2;
let motorSize = 0;
function setMotorSize(_) {
motorSize = _;
}
function getMotorSize() {
return motorSize;
}
function getWheelCount() {
return wheels;
}
function getDrivingWheelCount() {
return drivingWheels;
}
return Object.freeze({
getWheelCount,
getDrivingWheelCount,
getMotorSize,
setMotorSize
});
}
return Object.freeze(Quad);
})();
window.Car4wd = (function() {
function Car4wd() {
const quad = new Quad();
const spareWheels = 1;
const extraDrivingWheels = 2;
function getSpareWheelCount() {
return spareWheels;
}
function getDrivingWheelCount() {
return quad.getDrivingWheelCount() + extraDrivingWheels;
}
return Object.freeze(Object.assign({}, quad, {
getSpareWheelCount,
getDrivingWheelCount
}));
}
return Object.freeze(Car4wd);
})();
let myQuad = new Quad();
let myCar = new Car4wd();
console.log(myQuad.getWheelCount()); // 4
console.log(myQuad.getDrivingWheelCount()); // 2
console.log(myCar.getWheelCount()); // 4
console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
console.log(myCar.getSpareWheelCount()); // 1
Feedback encouraged.
I have a rather academic question that doesn't particularly apply to anything I'm doing, I just really want to know the answer!
Say we have a simple object definition in the global namespace as such:
TestObject = function(){};
It has a method added to it's prototype that can be instantiated into a new object itself:
TestObject.prototype.AnotherObject = function() {};
Instantiate the first object:
var myObject = new TestObject();
Now my question is this:
How does
myObject.myProperty = new myObject.AnotherObject();
differ to
myObject.myProperty = new TestObject.prototype.AnotherObject();
Or are they exactly the same?
The difference I see is this: I could use the second method to instantiate objects within the TestObject context without knowing the name of the instantiated object itself, i.e.
TestObject.prototype.createAnObject = function() {
this.anotherProperty = new TestObject.prototype.AnotherObject();
}
And finally:
What are the implications of using a prototype method to instantiate an object of the same name? Why do this result in an infinite loop? (What actually happens inside..)
TestObject.prototype.AnotherObject = function () {
this.AnotherObject = new TestObject.prototype.AnotherObject();
};
myObject.AnotherObject();
Yet this does not...
TestObject.AnotherObject = function() {};
TestObject.prototype.createAnObject = function() {
this.AnotherObject = new TestObject.prototype.AnotherObject();
};
myObject.createAnObject();
...
I have a deep desire to understand the relationships between objects here! Thank you!
The reason I ask these questions is because I want to make something like so where there is a 1:1 relationship between objects:
ClientObject = function () {
this.objectname = "a client class";
}
ClientObject.prototype.loginUser = function(name) {
this.loggedin = true;
if (typeof this.User === 'undefined') {
this.User = new ClientObject.User(name);
}
}
ClientObject.User = function (name) {
this.username = name;
}
ClientObject.User.prototype.getProfile = function() {
return 'user profile';
}
var testClient = new ClientObject();
console.log('testClient.User = ' + (typeof testClient.User)); // should not exist
testClient.loginUser('Bob'); // should login 'bob'
console.log('testClient.User = ' + (typeof testClient.User)); // should exist now Bob is logged in
console.log(testClient.User.username); // should be bob
testClient.loginUser('Tom'); // should not do anything as User object already created
console.log(testClient.User.username); // bob still
console.log(testClient.User.getProfile()); // new functionality available
I am just not sure if I'm breaking any best practises or conventions here unwittingly.
myObject.myProperty = new myObject.AnotherObject();
differ to
myObject.myProperty = new TestObject.prototype.AnotherObject();
There's no difference at all. Remember, objects in JavaScript have a prototype chain. When you call new myObject.AnotherObject(); the engine will first check for a AnotherObject on myObject itself. Failing to find it, it will check on myObject's prototype, which it will find. The second version
myObject.myProperty = new TestObject.prototype.AnotherObject();
Just goes right to the place where AnotherObject is defined.
TestObject.prototype.AnotherObject = function () {
this.AnotherObject = new TestObject.prototype.AnotherObject();
}
myObject.AnotherObject();
Just walk through the code. When you say: myObject.AnotherObject();, AnotherObject will be called, with this set to myObject. The first line of that will attempt to create a new property on myObject (which is this) by setting it to the result of
new TestObject.prototype.AnotherObject();
which will then re-enter the very same AnotherObject function, but this time with this set to a new object whose prototype is set to TestObject.prototype.AnotherObject's prototype. And so on ad infinitum
Finally,
TestObject.prototype.createAnObject = function() {
this.AnotherObject = new TestObject.prototype.AnotherObject();
}
myObject.createAnObject();
Will not cause an infinite loop, so far as I can tell, and as far as I can test: FIDDLE
Basically, createAnObject will enter with this set to myObject. Inside of which a brand new property called AnotherObject will be created on myObject, which will be set to a new invocation of the AnotherObject function you previously set up.
Note that after this call is made, the AnotherObject function will still exist, but, it will be shadowed by the AnotherObject property you just created. So now you'll never ever be able to say
var f = new myObject.AnotherObject()
Because you now have a AnotherObject property sitting right on myObject, which will be found and returned before anything on the prototype is ever checked.
Well, I mean, you could always say delete myObject.AnotherObject and remove that property from the object, which would then open you up to the AnotherObject being found on the prototype, but really, you should avoid name conflicts like this to begin with.
Regarding your last bit of code
A) Why not make User its own function?
B) Why not set up this.User = new ...() right in the ClientObject constructor function? That way you wouldn't need the undefined check
C) ClientObject should be defined as
function ClientObject(){...`
the you have it now seems to be creating an implicit global.
I am getting confused over which way I should be creating an object in javascript. It seems there are at least two ways. One is to use object literal notation while the other uses construction functions. Is there an advantage of one over the other?
If you don't have behaviour associated with an object (i.e. if the object is just a container for data/state), I would use an object literal.
var data = {
foo: 42,
bar: 43
};
Apply the KISS principle. If you don't need anything beyond a simple container of data, go with a simple literal.
If you want to add behaviour to your object, you can go with a constructor and add methods to the object during construction or give your class a prototype.
function MyData(foo, bar) {
this.foo = foo;
this.bar = bar;
this.verify = function () {
return this.foo === this.bar;
};
}
// or:
MyData.prototype.verify = function () {
return this.foo === this.bar;
};
A class like this also acts like a schema for your data object: You now have some sort of contract (through the constructor) what properties the object initializes/contains. A free literal is just an amorphous blob of data.
You might as well have an external verify function that acts on a plain old data object:
var data = {
foo: 42,
bar: 43
};
function verify(data) {
return data.foo === data.bar;
}
However, this is not favorable with regards to encapsulation: Ideally, all the data + behaviour associated with an entity should live together.
It essentially boils down to if you need multiple instances of your object or not; object defined with a constructor lets you have multiple instances of that object. Object literals are basically singletons with variables/methods that are all public.
// define the objects:
var objLit = {
x: 0,
y: 0,
z: 0,
add: function () {
return this.x + this.y + this.z;
}
};
var ObjCon = function(_x, _y, _z) {
var x = _x; // private
var y = _y; // private
this.z = _z; // public
this.add = function () {
return x + y + this.z; // note x, y doesn't need this.
};
};
// use the objects:
objLit.x = 3;
objLit.y = 2;
objLit.z = 1;
console.log(objLit.add());
var objConIntance = new ObjCon(5,4,3); // instantiate an objCon
console.log(objConIntance.add());
console.log((new ObjCon(7,8,9)).add()); // another instance of objCon
console.log(objConIntance.add()); // same result, not affected by previous line
Another way to create objects in a uniform way is to use a function that returns an object:
function makeObject() {
var that = {
thisIsPublic: "a public variable"
thisIsAlsoPublic: function () {
alert(that.thisIsPublic);
}
};
var secret = "this is a private variable"
function secretFunction() { // private method
secret += "!"; // can manipulate private variables
that.thisIsPublic = "foo";
}
that.publicMethod = function () {
secret += "?"; // this method can also mess with private variables
}
that.anotherPublicVariable = "baz";
return that; // this is the object we've constructed
}
makeObject.static = "This can be used to add a static varaible/method";
var bar = makeObject();
bar.publicMethod(); // ok
alert(bar.thisIsPublic); // ok
bar.secretFunction(); // error!
bar.secret // error!
Since functions in JavaScript are closures we can use private variables and methods and avoid new.
From http://javascript.crockford.com/private.html on private variables in JavaScript.
The code below shows three methods of creating an object, Object Literal syntax, a Function Constructor and Object.create(). Object literal syntax simply creates and object on the fly and as such its __prototype__ is the Object object and it will have access to all the properties and methods of Object. Strictly from a design pattern perspective a simple Object literal should be used to store a single instance of data.
The function constructor has a special property named .prototype. This property will become the __prototype__ of any objects created by the function constructor. All properties and methods added to the .prototype property of a function constructor will be available to all objects it creates. A constructor should be used if you require multiple instances of the data or require behavior from your object. Note the function constructor is also best used when you want to simulate a private/public development pattern. Remember to put all shared methods on the .prototype so they wont be created in each object instance.
Creating objects with Object.create() utilizes an object literal as a __prototype__ for the objects created by this method. All properties and methods added to the object literal will be available to all objects created from it through true prototypal inheritance. This is my preferred method.
//Object Example
//Simple Object Literal
var mySimpleObj = {
prop1 : "value",
prop2 : "value"
}
// Function Constructor
function PersonObjConstr() {
var privateProp = "this is private";
this.firstname = "John";
this.lastname = "Doe";
}
PersonObjConstr.prototype.greetFullName = function() {
return "PersonObjConstr says: Hello " + this.firstname +
" " + this.lastname;
};
// Object Literal
var personObjLit = {
firstname : "John",
lastname: "Doe",
greetFullName : function() {
return "personObjLit says: Hello " + this.firstname +
", " + this.lastname;
}
}
var newVar = mySimpleObj.prop1;
var newName = new PersonObjConstr();
var newName2 = Object.create(personObjLit);
It depends on what you want to do. If you want to use (semi-)private variables or functions in you object, a constructor function is the way to do it. If your object only contains properties and methods, an object literal is fine.
function SomeConstructor(){
var x = 5;
this.multiply5 = function(i){
return x*i;
}
}
var myObj = new SomeConstructor;
var SomeLiteral = {
multiply5: function(i){ return i*5; }
}
Now the method multiply5 in myObj and SomeLiteral do exactly the same thing. The only difference is that myObj uses a private variable. The latter may be usefull in some cases. Most of the times an Object literal is sufficient and a nice and clean way to create a JS-object.
Do you want single instance of the object for the page -- Literal.
Do you want to just transfer data like DTO objects simple GET SET :- Literal
Do you want to create real objects with method behaviors , multiple instances - Constructor function , Follow OOP principles , inheritance :- Constructor functions.
Below is the youtube video which explains in detail what is literal , what are constructor functions and how they differ from each other.
https://www.youtube.com/watch?v=dVoAq2D3n44
As mentioned in https://www.w3schools.com/js/js_object_definition.asp
Using an object literal, you both define and create , one object in one
statement.
Also
Object literal only create a single object. Sometimes we like to have
an object type that can be used to create many objects of one type.
Go with object literal, it's more consise and expands better with the introduction of initial values.
The Object() constructor function is a bit slower and more verbose. As
such, the recommended way to create new objects in JavaScript is to
use literal notation
Udacity Object-Oriented JavaScript
Actually, methinks, we can have private methods in object literals. Consider code below:
var myObject = {
publicMethod: function () {
privateMethod1();
privateMethod2();
function privateMethod1(){
console.log('i am privateMethod1');
}
function privateMethod2(){
console.log('i am privateMethod2');
}
}
}
Matter of taste, but I prefer to use object literals where it is possible.
Here is a benchmark that shows the access time for accessing properties on literals, constructors and classes. It might take a while but it shows almost every way to access properties. To me this benchmark shows literal properties access time overall are slightly slower than class and constructor properties access time. The worst performing times are from getters and setters on an object literal. Unlike getters and setters on classes and constructors which seem to be even faster than most other access times.
Benchmark: https://www.measurethat.net/Benchmarks/Show/12245/0/the-grand-dictionary-property-accessor-schema
// Object Literal and Object constructor
function MyData(foo, bar) {
this.foo = foo;
this.bar = bar;
}
MyData.prototype.verify = function () {
return this.foo === this.bar;
};
//add property using prototype
var MD = new MyData;//true.
var MD = new MyData();//true.
MD.verify// return only the function structure.
MD.verify(); //return the verify value and in this case return true coz both value is null.
var MD1 = new MyData(1,2); // intialized the value at the starting.
MD1.verify// return only the function structure.
MD1.verify(); // return false coz both value are not same.
MD1.verify(3,3);// return false coz this will not check this value intialized at the top
MyData.prototype.verify = function (foo,bar) {
return this.foo === this.bar;
};
var MD1 = new MyData(1,2);
MD1.verify();
MD1.verify(3,3);// return false coz this keyword used with foo and bar that will check parent data
I was just wondering about the difference between the following declaration of JavaScript objects. Specifically, the difference between thing object literal and thing1 object from thing class.
Code:
var thing = {
sanity:0,
init:function(){
//code
},
send:function(){
//code
}
}
function thing(){
this.sanity = 0;
this.init = function(){
//code
};
this.send = function(){
//code
};
}
thing1 = new thing();
Static Objects / Object Literals
Static objects, or object literals, don't require instantiation with the new operator and also behave like singletons. Consider the following example:
Code:
var staticObject1 = {
a: 123,
b: 456
};
var staticObject2 = staticObject1;
console.log(staticObject1, staticObject2);
staticObject2.b = "hats";
console.log(staticObject1, staticObject2);
Output:
Object a=123 b=456 Object a=123 b=456
Object a=123 b=hats Object a=123 b=hats
Notice that changing staticObject2.b also affected staticObject1.b. However, this may not always be the desired effect. Many libraries, such as Dojo, offer an object cloning method that can alleviate this situation if you want to make a copy of a static object. Continuing the previous example, consider the following:
Code:
var staticObject3 = dojo.clone(staticObject1); // See the doc in the link above
staticObject1.a = "pants";
console.log(staticObject1, staticObject2, staticObject3);
Output:
Object a=pants b=hats Object a=pants b=hats Object a=123 b=hats
Notice that the values of the members of staticObject1 and staticObject2 are the same, whereas staticObject3 is not affected by changes to these other objects.
Static objects are also useful for creating project or library namespaces, rather than filling up the global scope, and promotes compatibility like no one's business.
This is useful when creating libraries that require portability or interoperability. This can be seen in popular libraries such as Dojo, YUI and ExtJs, where all or most methods are called as dojo.examplMethod(), YUI().exampleMethod(), or Ext.exampleMethod() respectively.
Static objects can also be considered loosely analogous to struct's in C/C++.
Class Constructors / Instantiated Objects
Classes in JavaScript are based on prototypal inheritance, which is a far more complex subject and can be read about here, here and here.
As opposed to static objects, this method of object creation gives the unique opportunity for private scope object members and methods because of JavaScript's closuer property. Consider the following example of private class members:
Code:
var SomeObject = function() {
var privateMember = "I am a private member";
this.publicMember = "I am a public member";
this.publicMethod = function() {
console.log(privateMember, this.publicMember);
};
};
var o = new SomeObject();
console.log(typeof o.privateMember, typeof o.publicMember);
o.publicMethod();
Output:
undefined string
I am a private member I am a public member
Notice that typeof o.privateMember is "undefined" and not accessible outside of the object, but is from within.
Private methods can also be made, but are not as straight forward yet are still simple to implement. The issue lies in that the value of this inside of the private method defaults to window and one of two techniques must be applied to ensure that this refers to the object that we are working within, in this case, the instance of SomeObject. Consider the following example:
Code:
var SomeObject = function() {
var privateMember = "I am a private member";
var privateMethod = function() {
console.log(this.publicMember);
};
this.publicMember = "I am a public member";
this.publicMethod = function() {
console.log(privateMember, this.publicMember);
};
this.privateMethodWrapper = function() {
privateMethod.call(this);
}
};
var o = new SomeObject();
console.log(typeof o.privateMethod, typeof o.publicMethod, typeof o.privateMethodWrapper);
o.privateMethodWrapper();
Output:
undefined function function
I am a public member
Notice that withing privateMethodWrapper(), privatemethod was executed using call and passing in this for the function's context. This is all fine; however, the following technique is preferable (in my opinion) as it simplifies the calling scope and produces identical results. The previous example can be changed to the following:
Code:
var SomeObject = function() {
var self = this;
var privateMember = "I am a private member";
var privateMethod = function() {
console.log(self.publicMember);
};
this.publicMember = "I am a public member";
this.publicMethod = function() {
console.log(privateMember, this.publicMember);
};
this.privateMethodWrapper = function() {
privateMethod();
}
};
var o = new SomeObject();
console.log(typeof o.privateMethod, typeof o.publicMethod, typeof o.privateMethodWrapper);
o.privateMethodWrapper();
Output:
undefined function function
I am a public member
This answer was the basis for a post on my blog, where I give additional examples. Hope that helps ;)
Case 2 is referencing javascript class constructors. A glaring difference is that the variable is not yet an object, so you cannot internally reference thing1.sanity. You would have to initialize the class by creating an instance of said class prior to calling any internal members:
var myConstructor = function() {
this.sanity = 0;
}
// wont work
alert(myConstructor.sanity);
// works
var thing1 = new myConstructor();
alert(thing1.sanity);
Here is an article going further in-depth than my quick example:
Class Constructors vs. Object Literals
The difference is that the thing1 object is associated with the thing1 class, and will inherit (not literally) the thing1 prototype.
For example, you can later write
thing.prototype.initAndSend = function() { this.init(); this.send(); };
You will then be able to write thing1.initAndSend() without modifying thing1. In addition, thing1.constructor will be equal to the thing method, whereas {}.constructor is equal to Object.
By the way, standard convention is to capitalize class names.
Functions are objects and also constructors (you can instantiate them using new).
Hash-tables/Objects ({}) are not able to be instantiated, thus they are commonly used as data structures. And I am not so sure if it is wise to call them "Objects".
With the first method, you are declaring a single object. With the second, you are declaring a class from which you can instantiate (i.e. create) many different copies.