Before ES6 we used the following constructor method to create objects

1. Use the constructor to create a star class

function Star(uname, Age){this.name = uname this.age = age this.sing = sing(){console.log(' sing ')}} let star = new star (' sing ', 38)Copy the code

Results: A constructor is a special function used to initialize an object, that is, to assign initial values to its member variables. We can extract some common properties and methods from the object and encapsulate them in this function

Note:

  • The constructor is used to create a class of objects whose first letter is capitalized.
  • Constructors have to be used with the new keyword to make sense.

The constructor does four things:

  1. First, a new empty object is created in memory.
  2. Let this point to the new object.
  3. Execute the code inside the constructor to add properties and methods to the new object.
  4. Return the new object (so there is no need to write a return inside the constructor)

The constructor

You can add members to javascript constructors, either on the constructor itself or on this inside the constructor. Members added in these two ways are called static and instance members, respectively.

  • Static members: Members added to the constructor itself are called static members and can only be accessed by the constructor itself.

  • Instance members: Object members created inside a constructor are called instance members and can only be accessed by the instantiated object.

    function Star(uname, Age){this.name = uname this.age = age this.sing = function (){console.log(' sing ')} Age Sing is instance members // Instance members can only be accessed by instantiation. Let LDH = new Star(' Andy ', 18) console.log(ldh.name); console.log(ldh.age); Ldh.sing () // Instance members cannot be accessed through constructors //console.log(star.name) // static members: members added on the constructor itself. Sex = 'male' // Static member can only access console.log(star.sex) via constructor // Can not access console.log(ldh.sex) via objectCopy the code

Constructor problem

function Star(uname, Age){this.name = uname this.age = age this.sing = function (){console.log(' sing ')}} let LDH = new Star(' sing ', 39) let zxy = new Star(' Jacky ', 34) The above example instantiates two objects and creates two Spaces in memory for the same function at different addresses, so constructors are a waste of resources. console.log(ldh.sing === zxy.sing);Copy the code
  • There is a memory waste problem

Constructor prototype

Function Star(uname, age){this.name = uname this.age = age} Star.prototype = function (){console.log()} let LDH = new Star(' dandy ', 39) let zxy = new Star(' dandy ', 39) 34) // Since the function is a complex data type, the memory is allocated a separate space for this function. The above example instantiates two objects and creates two Spaces in memory for the same function at different addresses, so constructors are a waste of resources. console.log(ldh.sing === zxy.sing);Copy the code

Constructor functions assigned by stereotypes are shared by objects. Javascript states that each constructor has a Prototype property that points to another object. Note that prototype is an object whose properties and methods are owned by the constructor tree.

_proto_ Object Prototype

Note that the sing method can be called this way through ldh.sing() because there is also an object prototype on the objectprotoIt points to our constructor’s prototype object, so we can use it directly

Method lookup rules:

  • First check whether the LDH object has a sing method. If so, execute the sing method on the object.
  • If there is no sing method because __proto__ exists, use the prototype constructor to find sing

Summary: A prototype is an object in a constructor, also called a prototype or prototype object. It is an object that exists in every constructor. Its main function is to share the method, and once we define the method on the prototype object, all of our instance objects can call the method, and it’s shared, and there’s no extra space for the function.

Constructor constructor

Both proto and prototype objects have a constructor inside. We call it a constructor because it refers back to the constructor itself.

Function Star(uname, age){this.name = uname this.age = age} Prototype = function (){console.log(' prototype ')} let LDH = new Star(' prototype ') /*console.log(' prototype ') ', Star.prototype); The console. The log (' LDH. __proto__ : 'LDH. __proto__); * / console log (' Star. The prototype: 'Star. The prototype. The constructor); The console. The log (' LDH. __proto__ : ', LDH __proto__. Constructor);Copy the code

Print the result (you can see that the constructor itself is returned) :

Where constructor is used mainly to record which constructor the object refers to, it can redirect the prototype object to the original constructor.

One small detail: Suppose we define multiple shared methods:

Function Star(uname, age){this.name = uname this.age = age} Star.prototype.movie = function (){console.log(' movie ')} let LDH = function (){console.log(' movie ')} let LDH = function (){console.log(' movie ')} let LDH = function (){console.log(' movie ')} let LDH = function (){console.log(' movie ') New Star (' Andy lau, 39) LDH. Sing (LDH). The movie () the console. The log (' Star. The prototype: 'Star. The prototype. The constructor); The console. The log (' LDH. __proto__ : ', LDH __proto__. Constructor);Copy the code

This one up here is fine. Print the resultBut the following approach is problematic

Star.prototype = {function () {console.log(' sing ')}, movie: Function () {console.log(' movie ')}} let LDH = new Star(' dh.movie ', 39) ldh.sing() dh.movie() console.log(' star.prototype ') ', Star.prototype.constructor); The console. The log (' LDH. __proto__ : ', LDH __proto__. Constructor);Copy the code

Although methods can be printed, we can see that the original constructor that constructor points to becomes an object. This reason grammar question, if we have Star. The prototype. The constructor = sing () method is the modification operations on this property, Star.prototype = {sing()} Overrides the original constructor so there is no way to refer back to the original constructor. Of course, the correct solution here is to manually add a constructor and have it refer back to the original constructor.

Function Star(uname, age){this.name = uname this.age = age} /* star.prototype. sing = function (){console.log()} star.prototype. movie = function (){console.log()}*/ Star. Prototype = {constructor: Star, sing: function () {console.log()}, movie: Function () {console.log(' movie ')}} let LDH = new Star(' dh.movie ', 39) ldh.sing() dh.movie() console.log(' star.prototype ') ', Star.prototype.constructor); The console. The log (' LDH. __proto__ : ', LDH __proto__. Constructor);Copy the code

