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 - .nameproperty, 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 Fcreates a new class called- F. It is convention to use- PascalCasewhen naming a class.
- constructoris a special function which is called when the- newkeywork is used on- F. It initialises the class. The parameters of- constructorare  what you pass in when you initialise the class. Inside, you can add the parameter passed into- constructorinto- this(special keyword), which makes it usable throughout the class. See- constructor(MDN) for more information.
- The first method has the statickeyword, which means it can be used without initialising the class. So, you don't need to use thenewkeyword to access it, but just doClassName.methodName(). Seestatic(MDN) for more information.
- The second function needs F()to be initialised with thenewkeyword before it can be used. It also returnsthisin 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- newkeyword is because it was defined as a- staticmethod.
- The new F()part is creating a new instance ofF(). Then, we are accessing a method off of it.