JS Create Object Mode

JS Factory Mode

Create objects using literal quantities.

let person = {
  name: "LBJ",
  age: 23,
  gender: 'male',
  sayName: function(){
      console.log(this.name);
  }
}
var animal = new Object();
person.name = "wugui";
person.age = 18;
person.gender = 'male';
person.sayName = function(){
    console.log(this.name)
}

If it's just a regular exercise, there's no problem, but when we need a large number of objects, it's completely unnecessary to repeat the same code.

Creating objects using factory mode
function sayName() {
  console.log(this.name);
}

function Person(name, age, gender) {
  return {
    name,
    age,
    gender,
    sayName:sayName
  }
}
let p1 = Person('Teddy', 12, 'male') 
console.log(p1);//{ name: 'Teddy', age: 12, gender: 'male',sayName: [Function: sayName] }

We just need to pass in the parameters to the factory function to get a lot of objects.But it also has obvious drawbacks.

Disadvantages of factory functions:
function Cat(name, age, gender) {
  return {
    name,
    age,
    gender,
    sayName:sayName
  }
}
function Dog(name, age, gender) {
  return {
    name,
    age,
    gender,
    sayName:sayName
  }
}
function sayName() {
  console.log(this.name);
}
let cat1 = Cat('Teddy', 12, 'male') 
let dog1 = Dog('Teddy', 23, 'female')
console.log(cat1);//{ name: 'Teddy', age: 12, gender: 'male',sayName: [Function: sayName] }
console.log(dog1);// { name: 'Teddy', age: 23, gender: 'female',sayName: [Function: sayName] }

In the example above, there is a Dog factory function, and a Cat factory function, if we want to create an object of cat1 and dog1, but the result is exactly the same (if the same parameter is passed in, the examples are different for the sake of difference).We don't know whether a function is an instance object of Cat or a Dog.Take another look at the example below.

Constructor Pattern
function Cat(name, age, gender) {
  this.name = name
  this.age = age
  this.gender = gender
  this.sayName = sayName
}
function Dog(name, age, gender) {
  this.name = name
  this.age = age
  this.gender = gender
  this.sayName = sayName
}
function sayName() {
  console.log(this.name);
}
let cat1 = new Cat('Teddy', 12, 'male') 
let dog1 = new Dog('Teddy', 12, 'male') 
console.log(cat1);
/**
 *Cat { 
  name: 'Teddy',
  age: 12,
  gender: 'male',
  sayName: [Function: sayName]
} */
console.log(dog1);
/**
 * Dog {
  name: 'Teddy',
  age: 12,
  gender: 'male',
  sayName: [Function: sayName]
}
 */

Using the constructor pattern, even if we pass in the same parameters to create an object, we can intuitively know whether it is an instance of a Dog object or an instance of a Cat object (the identities of Cat and Dog are written before)

The most direct difference between factory mode and constructor is the new operator.When an instance is created using the new operator:

  • Open up a space in memory
  • The [[prototype]] of this object instance is uProto_uPoints to the prototype of the constructor, so new objects can use methods on the prototype of the constructor (understanding the key point of inheritance)
  • this points to a new object coming out of new
  • Assigning values within a function
  • Normally return return return values are not used

In the code above:

console.log(cat1.sayName === dog1.sayName);//true
//They both point to the same address

SayName is the same global approach, which solves the problem of code reuse.But if there are more constructors in the future, they will also need a sayName method, which will do more.The solution at this point is to change the name of sayName and perfect it, but it also brings new problems. What if there are new objects that need sayName to implement?It's impossible for us to keep taking a new name, have a sayName do all the work, or combine it with our custom construction types.We need a prototype model to solve this problem.

Prototype mode:

Mode 1:

function Person() {
  Person.prototype.name = 'zhangsan',
  Person.prototype.height = '1.78',
  Person.prototype.weight = '70KG',
  Person.hobby = ['basketball', 'football', 'piano']
  Person.sayName = function() {
    console.log(this.name);
  }
}

Mode 2:

Person.prototype = {
  name: 'zhangsan',
  height: '1.78',
  weight: '80KG',
  hobby:['basketball', 'football', 'piano'],
  sayName: function() {
  console.log(this.name);
  }
}
console.log(p1.sayName === p2.sayName);//true, they all use prototype methods, so they are the same
console.log(p1.hobby === p2.hobby);//true, for the same reason
//When p1 likes playing table tennis, p2 will also be forced to like it
p1.hobby.push('tennis')
console.log(p1.hobby);//[ 'basketball', 'football', 'piano', 'tennis' ]
console.log(p2.hobby);//[ 'basketball', 'football', 'piano', 'tennis' ]

The prototype pattern solves the problem of sharing methods. The sayName method is on Person's prototype object. When there is another'Dog'constructor that also wants a sayName method, two sayNames on the prototype of different constructors also solve the problem caused by the custom constructor pattern, can have the same name, and can implement different functions.

Of course, the problem with sharing is that not everything you want to share is like the'hobby Hobby'above.

If you want P1 and P2 hobbies to influence each other, you can do so (bad way)

p1.hobby = ['dance', 'rap', 'music']
p2.hobby = ['study', 'sleep', 'eat']
p1.hobby.push('tennis')
console.log(p1.hobby);//[ 'dance', 'rap', 'music', 'tennis' ]
console.log(p2.hobby);//['study', 'sleep', 'eat']
console.log(p1.hobby === p2.hobby);//flase

//At this point the hobby of p1 p2 is their own property, overwriting the hobby of the Person prototype
//When an object accesses its attributes, it will first find out if it has it or not, and if not, it will only be given if it has been found on the [[prototype]] prototype (asking its father for money).
//When p1 new comes out, his [[prototype]] points to Person

Although this can solve this problem, is this not really the way we started with creating objects literally, adding them one by one is not what we need.

Here, our goal is already obvious. Our goal is to share what we want without adding the attributes we want in a literal way.

We combine the benefits of the custom constructor pattern with the benefits of the prototype pattern.

Combination mode:
function Person(name, height, hobby) {
  this.name = name
  this.height = height
  this.hobby = hobby
}
Person.prototype.sayName = function() {
  console.log(this.name);
}
let p1 = new Person('LBJ', '2.06', ['study', 'sleep', 'eat'])
let p2 = new Person('KOBE', '1.98', ['dance', 'rap', 'music'])
console.log(p1);
/**
 * Person {
  name: 'LBJ',
  height: '2.06',
  hobby: [ 'study', 'sleep', 'eat' ]
}
 */
console.log(p2);
/**
 * Person {
  name: 'KOBE',
  height: '1.98',
  hobby: [ 'dance', 'rap', 'music' ]
}
 */
console.log(p1.sayName === p2.sayName);//true, they all use the same sayName method
console.log(p1.hobby === p2.hobby);//false, they have their own hobbies

Keywords: Javascript

Added by Robert Elsdon on Fri, 03 Sep 2021 09:59:47 +0300