There are some differences of the two ways of adding a prototype.
The first example adds some methods to the prototype
of f
. This is because you are setting keys to some functions.
As prototype
is an object, we can also try the same thing with an object.
Let's set an empty object, and add a method and a value, as so.
const obj = {};
obj.website = "stackoverflow.com";
obj.visit = () => {
console.log(`Visit ${obj.website} today!`);
};
Note: Arrow syntax (() => {}
) is new syntax, and isn't supported in legacy browsers.
You can see the similarities of an object and prototype
.
The second example overwrites the entire prototype
of f
, as you are setting prototype
to be an empty object, then containing some values.
You can see what is happening step-by-step with an object.
First, you define an object, and add a property of name
, as so.
let obj = {};
obj.name = "Stack Overflow";
Next, we'll add a URL to Stack Overflow, as so.
obj = {
url: "stackoverflow.com",
};
However, when we try to access the .name
property, we get a value of undefined
, as so.
console.log(`See ${obj.name} at ${obj.url}!`);
// Outputs: See undefined at stackoverflow.com!
Here is the final result:
// Step 1
let obj = {};
obj.name = "Stack Overflow";
// Step 2
obj = {
url: "stackoverflow.com",
};
// Step 3
console.log(`See ${obj.name} at ${obj.url}!`);
This is the reason why const
is used in objects; so that this issue doesn't occur!
In summary, there are differences between the two methods of changing prototypes.
- The first example will add methods to the
prototype
, without deleting or overwriting the existing ones.
- The second example will overwrite the existing methods in
prototype
, and add the new ones.
Also, just a side tip, in modern JavaScript, you should use a class
instead of a function
for prototypes like these. For example:
class F {
constructor(name) {
this.name = name;
}
static toStr() {
return "new F()";
}
sayHi() {
console.log(`Hi ${this.name}!`);
return this;
}
}
console.log(F.toStr());
const f = new F("Person");
f.sayHi();
Here are some key points of what is happening:
class F
creates a new class called F
. It is convention to use PascalCase
when naming a class.
constructor
is a special function which is called when the new
keywork is used on F
. It initialises the class. The parameters of constructor
are what you pass in when you initialise the class. Inside, you can add the parameter passed into constructor
into this
(special keyword), which makes it usable throughout the class. See constructor
(MDN) for more information.
- The first method has the
static
keyword, which means it can be used without initialising the class. So, you don't need to use the new
keyword to access it, but just do ClassName.methodName()
. See static
(MDN) for more information.
- The second function needs
F()
to be initialised with the new
keyword before it can be used. It also returns this
in the function body. This creates something called method chaining, which makes it possible to call another method or property after the method has been called.
F.toStr()
is calling the toStr()
method on the class F
. The reason you don't need to use the new
keyword is because it was defined as a static
method.
- The
new F()
part is creating a new instance of F()
. Then, we are accessing a method off of it.