Constructor for Javascript Objects - javascript

I am trying to create a JAvascript Object with a constructor and 2 methods. I am getting errors when I try to use the following code, what am I doing wrong? Specifically, it wont allow me to define the constructor function as shown below.
var Feed = {
templateDOM: '',
function(tDOM) {
this.templateDOM = tDOM;
},
loadFeed: function(feedPage, feedsPerPage) {
...
},
showFeed: function(data, tDOM, destination) {
...
}
};

You aren't creating a constructor function at all here. It is a plain object, only you forgot to provide a property name for the second value in it.
If you wanted to create a constructor function, it would look more like this:
function Feed(tDOM) {
this.templateDOM = tDOM;
}
Feed.prototype.loadFeed = function loadFeed(feedPage, feedsPerPage) {
};
Feed.prototype.showFeed = function showFeed(data, tDOM, destination) {
};
Which you can then invoke like:
var my_feed = new Feed("some value");
myFeed.loadFeed("some value", "some other value");

I don't think that you approach can take you where you want. In your case you make use of an object literal. How are you going to make use of constructor, when you have already created an object?
I think that the following would be more suitable:
// Define a cosntructor
function TemplateDom(tDom){
this.templateDOM = tDOM;
}
and then add to the prototype of you constructor the methods:
// Add to the prototype of your constructor the following two functions.
// So each object that will be created using this constructor would have
// defined also those two methods.
TemplateDom.prototype.loadFeed = function(feedPage, feedsPerPage) {
...
};
TemplateDom.prototype.showFeed = function(data, tDOM, destination) {
...
};
Then you can create an object like below:
var templateDom = new TemplateDom("here you pass a dom value");
and you can use the functions loadFeed and showFeed as simple as
templateDom.loadFeed("feedpage value","feedsperpage value");
templateDom.showFeed("data value","tDom value","destination value");

Related

How to define the function prototype if the function is defined as an object property

I want to create an object containing various functions. How can I define functions in the prototype of a constructor function, if the constructor function is a property of an object?
I tried it like this:
var UTILS = {
MyFuncCtor1: function () {
},
MyFuncCtor1.prototype.MyFunc1 : function() {
}
}
but it does not work
sinsc UTILS is an object, defining a "left-side" value is actually defining a property in this object.
Therefor the above code has no real meaning since MyFuncCtor1.prototype.MyFunc1 is not a valid key.
Once possible proper way to do that would be:
function MyFuncCtor1() {
}
MyFuncCtor1.prototype.MyFunc1 = function() {
alert('MyFunc1')
};
const UTILS = {
MyFuncCtor1: new MyFuncCtor1()
}
UTILS.MyFuncCtor1.MyFunc1()
https://jsfiddle.net/kadoshms/87qdt63e/4/
You could do it in two steps. First you define your constructor function and append your prototype functions. The you define your object and set the constructor as a property.
function MyFuncCtor1() {
}
MyFuncCtor1.protptype.MyFunc1 = function() {
}
var UTILS = {
MyFuncCtor1: MyFuncCtor1
}

Difference between creating javascript objects

When creating an object to use JS in an OO manner, is there any difference within a JS engine between (with the exception of being able to define a constructor:
var Uploader = Uploader || {};
and
var Uploader = function() {
}
and
function Uploader() {
}
Especially when later, you wish to do something along the lines of
Uploader.DOM = {
Create: function(file) {
}
};
Is it all down to personal preference? Or is there a real difference?
Objects:
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
}
}
In MyObj.find function this keyword will point to MyObj (which somewhat resembles how this works in languages those have classes). You can use this functionality to do mix-ins:
var MyObj2 = {
myArr: [4,2,6]
}
MyObj2.find = MyObj.find;
In MyObj2.find function this keyword will point to MyObj2.
Also objects support getters and setters (works on IE9+ and all good browsers):
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
},
get maxValue() {
return Math.max.apply(null, this.myArr);// maxValue is calculated on the fly
},
a_: null,
get a () {
return this.a_;
},
set a (val) {
//fire a change event, do input validation
this.a_ = val;
}
}
Now max value in the array can be accessed like this: MyObj.maxValue. I also added a property a_. It can't be named the same as its getter and setter so appended an underscore. Appending or prepending underscores is a naming convention for private variables which should not be accessed directly.
var qwe = MyObj.a // get a_
MyObj.a = 'something'; //set a_
Functions:
var u = new Uploader(); // will throw an exception
var Uploader = function() { }
Uploader is defined in runtime here. It does not exist yet when I try to instantiate it.
var u = new Uploader(); //will work
function Uploader() {}
Uploader is defined in compilation time here so it will work.
Functions can be used with revealing pattern to conceal some members. Functions don't support getters and setters but you can put objects inside functions.
function myFunc() {
function privateFunc() {};
function publicFunc() {};
var obj = {
//members, getters, setters
};
return {
publicFunc: publicFunc,
obj: obj
}
}
You can call muFunc.publicFunc() outside of myFunc because it is returned. But you can not use privateFunc outside because it is not returned.
Revealing pattern functions are not meant to be instantiated usually. This is because when you instantiate it everything inside will be copied to a new instance. So it will use up more memory than if you would add functions using prototype.
myFunc.prototype.someFunc = function() {};
Like this all instances of myFunc will share the same instance of someFunc.
Conclusion: with functions you can simulate a private access modifier but in objects the this keyword acts somewhat similar of what you'd expect in a language that have classes. But you always can use call, apply and bind to change the context (i.e. what 'this' keyword will be) of the function.

