Reputation: 1527
As you know JavaScript is a very flexible object-oriented language when it comes to syntax, but my question is which way of defining function in JavaScript is popular?
Did only javascript provide multi way for helps to know some alternatives in order to read other people's code OR multiple way is based on performance reason?
1. Using a function
function Apple (type) {
this.type = type;
this.color = "red";
this.getInfo = getAppleInfo;
function getAppleInfo() {
return this.color + ' ' + this.type + ' apple';
}
}
2. Using object literals
var apple = {
type: "macintosh",
color: "red",
getInfo: function () {
return this.color + ' ' + this.type + ' apple';
}
}
3. Singleton using a function
var apple = new function() {
this.type = "macintosh";
this.color = "red";
this.getInfo = function () {
return this.color + ' ' + this.type + ' apple';
};
}
Upvotes: 3
Views: 150
Reputation:
In brief to your question "which method is popular?" I must say I have seen all sorts of different approaches used in all sorts of combinations in the wild. There is no standard way (with lots of bugs as a consequence).
The reason there is multiple ways is because JS is not an object oriented language. It is an object based scripting language and wasn't meant originally to be used for big scale applications and libraries. It allows you to do something which looks spectacular in 5 lines of code because of the flexible syntax, but becomes a nightmare when big scale robustness and readability is required.
Personally I wrote a JavaScript library which tries to bring a clean and natural syntax to JS like in C++, declarations first, definitions after and which at once allows comfortable use of static, private, protected, virtual etc members in JS.
OoJs can be found on GitHub. This is a basic example of the syntax:
;( function class_Template( namespace )
{
'use strict'; // recommended
if( namespace[ "Template" ] ) return // protect against double inclusions
namespace.Template = Template
var Static = TidBits.OoJs.setupClass( namespace, "Template", "BaseClass" )
// Static data members, private by default
//
Static.privateStaticDM = 0
Static.protectedStaticDM = 0
Static.publicStaticDM = 0
Static.Private
(
"privateStaticDM" //< can do for consistency, but private is the default
, privateStaticMethod // accesslevel for data members
)
Static.Protected
(
"protectedStaticDM"
, protectedStaticMethod
)
Static.Public
(
"publicStaticDM"
, publicStaticMethod
)
// constructor
//
function Template( parameter )
{
// Data members
//
this.privateInstanceDM = parameter
this.protectedInstanceDM = 0
this.publicInstanceDM = 0
this.Private
(
"privateInstanceDM"
, init
, this.Virtual
(
virtualPrivateInstanceMethod
)
)
this.Protected
(
"protectedInstanceDM"
, protectedInstanceMethod
)
var iFace = this.Public
(
"publicInstanceDM"
, publicInstanceMethod
)
this.init() // if you have to do something else
return iFace
}
// all your method definitions go here
//
function init(){}
function privateStaticMethod(){}
})( window )
Upvotes: 1
Reputation: 33870
First of all, I must tell you that i am not a specialist and you may find better (complete) answer on the subject.
The big difference between the 3 ways are the prototype. The method 1 [Usin a function]
will allow you to bind prototype object that are not shared among other object.
You can add prototype method the Apple
object aswell as the Object
object. See for example :
//init
Object.prototype.hello = 'Hello';
Apple.prototype.world = ' World';
//Method 1
alert(apple.hello + apple.world); //Hello World
//Method 2
alert(apple.hello + apple.world); //Helloundefined
//Method 3
alert(apple.hello + apple.world); //Helloundefined
If you want multiple instance of the same object, you'll have a bad time without the first method. As in you example, if you want 2 different apple, you need to copy/paste and change properties (except for the first method).
//Method 1
var macintosh = new Apple('macintosh');
var otherApple = new Apple('Heisenberg')
//Method 2
var macintosh = {
type: "macintosh",
color: "red",
getInfo: function () {
return this.color + ' ' + this.type + ' apple';
}
}
var otherApple = {
type: "I'm not good with apple's name",
color: "red",
getInfo: function () {
return this.color + ' ' + this.type + ' apple';
}
}
//Method 3
var macintosh = new (function(type) {
this.type = type;
this.color = "red";
this.getInfo = function () {
return this.color + ' ' + this.type + ' apple';
};
})('macintosh');
var otherApple = new (function(type) {
this.type = type;
this.color = "red";
this.getInfo = function () {
return this.color + ' ' + this.type + ' apple';
};
})('Still not better');
In the method 1 and method 3, you can have local variable. Elements that are not accessible outside the object.
This is kinda useful when you have event handler function inside you object. In those function, you lose the this
reference. Lucky, you can save it in a local variable. Take for example timeout
and let not cheat with something like .bind()
:
//Method 2
var apple = {
getMe : 'YES!',
setTimer : function(){
setTimeout(this.goGetHim, 500);
},
goGetHim : function(){
//alert(this.getMe); Do not work
alert(apple.getMe); //Kinda lame
}
}
// Method 1, 3
yourinitfn(){
var self = this
this.getMe : 'YES!',
this.setTimer : function(){
setTimeout(this.goGetHim, 500);
},
this.goGetHim : function(){
alert(self.getMe); //YES!
}
}
apple.self;//Undefined
The last thing i could think of is the identification. Basicly, you can easily, with the method #1, know that the object is an apple :
//Method 1
alert(apple instanceof Object); //True
alert(apple instanceof Apple); //True
//Method 2
alert(apple instanceof Object); //True
alert(apple instanceof Apple); //False
//Method 2
alert(apple instanceof Object); //True
alert(apple instanceof Apple); //False
If someone could find other advantage on those subject, I would be gratefull :
I've never used, and shall never use the singleton function to create an object. I've read somewhere (can't find the reference now) that using new function
is a bad practice and a big performance hit. Note that I may be wrong here...
Upvotes: 2
Reputation: 36521
Your Options 1 and 3 are essentially the same. Option 1 would need to be called with new
in order to create an instance. Option 3 is simply doing that right away. But that's kind of weird, because if there's only going to be one object, you might as well just use Option 2 (object literal).
You are missing another common option, which I guess you could call an object factory. In such a case, you essentially wrap your Option 2 in a function to be able to instantiate multiple copies of the object.
You are also missing any uses of function prototypes, which is important to use when instantiating classes with methods, for performance reasons. For example:
var Apple = function () {
this.type = "macintosh";
this.color = "red";
};
Apple.prototype = {
getInfo: function () {
return this.color + ' ' + this.type + ' apple';
}
};
var myApple = new Apple();
In this case, only one copy of the getInfo
method exists, whereas in your examples, that method is recreated every time an apple is instantiated. Also, using prototypes gives the ability to take advantage of prototypal inheritance. Somewhat confusingly, there are alternative ways to accomplish this introduced in newer versions of Javascript, but they're ultimately the same.
I would use your Option 2 if I needed an object without any methods or if I was using previously defined functions as my methods (e.g. not creating new function expressions every time the object is instantiated). Otherwise, I'd use a prototype and constructor function.
I recommend reading Reg Braithwaite's Javascript Allongé, which is free online and really gave me a feel for how the Javascript function and object model can be fully utilized.
Upvotes: 0
Reputation: 664538
- Using a function vs
- Using object literals
Means that you will need to call it to get an instance:
var apple = new Apple("Macintosh");
It is then quite equal to the object created with the object literal. However, using a constructor function allows us the optimisation of sharing a few values between multiple instances, mostly the methods:
function getInfo() {
return this.color + ' ' + this.type + ' apple';
}
function Apple (type) {
this.type = type;
this.color = "red";
this.getInfo = getAppleInfo;
}
var apple1 = new Apple("Macintosh"),
apple2 = new Apple("Golden Delicious");
apple1.getInfo === apple2.getInfo // only one function object!
However, that's what a factory function could do as well by returning object literals. Using new
with the constructor function has the additional advantage of the instances sharing their prototype object, from which they inherit properties. We could simplify it to
function Apple (type) {
this.type = type;
this.color = "red";
}
Apple.prototype.getInfo = function getInfo() {
return this.color + ' ' + this.type + ' apple';
};
// now, having
var apple2 = new Apple("Golden Delicious");
apple2.getInfo === Apple.prototype.getInfo // still only one function object
apple2.getInfo() // and we can access it directly on instances without explicitly
// having created a property on them!
apple2 instanceof Apple // is also a feature
See Use of 'prototype' vs. 'this' in JavaScript? for more details.
3 Singleton using a function
var apple = new function() {
Never ever use this. It obscures the existence of a constructor function, which allows to construct other non-singleton instances behind your back.
Upvotes: 0