What is the difference between this two codes and which one should I use?
function Test() {}
Test.method = function() {};
With Prototype:
function Test() {}
Test.prototype.method = function() {};
1st case : static method.
function Test() {}
Test.method = function () { alert(1); };
var t = new Test;
Test.method(); // alerts "1"
t.method(); // TypeError: Object #<Test> has no method 'method'
2nd case : instance method.
function Test() {}
Test.prototype.method = function () { alert(1); };
var t1 = new Test;
var t2 = new Test;
t1.method(); // alerts "1"
t2.method(); // alerts "1"
Test.method(); // TypeError: Object function Test() {} has no method 'method'
The first example merely assigns a function to a new property of Test called method. There is nothing special or magic about it (by which I mean, the language does not do anything interesting with it). You might call this a static method, because it's shared across all instances, but it's really just a normal property. (Functions are objects and objects have properties.)
In the second case, a new method is added to Test's prototype, which makes it available to all instances of Test. This is special behavior. Every object in JavaScript has an internal link to another object, which is called its prototype. This link is established using the prototype of the constructor that created the object, so any instance created by Test will have the new property in its prototype chain.
For example:
function Test() {}
Test.method = function() {};
var a = new Test();
console.log(a.method); // => undefined
But:
function Test() {}
Test.prototype.method = function() {};
var a = new Test();
console.log(a.method); // => function
The prototype method is shared between all instances of Test.
The difference goes back to how the prototype chaining works. If you create instances of Test then they will be able to access the methods that are defined on the prototype.
The first code, simply adds a "static" method on the constructor; You won't be able to access that method doing something like this:
var testInst = new Test();
testInst.method() // Error Undefined is not a function
The only way to invoke that method is via the constructor reference i.e.
Test.method();
As i mentioned, the above is feasible if you add the method to the prototype of the constructor.
If you define a method in the prototype, any instances will be able to use that method. If you define the method as simply a part of the original object, it allows you to simply use that in a manner that one could reasonably refer to as a static method.
For example:
Array.isArray( [] ) //true
[].isArray() //throws a TypeError
The second example throws a TypeError because isArray() is not in the Array.prototype (remember, instances only access methods defined in that instance, or in that instance's prototype or __proto__ chain).
In short:
* A method defined in the original object can be accessed by that object, but not instances of that object.
* A method defined in the original object's prototype can be accessed by any instance of the original object.
Will NOT Work (for an instance)
function Test() {}
Test.method = function() {};
Will Work (for an instance)
function Test() {}
Test.prototype.method = function() {};
Why?
Assuming that you create an instance of Test:
t = new Test()
On calling a method:
t.method()
JavaScript will first look within Test, for example the 3 properties and methods will be recognized below:
function Test() {} {
this.a = "hello";
this.b = "world";
this.c = function() { alert( this.a + this.b) }
}
and then the second, the look up will be done on prototype:
Test.prototype.method = function() { console.log('prototype defined method') }
In JavaScript the below does not register to the instance t but instead Test:
Test.method = function() { console.log('something unsual') };
therefore
Test.method() // works
t.method() // no works
Related
What is the difference between the following two declarations?
Class.method = function () { /* code */ }
Class.prototype.method = function () { /* code using this.values */ }
Is it okay to think of the first statement as a declaration of a static method, and the second statement as a declaration of an instance method?
Yes, the first function has no relationship with an object instance of that constructor function, you can consider it like a 'static method'.
In JavaScript functions are first-class objects, that means you can treat them just like any object, in this case, you are only adding a property to the function object.
The second function, as you are extending the constructor function prototype, it will be available to all the object instances created with the new keyword, and the context within that function (the this keyword) will refer to the actual object instance where you call it.
Consider this example:
// constructor function
function MyClass () {
var privateVariable; // private member only available within the constructor fn
this.privilegedMethod = function () { // it can access private members
//..
};
}
// A 'static method', it's just like a normal function
// it has no relation with any 'MyClass' object instance
MyClass.staticMethod = function () {};
MyClass.prototype.publicMethod = function () {
// the 'this' keyword refers to the object instance
// you can access only 'privileged' and 'public' members
};
var myObj = new MyClass(); // new object instance
myObj.publicMethod();
MyClass.staticMethod();
Yes, the first one is a static method also called class method, while the second one is an instance method.
Consider the following examples, to understand it in more detail.
In ES5
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.isPerson = function(obj) {
return obj.constructor === Person;
}
Person.prototype.sayHi = function() {
return "Hi " + this.firstName;
}
In the above code, isPerson is a static method, while sayHi is an instance method of Person.
Below, is how to create an object from Person constructor.
var aminu = new Person("Aminu", "Abubakar");
Using the static method isPerson.
Person.isPerson(aminu); // will return true
Using the instance method sayHi.
aminu.sayHi(); // will return "Hi Aminu"
In ES6
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
static isPerson(obj) {
return obj.constructor === Person;
}
sayHi() {
return `Hi ${this.firstName}`;
}
}
Look at how static keyword was used to declare the static method isPerson.
To create an object of Person class.
const aminu = new Person("Aminu", "Abubakar");
Using the static method isPerson.
Person.isPerson(aminu); // will return true
Using the instance method sayHi.
aminu.sayHi(); // will return "Hi Aminu"
NOTE: Both examples are essentially the same, JavaScript remains a classless language. The class introduced in ES6 is primarily a syntactical sugar over the existing prototype-based inheritance model.
When you create more than one instance of MyClass , you will still only have only one instance of publicMethod in memory but in case of privilegedMethod you will end up creating lots of instances and staticMethod has no relationship with an object instance.
That's why prototypes save memory.
Also, if you change the parent object's properties, is the child's corresponding property hasn't been changed, it'll be updated.
For visual learners, when defining the function without .prototype
ExampleClass = function(){};
ExampleClass.method = function(customString){
console.log((customString !== undefined)?
customString :
"called from func def.");}
ExampleClass.method(); // >> output: `called from func def.`
var someInstance = new ExampleClass();
someInstance.method('Called from instance');
// >> error! `someInstance.method is not a function`
With same code, if .prototype is added,
ExampleClass.prototype.method = function(customString){
console.log((customString !== undefined)?
customString :
"called from func def.");}
ExampleClass.method();
// > error! `ExampleClass.method is not a function.`
var someInstance = new ExampleClass();
someInstance.method('Called from instance');
// > output: `Called from instance`
To make it clearer,
ExampleClass = function(){};
ExampleClass.directM = function(){} //M for method
ExampleClass.prototype.protoM = function(){}
var instanceOfExample = new ExampleClass();
ExampleClass.directM(); ✓ works
instanceOfExample.directM(); x Error!
ExampleClass.protoM(); x Error!
instanceOfExample.protoM(); ✓ works
****Note for the example above, someInstance.method() won't be executed as,
ExampleClass.method() causes error & execution cannot continue.
But for the sake of illustration & easy understanding, I've kept this sequence.****
Results generated from chrome developer console & JS Bin
Click on the jsbin link above to step through the code.
Toggle commented section with ctrl+/
A. Static Method:
Class.method = function () { /* code */ }
method() here is a function property added to an another function (here Class).
You can directly access the method() by the class / function name. Class.method();
No need for creating any object/instance (new Class()) for accessing the method(). So you could call it as a static method.
B. Prototype Method (Shared across all the instances):
Class.prototype.method = function () { /* code using this.values */ }
method() here is a function property added to an another function protype (here Class.prototype).
You can either directly access by class name or by an object/instance (new Class()).
Added advantage - this way of method() definition will create only one copy of method() in the memory and will be shared across all the object's/instance's created from the Class
C. Class Method (Each instance has its own copy):
function Class () {
this.method = function () { /* do something with the private members */};
}
method() here is a method defined inside an another function (here Class).
You can't directly access the method() by the class / function name. Class.method();
You need to create an object/instance (new Class()) for the method() access.
This way of method() definition will create a unique copy of the method() for each and every objects created using the constructor function (new Class()).
Added advantage - Bcos of the method() scope it has the full right to access the local members(also called private members) declared inside the constructor function (here Class)
Example:
function Class() {
var str = "Constructor method"; // private variable
this.method = function () { console.log(str); };
}
Class.prototype.method = function() { console.log("Prototype method"); };
Class.method = function() { console.log("Static method"); };
new Class().method(); // Constructor method
// Bcos Constructor method() has more priority over the Prototype method()
// Bcos of the existence of the Constructor method(), the Prototype method
// will not be looked up. But you call it by explicity, if you want.
// Using instance
new Class().constructor.prototype.method(); // Prototype method
// Using class name
Class.prototype.method(); // Prototype method
// Access the static method by class name
Class.method(); // Static method
Say I have a constructor function in JavaScript, which I use to create my objects. How would I alter the "contents" of all the objects created by this function through a method call from this function. What I am wondering is, weather it is possible to invoke a method call upon the prototype, like we'd modify the prototype adding our own methods/properties.
For example:
function MyConstructor()
{
var privateVariable = "This is an ORIGINAL private variable";
this.publicVariable = "This is public";
this.modificationMethod = function(){
// I want to call this methode on the prototype
privateVariable = "I am now changed";
};
this.alertMe = function(){
alert(privateVariable);
};
}
var a = new MyConstructor();
a.alertMe(); // alerts This is an ORIGINAL private variable
a.modificationMethod();
a.alertMe(); // alerts I am now changed
This works when I want to change a single object, I invoke the method, it changes that single object. However, I want to change all the objects that are created by the constructor.
I know I can add new methods to it like this:
MyConstructor.prototype.foo = function(){
alert("foo");
}
a = new MyConstructor();
a.foo();
But it does not let me run the existing methods to change the properties, and throws an error:
MyConstructor.prototype.modificationMethod();
"modificationMethod is not a function"
EDIT: Updating the answer to reflect everything discussed in comments. I initially misunderstood the OP's issue.
Every object is linked to a prototype object. When trying to access a property that does not exist, JavaScript will look in the object's prototype object for that property and return it if it exists.
The prototype property of a function constructor refers to the prototype object of all instances created with that function when using new.
What that means is that prototype object is sort of a fallback mechanism when an object itself does not have the desired property.
The concept of private variables are in fact closures.
Prototype functions are defined outside of the constructor function scope, meaning they cannot access the "private properties".
However, it is possible to assign a closure to the prototype property itself, effectively making a private shared (static) variable.
function MyConstructor() {};
MyConstructor.prototype = (function() {
var extensions = {
foo: null,
test: function() {
alert("Test was extended");
}
};
return {
registerExtension: function(name, callback) {
extensions[name] = callback;
},
// in order to use the extensions object, you need a generic function such as invoke
invoke: function(name) {
if (typeof extensions[name] === 'function')
extensions[name].call(this);
}
};
}());
var a = new MyConstructor();
a.invoke('test'); //will alert
a.invoke('foo'); //will not alert (not a function)
a.registerExtension('foo', function() {
alert("foo is now extended as well");
});
a.invoke('test'); //will alert
a.invoke('foo'); //will alert
A simpler approach, if you don't mind for the extended functions to be visible (public), would be to directly extend the prototype.
function MyConstructor() {};
MyConstructor.prototype = {
foo: null,
test: function() {
alert("Test was extended");
}
};
var a = new MyConstructor();
a.test(); //will alert
//a.foo(); //will not alert (not a function)
MyConstructor.prototype.foo = function() {
alert("foo is now extended as well");
};
a = new MyConstructor();
a.test(); //will alert
a.foo(); //will alert
You can easily create an interface for prototype extension.
Object.prototype.registerExtension = function( name, func ){
this.prototype[ name ] = func;
};
// ...
MyConstructor.registerExtension( 'foo', function() {
alert("foo is now extended as well");
} );
There is such a function from a third-party library:
(function($) {
window.NestedFormEvents = function() {
this.addFields = $.proxy(this.addFields, this);
this.removeFields = $.proxy(this.removeFields, this);
};
//......
NestedFormEvents.prototype = {
addFields: function(e) { .....
});
Is there any way to call addFields() from a client? typeof window.NestedFormEvents returns "function", but window.NestedFormEvents.addFields returns undefined as well as window.NestedFormEvents.addFields().
The source code is here: https://github.com/ryanb/nested_form/blob/master/vendor/assets/javascripts/jquery_nested_form.js
This is constructor function. When called with new keyword it returns new object which has methods defined in constructor's prototype:
var nestedFormEvent = new NestedFormEvents();
nestedFormEvent.addFields();
Now if you check console.log(nestedFormEvent) object you will see all necessary methods in it.
You're calling addFields as though it were a static method of NestedFormEvents.
Rather, it is a method of its prototype. So:
var instance = new NestedFormEvents;
alert(NestedFormEvents.addFields); //undefined
alert(instance.addFields); //finds function
In short, any time you're trying to use methods declared on a function's prototype, you need to instantiate it, with new.
When trying to test prototype functionality, I got this odd result:
Here is my first test:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype.name = "Fred";
alert(a.name);
</script>
And, here's the second one:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype = {
name : "Fred",
}
alert(a.name);
</script>
I can't understand why the first will return a alert with "Fred" and the second is "undefined" though these mean the same thing?
Could you help me with it?
Thank you.
When you define a function in JavaScript, the interpreter makes a special prototype property available on the function, which points to an object, in case you use that function as a constructor. The [[Prototype]] internal property points to this object when you create a new object using the constructor.
When you replace the prototype property with a new one, you are replacing that reference, and if you do it after you instantiate an object, you will find the prototype object appears to be stale (that object's [[Prototype]] is pointing to the original object that prototype pointed to).
Solutions
Only assign new properties directly on the prototype property.
var constructor = function() { };
constructor.prototype.someMethod = function() { };
Use an extend type function to extend the existing prototype property with your new object (in this example, I used Underscore's extend() function).
var constructor = function() { };
_.extend(constructor.prototype, { someMethod: function() { } });
Make sure after the constructor, assigning the prototype property is the very next step in your program (generally not recommended).
var constructor = function() { };
constructor.prototype = { someMethod: function() { } };
Your ordering is messed up. You need assign the object to the prototype before using the new operator:
function Hello() {
}
Hello.prototype = {
name : "Fred",
}
var a = new Hello();
alert(a.name);
Demo.
The two code snippets are not actually equal.
In the first script you only override Hello.prototype.name, while in the second script you override the whole content of Hello.prototype.
I am just curious whether I can include an object into function prototype chain. What I mean:
var test = function() { return 'a'; };
console.log(test.bind(this)); // return new bound function
// changing the prototype
// in console the prototype is really set as needed
// test => new object => function prototype => Object prototype
var F = function() {};
F.prototype = Function.prototype;
test.prototype = new F();
console.log(test.bind()); // this still works and returns new bound function
test.prototype.bind = function() {
return 'test';
};
console.log(test.bind()); // this does not work as expected -> returns new bound function instead of 'test'. When I do delete Function.prototype.bind, then console.log(test.bind) returns undefined
You have a function test. It is a instanceof Function, and inherits from Function.prototype so that you can call test.bind for example.
Then you set the "prototype" property of your function to an object inheriting from Function.prototype. That means that all instances of test will inherit from that object (and from Function.prototype):
var t = new test;
t instanceof test; // => true
t instanceof Function; // => true
Then you overwrite the test property on your custom prototype object. You do good to do so, because Function methods should only be called on functions (i.e. callable objects):
>>> Function.prototype.bind.call({})
Unhandled Error: Function.prototype.bind: this object not callable
In your tests with console.log you only apply the Function methods on your test function, not on instances of it. Good, because they'd fail. So, I can see no reason why any objects should inherit from Function - you can't construct functions that don't inherit directly from Function.