
Let's look at a example below.
// make constructor function
let Person = function (name) {
this.name = name;
};
// create foo object from Person
let foo = new Person("foo");
console.log(foo.name);
When Person() is called as a constructor function, before executing function code, Person() makes a empty object and bind it to this. The most important thing is that the Person.prototype is linked to this empty object as [[prototype]].

let foo = {
name: "foo",
age: "35",
gender: "man",
};
console.dir(foo);
// Object {name: "foo", age: "35", gender: "man", __proto__: Object.prototype}
let Person = function (name, age, gender, position) {
this.name = name;
this.age = age;
this.gender = gender;
};
let bar = new Person("seunghwan", 27, "male");
console.dir(bar);
// Person {name: "seunghwan", age: 27, gender: "male", __proto__: Person.prototype}
let baz = new Person("junyoung", 30, "female");
console.dir(baz);
// Person {name: "junyoung", age: 30, gender: "female", __proto__: Person.prototype}
Prototype of each object is different. It is Object.prototype when using object literal. But it is Person.prototype when using constructor function.
let Person = function (arg) {
// a way of correcting mistake
if (!(this instanceof Person)) {
return new Person(arg);
}
this.value = arg ? arg : 0;
};
let tmp = new Person(10);
console.log(tmp.value); // 10
let hello = Person(4);
console.log(hello.value); // 4
If Person() is called as just function, global object(window) is binded to this. So !(this instanceof Person) equals to true and it will return new Person(arg). Therefore, even though we do mistake like not calling constructor function but just function, it corrects mistake by returning constructor function and executing it. That's why hello.value return 4.