Extending object literal

var x = {
name: "japan",
age: 20
}
x.prototype.mad = function() {
alert("USA");
};
x.mad();
The above code does not work.
object literals cannot be extended? or x.mad() not the right way to call.
You can't do it this way. To be able to define object methods and properties using it's prototype you have to define your object type as a constructor function and then create an instance of it with new operator.
function MyObj() {}
MyObj.prototype.foo = function() {
// ...
}
var myObj = new MyObj();
myObj.foo()
If you want to keep using object literals, the only way to attach behaviour to your object is to create its property as anonymous function like so
var myObj = {
foo: function() {
// ...
}
}
myObj.foo();
The latter way is the quickest. The first is the way to share behaviour between mutiple objects of the same type, because they will share the same prototype. The latter way creates an instance of a function foo for every object you create.
Drop the prototype.
Replace:
x.prototype.mad = function() {
With:
x.mad = function() {
This simply adds a mad property to the object.
You dont have .prototype available on anything but function object. So your following code itself fails with error TypeError: Cannot set property 'mad' of undefined
x.prototype.mad = function() {
alert("USA");
};
If you need to use prototype and extension, you need to use function object and new keyword. If you just want to add property to your object. Assign it directly on the object like following.
x.mad = function() {
alert("USA");
}
x.constructor.prototype.mad = function() {
alert("USA");
};
x.mad();
This also works, by the way:
Object.prototype.mad = function() {
alert("USA");
}
var x = {
name: "japan",
age: 20
}
x.mad();
But then, the mad function will be part of any object what so ever,
literals, "class" instances, and also arrays (they have typeof === "object").
So - you'll probably never want to use it this way. I think it's worth mentioning so I added this answer.

Convert arguments into new object parameter without cloning the object?

I want to create a new object with parameters from 'arguments', but I don't know
how to or even possible to convert it directly without cloning. Here's how it is possible using a clone:
function theClass(name, whatever) {
this.name = name;
this.whatever = whatever;
}
// I need to use the arguments passed from this function but without using clone
// as shown.
function doSomething()
{
function clone(args) {
theClass.apply(this, args);
}
clone.prototype = theClass.prototype;
return new clone(arguments);
}
// Usage expectation.
var myNewObject = doSomething("Honda", "motorbike");
console.log(myNewObject.name);
However, this suffers on performance because each time you call doSomething, you have to create a clone just to pass that arguments to be applied in it from theClass.
Now I want to pass that arguments without passing to a cloned object, but I don't know
how to convert it directly.
Any idea?
Note: As clarified by kaminari, the parameters passed are not strictly 'name' and 'whatever', but could be anything depends on the object I want to create. 'theClass' in the code is merely an example.
Thanks.
EDIT: In light of the intended use of these functions:
Probably your best option on maintaining your intended behavior is to implement your function in the following way:
function theClass(options){
this.name = options.name || ''; //or some other default value
this.whatever = options.whatever || '';
};
function doSomething(options){
options = options || {};
return new theClass(options);
};
With this implementation in mind, the code you supplied in "usage expectation" would look like this:
var myNewObject = doSomething({name: "honda", whatever: "motorbike"});
console.log(myNewObject.name);
In this manner, theClass can support as many or as few parameters as need be (only depends on what's supplied in the object and what you choose to extract from it) and similarly, the wrapper doSomething can be given as many or as few options as desired.
this suffers on performance because each time you call doSomething, you have to create a clone just to pass that arguments to be applied in it from theClass.
Simply define the clone function outside of doSomething, and it won't get recreated every time:
function theClass(name, whatever) {
this.name = name;
this.whatever = whatever;
}
function clone(args) {
theClass.apply(this, args);
}
clone.prototype = theClass.prototype;
function doSomething() {
return new clone(arguments);
}

Fundamental JavaScript OO

Ok I should know the answer to this but for some reason I have never really understood or had the need to really get to know JavaScript.
My question is: Looking at the code samples below am I correct in my understanding or am I missing some information.
Sample 1
Need to instantiate the function (or class) in order to use the IsOld method, and a separate copy of the IsOld function will be created for each instance.
function MyClass1() {
this.IsOld = function (age) {
if (age > 40) {
return true;
}
return false;
};
}
// sample usage
var m1 = new MyClass1();
console.log(m1.IsOld(34));
Sample 2
Need to instantiate but unlike MyClass1 the scripting engine will not need to create a copy of the method IsOld for each class instance.
var MyClass2 = (function () {
function MyClass2() { }
MyClass2.prototype.IsOld = function (age) {
if (age > 40) {
return true;
}
return false;
};
return MyClass2;
})();
// sample usage
var m2 = new MyClass2();
console.log(m2.IsOld(34));
Sample 3
No need to instantiate the function / class to access the IsOld method. A single instance of the IsOld method is used across all invocations.
var MyClass3 = {
IsOld: function (age) {
if (age > 40) {
return true;
}
return false;
},
};
// sample uage
console.log(MyClass3.IsOld(34));
Note: I am guessing there are plenty of similar question / answers here on SO but for some reason I could not find one that actually made sense to me.
Your understandings seems to be correct.
If by "need to instantiate" you mean use of 'new' keyword, I'd like to add something here.
In JavaScript use of new keyword is not the only way to create new instances. (Edited as per comments)
And any function can act as a constructor function.
When you use 'new' keyword followed by any function (say 'x') what it does is
Create new object (say 'y'), and set the function x's prototype as the new objects (y's) prototype.
Call the function 'x' in the newly created objects y's context, i.e this would refer to this new object 'y' inside the function 'x'
If the function does not return an object, return the new object 'x' created by the new operator as the result of the new expression.
Here is a good source for you to learn JavaScript by Douglas Crockford (http://javascript.crockford.com/)
So, if you are concerned about the memory (you should be), use a constructor function, and add all the common methods to functions prototype like you have done in Sample 2.
Then all those methods will be inherited to all the objects created using this function as the constructor. However, as mentioned before I think Sample 2 can be simpler:
var MyClass2 = function MyClass2() { };
MyClass2.prototype.IsOld = function (age) {
if (age > 40) {
return true;
}
return false;
};
var obj = new MyClass2();
As far as I know, you're right in all 3 cases.
Does need instantiate IsOld and for every instance there will be new function created.
Doesn't need instantiate IsOld as it is in prototype.
Doesn't need instantiate IsOld as MyClass3 is already an instance (an object not a function).
It seems to me there's been some misunderstanding regarding to the structure of the class and the dynamic nature of Javascript: for all the presented cases, every instance of the "class" creates a new unnamed function.
If you want to declare "classes" in a more traditional way (like C++ or Java), you'd better:
1) Define the functions:
function MyClass_IsOld(age) {
return (age > 40);
}
2) Create the "class" and define its prototype:
function MyClass() { /* put any instance constructor logic here */ };
MyClass.prototype.IsOld = MyClass_IsOld;
3) Use the class:
var myInstance = new MyClass();
console.log(myInstance.IsOld(37));
If you want to use the "method" as a regular function, declare it globally, like:
function MyClass_IsOld(age) {
return (age > 40);
}
function MyClass() { /* put any instance constructor logic here */ };
MyClass.prototype.IsOld = MyClass_IsOld;
var myInstance = new MyClass();
console.log(myInstance.IsOld(37)); // use as a method
console.log(MyClass_IsOld(37)); // use as a function
If you want to hide the implementation details, create a closure:
var MyClass = (function () {
function _MyClass_IsOld(age) {
return (age > 40);
}
function _MyClass() { /* put any instance constructor logic here */ };
_MyClass.prototype.IsOld = _MyClass_IsOld; // use as a method
return _MyClass;
})();
var myInstance = new MyClass();
console.log(myInstance.IsOld(37)); // use as a method
console.log(MyClass_IsOld(37)); // ERROR: undefined function

Categories