1. Factory mode

The factory pattern is a creation pattern that provides the best way to create objects. We create an object inside a function, give it properties and methods, and return the object with a return

function createPerson(name, age, job) {
    var o = new Object()
    o.name = name
    o.age = age
    o.job = job
    o.sayName = function() {
      console.log(this.name)
    }
    return o
  }
  var person1 = createPerson('caoyuan'.25.'Software engineer')
  var person2 = createPerson('neil'.23.'Software engineer')
  console.log(person1) // {name: "ca ", age: 25, job: "Software engineer", sayName: ƒ}
  console.log(person2) // {name: "Neil ", age: 23, job: "Software engineer", sayName: ƒ}
Copy the code

Constructor pattern

The construction pattern creates objects differently from the factory pattern;

  1. No object is explicitly created
  2. Properties and methods are assigned directly to this object
  3. No return object
function Person(name, age, job) {
    this.name = name
    this.age = age
    this.job = job
    this.sayName = function() {
      console.log(this.name)
    }
  }
  let person1 = new Person('caoyuan'.25.'Software Engineer')
  let person2 = new Person('neil'.23.'Software engineer')
  person1.sayName()
  person2.sayName()
Copy the code

Calling the constructor in this way actually goes through four steps

  1. Create an object
  2. Assign the scope of the constructor to the new object (so this refers to it)
  3. Code that executes the constructor type (adding properties to the new object)
  4. Returns the object

Parasitic constructor pattern

The basic idea behind this pattern is to create a function that simply wraps the object’s code and then returns the newly created object.

function Person(name, age, job) {
    var o = new Object()
    o.name = name
    o.age = age
    o.job = job
    o.sayName = function() {
      console.log(this.name)
    }
    return o
  }
  let friend = new Person('neil'.25.'software Engineer')
  friend.sayName() // neil
Copy the code

So that’s an example, throw out the new operator, and this pattern is exactly the same as the factory pattern. Constructors return a new object instance by default if they do not return a value. By adding a return statement to the end of the constructor, you can override the value returned when called to the constructor. The following example

function SpecialArray () {
    // Create an array
    var values = new Array(a)/ / add value
    values.push.apply(values, arguments)
    // Add the method
    values.toPipedString = function() {
      return this.join('|')}// Return the array
    return values

  }
  var color = new SpecialArray('1'.'2'.'3')
  console.log(color.toPipedString()) / / 1 | 2 | 3
Copy the code

Safe constructor pattern A safe object is an object that has no public properties and whose methods do not reference this. Suitable for use in a secure environment or to prevent data from being otherwise altered

The safe pattern follows a similar pattern to the parasitic constructor, but with two differences;

  1. Creating an instance of a new object does not reference this;
  2. The constructor is not called with the new operator
function Person(name, age, job) {
    var o = new Object()
    o.sayName = function() {
      console.log(name)
    }
    return o
  }

  let person = Person('neil'.25.'software Engineer')
  person.sayName() // neil
Copy the code

A scope-safe constructor

Introduces scope-safe constructors in codefunction Person(name, age, job) {
    this.name = name
    this.age = age
    this.job = job
  }
 var person = Person('neil'.25.'Softwate Engineer')
 console.log(window.age) / / 25

Copy the code

Suppose we call this to window, so the value is on window. How can we solve this problem? Modify the code as follows

function Person(name, age, job) {
    if (this instanceof Person) {
      this.name = name
      this.age = age
      this.job = job
    } else {
      return new Person(name, age, job)
    }
  }
  var person = Person('neil'.25.'software Engineer')
  console.log(window.age) // undefined
  console.log(person.age) / / 25
Copy the code

Now it seems that there is no problem in determining whether this is currently on the Person instance by using instanceof, so suppose that the inheritance of the pattern is stolen by using the constructor and the prototype chain is not used, the inheritance might be broken

function Polygon(sides) {
    if (this instanceof Polygon) {
      this.sides = sides
      this.getArea = function() {
        return 0}}else {
      return new Polygon(sides)
    }
  }

  function Rectangle(width, heigth) {
    Polygon.call(this.2) 
    this.width = width
    this.heigth = heigth
    this.getArea = function () {
      return this.width * this.heigth
    }
  }
  let rect = new Rectangle(5.10)
  console.log(rect.sides) // undefined

Copy the code

Rect. Sides is undefined. The Polygon instance is safe, but the Rectangle inherits Polygon’s sides attribute via call. So we create a new Polygon object. Rectangle does not have sides attribute. If constructor stealing is used in combination with prototype chains and parasitic patterns, the code is as follows

function Polygon(sides) {
    if (this instanceof Polygon) {
      this.sides = sides
      this.getArea = function() {
        return 0}}else {
      return new Polygon(sides)
    }
  }

  function Rectangle(width, heigth) {
    Polygon.call(this.2) 
    this.width = width
    this.heigth = heigth
    this.getArea = function () {
      return this.width * this.heigth
    }
  }
  Rectangle.prototype = new Polygon()
  let rect = new Rectangle(5.10)
  console.log(rect.sides) / / 2
Copy the code

Three, prototype mode

Each function we create has the Prototype property, which is a pointer to an object that contains properties and methods that can be shared by all the columns of a particular type. A prototype object is an instance object created by calling the constructor.

  function Person() {
  }
  Person.prototype.name = 'caoyuan'
  Person.prototype.age = '25'
  Person.prototype.sayName = function() {
    console.log(this.name)
  }
  let person1 = new Person()
  let person2 = new Person()
  person2.sayName()
  person1.sayName()
  console.log(person1.sayName == person2.sayName)

Copy the code

Dynamic prototype mode

It wraps all the information in the constructor, and retains the advantage of using both the constructor and the stereotype by initializing the stereotype in the constructor

function Person(name, age, job) {
    this.name = name
    this.age = age
    this.job = job
    / / method
    if (typeof this.sayName ! ='function') {
      Person.prototype.sayName = function() {
        console.log(this.name)
      }
    }
  }
  let person = new Person('neil'.25.'Software Engineer')
  person.sayName()

Copy the code

Use a combination of constructor and prototype patterns

The most common way to create custom objects is to use a combination of the constructor and prototype patterns.

  1. The constructor pattern defines the properties of an instance
  2. The stereotype pattern is used to define methods and shared properties
function Person(name, age, job) {
  this.name = name
  this.age = age
  this.children = ['1'.'2']
}
Person.prototype.sayName = function() {
  console.log(this.name)
}

let person1 = new Person('caoyuan'.25.'Software Engineer')
let person2 = new Person('neil'.23.'Software Engineer')

person1.children.push('3')
console.log(person1.children) / / Array [1, 2, 3]
console.log(person2.children) / / Array [1, 2]
console.log(person1.children === person2.children) // false
console.log(person1.sayName === person2.sayName) // true
Copy the code

Related articles:

Prototype chain foundation and a variety of ways to use