What is the difference between below approaches for adding methods to an object:
// Appending methods to a function using nested functions
var myObj1 = {
myMethod : function() {
console.log('myObj1.myMethod was called');
},
myOtherMethod : function() {
},
myOtherOtherMethod : function() {
}
}
// Appending methods to a function using the dot operator:
var myObj2 = {};
myObj2.myMethod = function(){
console.log('myObj2.myMethod was called');
}
myObj2.myOtherMethod = function(){
}
myObj2.myOtherOtherMethod = function(){
}
myObj1.myMethod(); // myObj1.myMethod was called
myObj2.myMethod(); // myObj2.myMethod was called
Both do the same thing. Besides the different syntax, is one approach preferred over the other? From my point of view, both approaches simply add methods (or function if you like) to an object.
http://jsfiddle.net/NK35z/
The two are semantically identical. The object literal syntax is preferred since it is more clear what you are doing and it also gives the JavaScript engine a chance to optimize the result.
There is no difference between both those ways of declaring objects/functions. If you mean static methods as in 'they don't change', that will work great.
They are not static methods in the traditional sense. Every time you create an object like that, it will have its own unique representation of it in memory. This means instead of one function in memory, you will have one function for each instance of that object (n copies of the function).
In order to make static methods (in the classical OOP sense, methods shared by a class (in JavaScript there are no classes, so objects using the same constructor/prototype) that do not require an instance), you can't really do it. But if you want the functions to only occupy one space in memory, you must use the Constructor Pattern:
function Foo()
{
//we won't assign any properties here.
}
Foo.prototype.method1 = function(var1, var2){
//don't use `this` here if you want the method to be truly static.
//static methods shouldn't try and access instance members.
};
Foo.prototype.method2 = function(var2, var3){
//whatever goes here
};
// Methods on the prototype are shared by all objects of foo, so we can create a new Foo
var f = new Foo();
foo.method1(1,2); // also works.
As others have said, there's no practical difference. Adding properties in a object literal makes sense where you know everything up front and can just assigne values. Adding properties one at a time make sense where you need to to some work before adding the method, e.g.:
var obj = {
/* define some stuff here */
};
if ( whatever ) {
obj.fn = function(){/* logic A */}
} else {
obj.fn = function(){/* logic B */}
}
There is no right or wrong way, use whatever suits best in each case. It's ok to use both for the same object.
They are exactly the same. You'll have to use the dot/square brackets accessor when you don't want to overwrite properties/methods that already exist on the object.
Related
Sometimes techniques like this is used to keep variable reference or create singleton. In this way we will call createVariable one time only.
What are the pros and cons of this approach?
function createVariable() {
// usually here may be some long asynchronous task
//
return true;
}
function useVariable() {
if(!useVariable.someVar) {
useVariable.someVar = createVariable();
}
// do something with useVariable.someVar
}
// we will call useVariable several times.
// The idea is to call createVariable
// one time only.
useVariable();
useVariable();
useVariable();
I am grateful to all ideas and recommendations. I don't want to create a singleton. Just want to keep variable reference on function level. Without
pollute the global scope.
What are the pros and cons of this approach?
The approach is okay, although I question the need for it as higher-level design question.
The implementation has a couple of issues:
If someVar contains a falsey value, you'll recreate it when you shouldn't. To check if you've previously created it, use if(!useVariable.hasOwnProperty("someVar")) { rather than if(!useVariable.someVar) {.
The falsey values are 0, "", NaN, undefined, null, and of course, false. (All other values are "truthy".)
Functions have some built-in properties, both their own (name, length) and ones they get from their prototypes (various methods, mostly). So if your variables have names like name, length, call, and so on, you'll mistakenly think you've created them when you haven't as createVariable will already have those properties with truthy values (in your createVariable case). You can work around that by adding a prefix of some kind, or using a separate object as a map (although objects inherit properties, too, so you'd still probably need a prefix), or if you were using ES2015+, you could use a Map.
You've said you only want to create the variable once and "not pollute the global scope" (which is a good thing to avoid). I do that by just wrapping my code in a scoping function:
(function() {
var someVar = createSomeVar();
// My other code here
})();
That keeps the global namespace untouched, and creates only a single copy of someVar without the need for any particular plumbing.
Here is how you would create a singleton (from http://www.dofactory.com/javascript/singleton-design-pattern):
var Singleton = (function () {
var instance;
function createInstance() {
var object = new Object("I am the instance");
return object;
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
then use it like this
var instance1 = Singleton.getInstance();
var instance2 = Singleton.getInstance();
//You can see here that they are indeed the same instance
alert("Same instance? " + (instance1 === instance2));
NOTE: this took five seconds to find via Google: http://dofactory.com/javascript/singleton-design-pattern
Below I've got a simple little inheritance chain in JavaScript:
var Base =(function(){
function Base(config){
this.name = function(){
return config.name;
}
this.department = function(){
return config.department;
}
}
Base.prototype.calculate = function(){
return this.name().length + this.department().length;
}
return Base;
})();
var base = new Base({
name: 'me',
department: 'this one'
});
console.log(base.calculate());
//inheritance
var Concrete = (function(){
Concrete.prototype = Base.prototype;
function Concrete(config){
Base.apply(this,arguments);
this.number = function(){
return config.number;
}
}
return Concrete;
})();
var concrete = new Concrete({
name: 'concrete',
department: 'the best',
number: 3
});
console.log(concrete.number()); //3
console.log(concrete.name()); //concrete
and it works as expected. I'm curious, though about how correct it would be to place method properties on the prototype of an object. Canonically I know that instance data should go with the instance of the class and the methods the object actually uses should be on the prototype, but what about the situation where the properties themselves are methods (like name and department in Base in this example)? In the interest of keeping things immutable I'd rather not let users change the properties of one of these objects after they've been initialized. In this case does it make any sense to use the prototype instead of the constructor to add functionality to an object?
Or it is only correct to place properties in the constructor so you have access to them when you do something like Base.prototype.whatever?
what about the situation where the properties themselves are methods? In the interest of keeping things immutable I'd rather not let users change the properties of one of these objects after they've been initialized.
I wouldn't call these "properties" any more, but "accessor" or "getter" methods.
In this case does it make any sense to use the prototype instead of the constructor to add functionality to an object?
Yes, if you mean functionality like calculate. If you mean getters like name, department or number you need to place them in the constructor as they need privileged access to the config.
Canonically I know that instance data should go with the instance of the class and the methods the object actually uses should be on the prototype
It's a bit different actually:
Everything instance-specific (data, accessor methods with distinct scopes) needs to go on the instance and is usually set up in the constructor
Everything that is shared amongst all instances (typically methods, but also data in some rare cases) should go on the prototype.
Concrete.prototype = Base.prototype;
No! Use Concrete.prototype = Object.create(Base.prototype); instead.
The heading of your question is a bit misleading.
A direct answer to your heading - Yes, prototype properties are encouraged. They might not make a lot of difference wrt writing the code and the usage of the code, but internally, how JS manages things, like memory, accessing the variables inside closures etc it much better when done via prototype properties.
Now your actual question, is hiding immutable configurations using closures and private scoped variables the only way to do things ?
Right now - I think yes, as ES6 is still not supported completely by every browser yet.
But soon, the support will spread out in all release version of browsers and then you can use this nifty ES6 data type WeakMap . Just like a Map but here the keys are objects. So your Base definition can be written like:
var Base = (function() {
var properties = new WeakMap(); // You have to keep variable private
function Base(config) {
properties.set(this, config);
}
Base.prototype = {
name: function() {
return properties.get(this).name;
},
department: function() {
return properties.get(this).department;
},
calculate: function() {
return this.name().length + this.department().length;
}
};
return Base;
})();
Yes, you still need to keep the variable properties out of reach, so the outer closure. But the number of closures have decreased by 1 in this case.
Similar approach can be for ES6 Symbol but the outer closure will still be required.
What we truly need here are classes which will truly solve the issue, as explained in this very well written blog
(Obviously I'm not sure what the title of this should be.)
I'd like to be able to modify the prototypes of native objects with minimal risk (because trust me; I have heard over and over again how it's a mortal javascript sin).
My train of thought goes something like this: I can greatly reduce the possibility of conflicts if I can add my custom functions to a single object on a prototype rather than directly adding them to the prototype itself.
If I have the code,
String.prototype.foo = function() {
//do stuff
};
...obviously the keyword this references the string that called it. However, if I do something like,
String.prototype.foo = {};
String.prototype.foo.bar = function() {
//do stuff
};
...the keyword this references the object foo.
If there some way to overcome this?
The only way to overcome this would be to override the context using call:
String.prototype.foo.bar.call('hello'))
which works, but is pretty ridiculous.
You're better off (as you've already heard) avoiding modifying native prototypes, and instead having an object with your methods accepting the string as a parameter.
Well, there's a couple of ways to do this, depending on how much work you want to put in.
Using bind is the most straightforward way, but you have to define the string as a variable so you can pass a reference of it to bind:
String.prototype.foo = function() { console.log(this); }
String.prototype.foo.bar = function() { console.log(this); }
var g = "hi there";
g.foo() // Yields g
g.foo.bar() // Yields String.prototype.foo()
g.foo.bar.bind(g)() // Yields g again.
There may be another very hackish way to produce the desired result by creating getters and setters on String.prototype.foo so that String.prototype.foo.bar activates a function that returns a function bound to the instance that foo refers to. ??? Confusing.
What might be the best solution to reduce the possibility of conflicts, is to take advantage of prototypal inheritance and create your own sub prototype of the native String.
function MyString(string) {
this.foo = function() { //whatever };
this.foo.bar = (function() {}).bind(this);
this.toString = function() { return string; } // because toString is not generic.
}
MyString.prototype = new String();
Here, you're creating your own "sub-prototype" of the String prototype. It inherits all the properties of the String prototype and adds its own, all without altering the native strings at all. BONUS: this.foo and this.foo.bar will both refer to your instance.
var instance = new MyString("hi");
instance.foo(); // this == instance
instance.foo.bar(); // this == instance
instance.replace("i", "e"); // returns "he"
This maybe wasn't the answer you were looking for, but hopefully it will at least be helpful.
As far as I can tell, there are two main ways of creating functions for an object in javascript. They are:
Method A, make it in the constructor:
function MyObject() {
this.myFunc1 = function() {
...
}
this.myFunc2 = function() {
...
}
...
}
Method B, add it to the prototype:
function MyObject() {
...
}
MyObject.prototype.myFunc1 = function() {
...
}
MyObject.prototype.myFunc2 = function() {
....
}
Obviously if you did:
MyObject.myFunc3 = function() {
....
}
then myFunc3 would become associated with MyObject itself, and not any new objects created with the new keyword. For clarity, we'll call it method C, even though it doesn't work for creating new objects with the new keyword.
So, I would like to know what the differences between the two are. As far as I can tell they have the same effect logically, even if what's happening on the machine is different.
If I were to guess I would say that the only real difference is when you're defining them in the constructor like in method A, it creates a whole new function object for each object that's created, and Method B only keeps one copy of it (in MyObject), that it refers to any time it's called. if this is the case, why would you do it one way over the other. Otherwise, what is the difference between method A and method B.
The advantage of giving a separate function to each object is that you can close over variables in the constructor, essentially allowing for "private data".
function MyObject(a,b) {
var n = a + b; //private variable
this.myFunc1 = function() {
console.log(n);
}
};
vs
function MyObject(a,b) {
this.n = a + b; //public variable
}
MyObject.prototype.myFunc1 = function() {
console.log(this.n);
}
Whether this is a good idea or not depends on who you ask. My personal stance is reserving constructor functions for when I actually use the prototype, as in option #2 and using plain functions (say, make_my_object(a,b)) when using closures, as in option #1.
The idea is that you can modify the prototype at any time and all objects of the type (even those created before the modification) will inherit the changes. This is because, as you mentioned, the prototype is not copied with every new instance.
The MyObject in method A is an instance for inner functions.
You cannot call its functions explicitly outside of it unless object (you can call it a class) was instantiated.
Assume this:
MyObject.MyFunc1(); // will not work
var obj = new MyObject();
obj.MyFunc1(); // will work
so this is the same as any class in other languages. Describing usefulness of classes and their usages goes beyond that question though.
Also to notice:
function MyObject() {
var privateVar = "foo";
this.publicProperty = "bar";
// public function
this.publicFunc = function() {
...
}
// private function
function privateFunc () {
...
}
}
For method B it's same as with method A, the only difference is prototyping is a style of creating object. Some use prototypes for readability or out of preference.
The main advantage in prototypes is that you can extend existing object without touching the original source. You need to be careful with that though.
(as example Prototype framework)
For method C you can call them a static functions. As you said they can be called explicitly by referring through object like:
MyObject.MyFunc1();
So which one to use depends on situation you're handling.
I am trying to create a prototype/class that inherits from the object that is returned by a specific function. But I dont know what that object's name is?
For the instance var xhr = XMLHttpRequest(); what object is returned by xhr.responseXML;? Is it XMLDocument? Or maybe XMLDOM?
Also if I create the object var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); and call xmlDoc.load("xmlFile.xml" ); will it return the same type of object as xhr.responseXML;?
I am trying to do the following:
function XMLHandler()
{
this.xmlFile = "defaultXML.xml";
}
// Make XMLHandler inherit from Javascript object
XMLHandler.prototype = new XMLDocument();
XMLHandler.prototype.constructor = XMLDocument;
You shouldn't include unrelated questions in the same post. To address your second question about declaring a function within a "class":
Your first syntax, declaring it within the constructor, will pointlessesly overwrite myClass.prototype.publicFunct to point to a newly created function every time the constructor is called. That is, you will be creating an extra copy of the function with each call to the constructor, with myClass.prototype.publicFunct always pointing to the most recently created copy - or undefined until the constructor has been called at least once. Don't do this.
Your second option is simply invalid syntax in JavaScript.
Your third syntax is prefered. This will add the function to the prototype once.
Remember: JavaScript doesn't have classes as such, though you can sort of simulate them if you think it is worth the bother.
I can tell by your recent questions that you are thinking like Java, which this is not.
First question:
responseXML is different for each browser. Firefox gives a nsIDOMDocument, IE gives an IXMLDOMDocument and Webkit browsers depend on the responseType setting but will probably be Document. Since you cannot predict what it will be stop trying to extend it. In most cases the type isn't made available by the browser's API so javascript cannot extend it anyway.
Moreover, since JavaScript's inheritance is not class based you are forced into doing this:
XMLHandler.prototype = new XMLDocument();
...which simply does not work for your purpose. Any instance of XMLHandler will be built on an unrelated, empty document and not the document returned by responseXML. You have to use a wrapper here.
Second Question:
Of your 3 methods the first is equivalent to the last but more wasteful because it repeatedly sets the same function to the same prototype. The second is nonsensical, the syntax is broken. These are your real options:
// Instance method, every instance is given a copy of the function upon "new"
function MyClass()
{
this.publicFunct = function()
{
alert("public function");
};
}
// Prototypal method, only one copy of the function shared by all instances
function MyClass()
{
}
MyClass.prototype.publicFunct = function()
{
alert("public function");
};
// Shorthand method, same as prototypal but handy for several members at once
// It prevents MyClass from being a descendent of another type
function MyClass()
{
}
MyClass.prototype = {
// A colon is only acceptable in object notation
publicFunct: function()
{
alert("public function");
}
};
I would go with a prototypal method for efficiency unless you need to selectively add functions to a class. Your use of "public function" (also "class") seems like another symptom of an OOP background, there aren't any private functions in JavaScript so "public" has no place, all member functions are public. If at some point you do need a private function you can fake the effect with a closure.
(function() {
// Assignments are mostly global
MyClass = function() {};
MyClass.prototype.publicFunct = function()
{
privateFunct();
};
// These statements affect local scope
var foo = 'bar';
function privateFunct()
{
alert("public function");
}
})(); // These extra brackets cause the contents to be executed immediately
Having said that it is rare to need private functions and all JavaScript is visible anyway so it's not secret really. The above could be thwarted like this:
thief = {};
MyClass.prototype.publicFunct.call(thief);
// privateFunct is called by publicFunct in the context of the thief
You might as well accept that functions are public. You can go a step further and give up on classes altogether. Objects are just objects that happen to have some functions and those functions can even be shared with completely different objects.