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
Related
I am new and going on javascript way. At the point of Closure. I can create object with new keyword and without new keyword, it is so weird me.
Here code:-
function RankingManage(rank) {
var rank = rank;
function rankInc() {
rank++;
}
function rankDec() {
rank--;
}
return {
makeInc: function () {
rankInc();
},
makeDec: function () {
rankDec();
},
showRank: function () {
return rank;
}
}
}
var Rank = new RankingManage(80);
var Rank2 = RankingManage(80);
Rank.makeInc();
Rank2.makeInc();
console.log(Rank.showRank());//Output:- 81
console.log(Rank2.showRank());//Output:- 81
This has nothing to do with closures.
Using new sets the value of this for the function to a new object and causes it to return this by default.
You are using a return statement to explicitly return an object, so you return that object instead of this.
Because you're creating and returning an object (with the return { ... }), you wouldn't normally call RankingManage via new. You're not using the object that the new operator creates, and you're overriding the default result of the new expression by returning a non-null object from the function. So both ways work, but it doesn't make sense to use new with your function as currently written.
Your current function is absolutely fine, just call it wihtout new. (And since it's not a constructor function — a function you call with new — you'd start it with a lower-case letter, by convention, not an upper-case one. So rankingManage.)
If you wanted to require new when calling RankingManage, you could use the object that new creates via the this keyword:
function RankingManage(rank) {
var rank = rank;
function rankInc() {
rank++;
}
function rankDec() {
rank--;
}
this.makeInc = rankInc;
this.makeDec = rankDec;
this.showRank = function() {
return rank;
};
}
We don't use a return in that, because (again) the default result of the new RankingManage expression is a reference to the object that new created.
But again, your existing function is fine.
Usually, things are done a little bit differently when you're defining an object in this way.
public function MyObject(value) {
this.value = value;
this.doSomething = function() { console.log("Hello!"); };
}
var myObject = new MyObject(10);
var notObject = MyObject(10);
myObject.doSomething(); // Prints Hello!
notObject.doSomething(); // Prints out "can not get property of undefined"
You will now see a change in behaviour, because new prevents the default behaviour of adding values to window and adds them to an object that gets returned.
JSFiddle: https://jsfiddle.net/LLx3376n/
Suppose we've the following function:
function Car(color){
this.wheels = 4;
this.color = color;
}
What exactly new operator does (new Car('red');) could be stated as follows:
Create an empty object and make the this inside the function to point to.
Invoke the function. (Note that this points to that empty object).
That empty object will be populated with properties: wheels and color.
Implicitly returns that object. (If you have explicit return statement, that object of this will be discarded.)
At the end, your returned object is of this structure:
{
wheels: 4,
color: 'red'
}
Alright, just looking at the question, it seems like it would matter, but lets look at a test I did.
So I created 3 constructor functions. I did the usual Car, then a Mazda, then a MX8 constructor. All of them inherit based on the code in the JSFiddle. Here is a shell of what I did, more detail can be found in the JSFiddle.
By the way I'm a big fan of Object.create which doesn't need any babysitting of anything.
var Car = function () {
//code here
}
var Mazda = function (type) {
this.type = type;
//more code here including a simple method test
}
var MX8 = function () {
//more code here
}
Mazda.prototype = new Car();
MX8.prototype = new Mazda("MX8");
var z = new MX8();
//refer to my JSFiddle
z.interior; // got correct interior
z.type; // got correct type ie model
z.warrantyInfo(); // method was correctly inherited
z.speed; // got correct speed
z.constructor === MX8; // false (unless I specify the constructor in the code of which is commented out in my JSFiddle)
short answer:
You need to explicitly set the constructor.
function Base() {}
function Derived() {}
// old prototype object is gone, including constructor property
// it will get however all the properties attached by Base constructor
Derived.prototype = new Base();
Derived.prototype.constructor = Derived;
Does it matter if my Object returns the wrong constructor?
Well, it depends on whether you're using that property or not. I'd say it's a good practice to keep the correct constructor.
Possible use case:
function getType (target) {
// name is empty unless you use the function declaration syntax
// (read-only property)
return target.constructor.name;
}
getType(new Derived()) // "Derived"
getType(new Base()) // "Base"
side note:
There are better ways of implementing inheritance in JS.
My favorite pattern is the following:
function Base (x) { this.x = x; }
function Derived (x, y) { Base.call(this, x); this.y = y; }
// creates an empty object whose internal "[[Prototype]]" property
// points to Base.prototype
Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;
The ideea behind Object.create is based on:
function create (proto) {
function f () {}
f.prototype = proto;
return new f();
}
The actual function Object.create is better because you can pass null as prototype, which doesn't work using the above code.
Anyway, you should watch this excellent playlist: Crockford on JavaScript.
I found different ways that seem to work.
Mostly recommended way in textbooks and the internet:
var Person = function() {
this.age = 23;
}
Tony = new Person();
This also seems to work:
function Person() {
this.age = 23;
}
Tony = new Person();
Is there a difference? And an additional question: Usually you cannot simply leave out parentheses. Here it is possible (new Person instead of new Person()). This is because of using the new keyword, right?
A third odd way that I just tried out looks like this:
function Person() {
return {age: 2};
}
Tony = new Person();
Tony = Person(); // both ways work! It seems that you can leave out 'new' here.
Here I don't get an object with the name of my class, but my property is also accessible and it seems like it was quite similar to both above approaches.
What shall I use and what are the technical differences? Thank you!
JavaScript is a classless language. Classes don't exist, but objects may inherit properties from each other by using prototypes. This means you are not limited to implementing inheritance in a class-like manner. Personally, I like to use a BackboneJS-inspired method (code requires UnderscoreJS):
var BaseObject = function(){}; //Create a function so that we may use the new operator.
//There may be code in the constructor
BaseObject.extend = function(obj) { //Add a static function to the BaseObject to extend it
var base = this; //Save a reference for later
//Create the constructor for the sub object. We need to extend it, so we can't use the base constructor. AFAIK, this is the only way to clone the base constructor, i.e. by creating a new function that calls it
var SubObject = _.extend(function(){
base.apply(this, arguments); //Call base constructor
}, this);
SubObject.prototype= _.extend({}, this.prototype, obj); //Create new prototype that extends the super prototype, but does not overwrite it.
return SubObject; //Return the new constructor + prototype
};
This allows you to do cool class-like stuff like this:
var Car = BaseObject.extend({
speed: 0,
acceleration: 5,
accelerate: function(){
this.speed += this.acceleration;
}
});
var RaceCar = Car.extend({
acceleration: 10,
});
var car = new Car();
var raceCar = new RaceCar();
car.accelerate();
raceCar.accelerate();
if(raceCar.speed > car.speed){
console.log('raceCar won');
}else{
console.log('car won');
}
For more information on inheritance in JavaScript, I strongly recommend reading JavaScript: The Good Parts by Douglas Crockford.
Regarding your examples:
The difference between 1 and 2 is minimal. For more information see this question.
In 3, you are just returning an object literal. The new keyword only has influence on the this keyword within the function, which you are not using, and so using new has no effect. For more information, see this quesion
1 and 2 (var x = function vs function x) are very similar. 3 is a completely different thing.
The difference between 1 and 2 has nothing to do with classes and has been asked before on SO (several times). I think the most complete answer is this one:
https://stackoverflow.com/a/338053/1669279
In short, the first x points to an anonymous function and some debugging tools might have problems with that. The first one is available from the line it was defined on while the second is available in the entire scope. Read the linked answer for details.
The 3rd "solution" is not a class at all. It is simply a function that returns an object (might be called a Factory method).
It is not a good idea to return things from your constructors, especially return this. You should only return things if you want to override the normal process of creating objects (like implementing the singleton pattern for example).
As a side-note, you should always use new when you instantiate a class. Here is what happens when you try to be smart and save characters:
function X () {
return this;
}
console.log(X()); // outputs the window object
The parenthesis after calling the constructor with no parameters are optional, but it is frowned upon to avoid them because it results in slightly more confusing code.
To sum it up, i usually use pattern 1. Pattern 2 is also ok.
One problem with pattern 2 can be this one:
var x = new X(); // works
console.log(x.message); // works, I am X
x.method(); // doesn't work, method hasn't been defined yet
function X() {
this.message = 'I am X';
}
X.prototype.method = function() {
console.log(this.message);
};
this is how i do mine:
;(function (window) {
"use strict";
//-- Private Vars
var opt, obj, rm, Debug;
//-- construtor
function App(requestedMethod) {
//-- set up some vars
if(typeof requestedMethod !== 'undefined') {
rm = requestedMethod;
}
opt = {
rMethod: (typeof rm !== 'undefined') ? (rm != null) ? rm : false : false
}
//-- containe resulable objects
obj = {}
//-- call the init method
this.init();
}
/** Public Methods **/
/**
* The Init method called on every page load
*/
App.prototype.init = function () {
var om = opt.rMethod;
//-- Once all init settings are performed call the requested method if required
if(om) {(typeof App.prototype[om] == 'function') ? App.prototype[om]() : _DB('Call to Method [' + om + '] does not exsist.');}
};
/**
* testmethod
*/
App.prototype.testmethod = function () {
};
/** Private Methods **/
function PrivateMethod(){
}
/**
* A console output that should enable to remain enable js to work in IE
* just incase i forget to remove it when checking on those pesky IE browsers....
*/
function _DB(msg){
if(window.console && window.console.log){
var logDate = new Date();
window.console.log('------------------- ' + logDate + ' ----------------------------------');
window.console.log(msg);
}
};
window.App = App;
})(window);
then call it like:
<script src="ptha/to/your/app.js"></script>
<script>$(function() { new App('testmethod'); });</script>
When the code is loaded the new App() will then run once all page load data has completed
Hope this helps.To get access to it outside add the new to a var
var App = new App('testmethod);
then you can access things like
App.testmethod()...
var Person = function() {
this.age = 23;
}
Person is a variable that contains(is referenced) an anonymous function
function Person() {
this.age = 23;
}
but here you declare a function called "Person"
function Person() {
return {age: 2};
}
and so you declare a function that returns a new static object.
The best way depends on the needs, if you want to declare classes use the second, while to create the modules uses the third. For the first method look here: http://helephant.com/2008/08/23/javascript-anonymous-functions/
If I create a constructor function BlahWidget and give it 2 public methods: publicHello and secondHello. I assign publicHello directly inside the widget using 'this' but use the prototype object to assign the secondHello method, what difference does that really make to the behaviour of the 2 methods on the widget?
var BlahWidget = function(){
this.publicHello = function(){
alert("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
alert("Second Hello");
}
My understanding was that using .prototype allows it to be called by inherited objects. But turns out that this is not the case. Both methods can be called by the inherited function objects, as shown below:
var MiniBlah = function(){
this.callSupers = function(){
this.publicHello();
this.secondHello();
}
}
MiniBlah.prototype = new BlahWidget();
MiniBlah.prototype.constructor = MiniBlah;
var x = new MiniBlah();
x.callSupers();//calls both publicHello and secondHello
The difference is that functions declared on the prototype object are shared across instances of objects created by a constructor function whereas functions declared inside of the body of a constructor function are not, they belong to the object constructed from the function.
What this means in practice is that you could create a load of objects from a constructor function with a function on the prototype doing X, then change that function on the prototype to do Y and all object instances will get the new functionality of the function.
An example
var BlahWidget = function(){
this.publicHello = function(){
console.log("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
console.log("Second Hello");
}
var blah1 = new BlahWidget();
var blah2 = new BlahWidget();
blah2.publicHello = function() {
console.log("Goodbye");
}
blah1.secondHello(); // logs SecondHello
blah2.secondHello(); // logs SecondHello
BlahWidget.prototype.secondHello = function(){
console.log("Second Goodbye");
}
blah1.secondHello(); // logs Second Goodbye
blah2.secondHello(); // logs Second Goodbye
blah1.publicHello(); // logs Hello
blah2.publicHello(); // logs Goodbye
Every single instance of "BlahWidget" will have its own distinct copy of the "publicHello" function.
Also, though this is just academic, I'm not sure I'd say that "prototype" is a keyword; it's more like a "special property name".
In JavaScript Functions are so powerful to build OOPs and modular concepts. Following concepts are implemented using Function only in JavaScript:
Method
Class
Constructor
Module
Below code shows the code which create class MyClass and it has private members:
function MyClass(a) {
var count = 3; // private member
// this check function is private function
function check() {
if (count > 0) {
count--;
return true;
}
else {
return false;
}
}
this._a = a;
this.get = function () {
if (check()) { // use of private function
return this._a;
}
else {
return "Thullu"; // after invoking get method 3 times in the object this else will be executed
}
}
}
In the above code variable, count is private as any object created from MyClass will not have this variable similarly function check() is private function as this function is not part of this in the MyClass. When we create an object of MyClass using new keyword this is returned. This concept is possible in JavaScript because of lexical scoping (functional scoping).
When we create object of this class MyClass, and call the get method more than 3 times:
I would like to write few points regarding new keyword.
When a function is called with the new operator, a new object is created with prototype members and assigned to this.
Above statement is true only if there is no explicit return value in the function. If explicit return is present in Class (function), then same return will be assigned to the object.
I would like to give here one more example with very basic functionality like in all OOP languages we have. We declare private field and then use public properties to expose the private field, in more formal and OOPs way we create Get and Set method to update private field or retrieve private member of class.
Same get and set functionality for private variables in JavaScript we can achieve as shown in below example:
// private class with get and set methods
function MyClass() {
var _privateField = 0; // It is private field as it is not part of "this"
this.GetPrivateField = function () {
return _privateField;
};
this.SetPrivateField = function (value) {
_privateField = value;
};
}
sometimes we loss the new keyword when define new object,
obj = new Clazz(); //correct
obj = Clazz(); //wrong, but no syntax error, hard to debug.
I want to write a function to help me create Class and make it new safe.
var Class = function(){
var constructor = arguments[0];
var superClasses = arguments[1..n];
function clazz(){
if(! this instanceof clazz){
return new clazz()//pass clazz arguments,not Class arguments
}
constructor();//pass clazz arguments
}
//clazz inherit from superClasses
return clazz;
}
var MyClazz = Class(function(name){
this.name = name
}, SuperClazz1, SuperClass2 )
MyClazz.extend({
show: function(){console.log(this.name)}
})
obj1 = new MyClazz("name1");
obj2 = MyClazz("name2");
// obj1 should same as obj2
Is it possible, any exists module?
sometimes we loss the new keyword...
All about coding discipline and testing... anyways, moving on to your question.
To find out whether your function was called as a constructor use instanceof:
function Foo() {
console.log(this instanceof Foo);
}
Foo(); // false
new Foo(); // true
When calling a function as a constructor this refers to the newly created object, otherwise this refers to the object the function was called on, in case it wasn't called on anything this will refer to the global object.
Update
Passing variable arguments to a constructor is not possible. new clas.call(....) will yield an error that call is not an constructor.
You can do two things:
Instead of returning the Class function itself from your class factory method, return a function that creates a new instance, sets up all the needed stuff and then returns that instance (this will make inheritance waaaay more complicated)
Just use the new keyword.
I've written my own Class thingy, and I've tried to support both new and () syntax for creating instances. The whole inheritance stuff etc. is complicated enough, making it even more magic just to save 4 more characters... not worth the effort. Use new and write tests.
Another Update
OK I couldn't resist to hack around more and I made it work:
function is(type, obj) {
return Object.prototype.toString.call(obj).slice(8, -1) === type;
}
function clas(args) {
if (is('Object', this)) {
ctor.apply(this, is('Arguments', args) ? args : arguments);
} else {
return new clas(arguments);
}
}
This will do the magic, at least in my case.
Sorry for the late submission on this answer but I believe it directly answers your question. My solution is to check the type of the constructed object and act accordingly.
You can see my solution here:
http://mikepackdev.com/blog_posts/9-new-scope-safe-constructors-in-oo-javascript
I hope this helps!