Print result:Summary: If we modify the original prototype object and assign a value to it, we must use constructor to refer back to the original constructor manually.

The relationship between constructors, instances, and prototype objects

First, the relationship between constructors and stereotypes:

The constructor’s Prototype property refers to the prototype object, and the constructor property refers back to the original constructor.

We can use the constructor new to refer to an instance object, so our constructor can refer to an instance object, and we know that the new instance object also has a _proto_ object that refers to a prototype object. Minor detail: our instance object also has a _proto_. Constructor constructor which can also refer to constructor but is equivalent to using the prototype object.

2. The prototype chain

Now we know that as long as there is an object, there must be an object prototype_proto_. Print example:

function Star(uname, Age){this.name = uname this.age = age} star.prototype. Sing = function (){console.log(' sing ')} let LDH = new Star(' Andy ', 49) ldh.prototype () prototypeCopy the code

You can see that the Prototype object also has an _ inside itproto_

function Star(uname, Age){this.name = uname this.age = age} star.prototype. Sing = function (){console.log(' sing ')} let LDH = new Star(' Andy ', 49) ldh.sing() console.log(star.prototype) console.log(star.proto__ === object.prototype)Copy the code

Print result:Here’s a diagram of the prototype chain:For example, if we create an instance of LDH, we need to use one of the member properties in the LDH. We first look for the Star prototype object, and if we don’t find it, we look for the DLH object instanceproto_Look for the prototype under Star; if found, point to the Star constructor via constructor; if not, continue up through _proto_Constructor (); constructor (); constructor (); constructor ();

Javescript member lookup mechanism (Rules)

  • When accessing an object property (or method), the first thing to look for is whether the object itself has the property.
  • If not, look up its prototype, which is _proto_The Prototype object pointing to.
  • If not, find the prototype of the prototype Object (that is, the prototype Object of Object).
  • And so on until Object is found (undefain is returned if not found).

Example: Give the Star object a sex member property

function Star(uname, Age){this.name = uname this.age = age} star.prototype. Sing = function (){console.log(' sing ')} let LDH = new Star(' Andy Lau ', 49) // here we give the LDH object a sex member property. Ldh.sex = 'male' // This is the member property of the Star object console.log(ldh.sex)Copy the code

Example 2: Give the Star prototype object a sex member property

function Star(uname, Age){this.name = uname this.age = age} star.prototype. Sing = function (){console.log(' sing ')} let LDH = new Star(' Andy Lau ', 49) // Here we give the Star object a member attribute. * / * console.log('Star prototype: '+ ldh.sex) console.log('Star prototype:' + ldh.sex)Copy the code

Example 3: Give an Object a sex member property

function Star(uname, Age){this.name = uname this.age = age} star.prototype. Sing = function (){console.log(' sing ')} let LDH = new Star(' Andy Lau ', 49) // This gives the Object a member property. Object.prototype.sex = 'male' console.log(LDH) console.log('Object prototype: '+ ldh.sex)Copy the code

Example 3: Add a sex member to LDH, Star, and Object prototype objects.

function Star(uname, Age){this.name = uname this.age = age} star.prototype. Sing = function (){console.log(' sing ')} let LDH = new Star(' Andy Lau ', 49) // Here we give the Star object a sex member attribute. Ldh. sex = 'male' // here we give the Star object a member attribute. Star.prototype.sex = 'female' // this gives the Object a member property. Object.prototype.sex = 'unknown' console.log(LDH) console.log(ldh.sex)Copy the code

Summary: it is a layer by layer through the prototype Object online search, until the Object, and if there are more than one same member, will take the nearest principle.

The prototype object this points to

var that function Star(uname, {this.name = uname this.age = age that = this} star.prototype. Sing = function (){console.log(' sing ')} let LDH = New Star(' Andy Lau ', 49) // 1. Inside the constructor, this refers to the object instance. // Because even if we add sing to the prototype object, the caller is still LDH, So this points to the LDH object instance ldh.sing() console.log(that === LDH) // 2. The this in the prototype object refers to the instance object LDHCopy the code

Extending built-in objects (a typical use of a prototype object that extends built-in methods)

You can extend methods in built-in objects by using prototype objects. For example, adding a custom sum to an array.

So let’s just print it out and see what the built-in methods and properties are inside the array object.

console.log(Array.prototype)
Copy the code

I took a quick look at some of the built-in methods that we see all the time. It’s because of these built-in methods that we can easily manipulate arrays, so let me customize a built-in method. Example:

Array.prototype.sum = function (){ let sum = 0 for (let i = 0; i < this.length ; i++){ sum += this[i] } return sum } console.log(Array.prototype)Copy the code

The print result shows that our custom sum method has been inserted into the Array.Let’s use it:

Array.prototype.sum = function (){ let sum = 0 for (let i = 0; i < this.length ; Sum ++){sum += this[I]} return sum} Let arr = [1, 10, 100] console.log(arr.sum())Copy the code

Print result:

Minor detail: Why is arR an instance object here? Now let’s verify that

Let arr2 = new Array() console.log(arr1) console.log(arr2) console.log(typeof arr1) === typeof arr2)Copy the code

Print result:You can see it’s just the way it’s defined and the syntax is different, but it’s the same thing.