Taihang, Wangwu two mountains, square seven hundred li, high maninsan. Ben is in the south of Jizhou, north of Heyang…….

Well, by convention, the first sentence is a trick. Before you read this article, I hope you have some knowledge of Javascript prototypes and prototype chains, which will help you understand this article better. But it doesn’t have to be.

Everybody back off. I’m going back to my story.

At the age of 90, yu Gong of the North Mountain lived facing the mountain.

var person = {
    name : 'yu Mr..age: 90.address: 'At the foot of the North Mountain'.whereToLive: function () {
        alert(this.address)
    }
};
Copy the code

. Yu Gong of beishan said, “Though I die, my son will survive. Son begot grandson, and grandson begot son; Children had children, and children had grandchildren; Want not children, want not grandchildren.

The problem is that there are so many children of the Foolish old man that using object literals to create objects is not reasonable. We introduce the first creation method.

The factory pattern

function createPerson (name, age, address){
    var o = new Object(a); o.name = name; o.age = age; o.address = address; o.whereToLive =function () {
        alert(this.address)
    };
    return o;
}

var son = createPerson('Fool boy'.30.'beishan');
var grandSon = createPerson('Silly Little Man'.5.'beishan');
Copy the code

One of the obvious disadvantages of the factory pattern is that because an intermediate object is generated and returned, the type of the object cannot be determined.

Constructor pattern

function Person(name, age, address) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.whereToLive = function(){
            alert(this.address);
        }; 
}
var son = new Person('Fool boy'.30.'beishan');
var grandSon = new Person('Silly Little Man'.5.'beishan');
Copy the code

Constructors are the same as normal functions, without any syntax differences, except that they are called with the new keyword. So it’s worth saying what new does:

  1. Create a new intermediate object
  2. Assign the constructor’s action to the intermediate object
  3. Execute the code in the constructor
  4. Return intermediate object

Take the code here as an example. The actions in steps 2 and 3 can actually be summarized as Person.apply(newObject,arguments). By the way one difference between bind and call/apply is that bind returns a function, Call /apply executes this function incidentally and returns the result of the execution.

So, what’s wrong with the constructor model? It’s also obvious. If Yu Gong has a thousand children and grandchildren, then each of them will have a whereToLive method

The prototype pattern

function Person () {
    
}

Person.prototype.name = 'yu Mr.;
Person.prototype.age = 90;
Person.prototype.address = 'beishan';
Person.prototype.whereToLive = function () {
    alert(this.address); 
};

var son = new Person();
var grandSon = new Person();
son.name = 'Fool boy';
son.address = 'Beyond the Hill';


son.whereToLive();   // 'Beyond the hill'
grandSon.whereToLive();   // select * from *;

Copy the code

We tried to modify the Address property on the Son object, and it seemed to work, but it didn’t affect the grandSon property. So these two addresses are not the same. Why is that? We are doing the following:

delete son.address;
son.whereToLive();   // select * from *;
Copy the code

We delete the son address property, and son’s address becomes the value defined in the prototype. So when we modify the Address property, instead of touching the value in the prototype, we create a new property on the object. The value of the property on the object is returned first when attempting to obtain the property. We call this attribute masking.

In addition, when reading object properties, it will first check whether the object itself is available. If not, it will search up the prototype chain. If it reaches the top of the prototype chain and does not find it, it will return undefined. Here’s another point of knowledge. A lot of beginner developers make this mistake:

var a = {};
console.log(a.b.c)
Copy the code

Attempts to obtain property C without verifying the presence of property B. If a is not found at the top of the prototype chain, the value of a.b is undefined, so getting the c attribute of undefined is always an error. The right thing to do is to make a judgment when you are not sure whether a corresponding attribute exists.

If the current object does not find the property to write to, it does not look up. Instead, it creates a new property in the current object. The reason for doing this is to prevent contaminating the property values of other objects. If you were careful, you might have noticed that I emphasized the primitive type properties at the beginning. What if it’s a reference type?

function Person () {
    
}

Person.prototype.name = 'yu Mr.;
Person.prototype.age = 90;
Person.prototype.address = ['beishan'];
Person.prototype.whereToLive = function () {
    alert(this.address); 
};

var son = new Person();
var grandSon = new Person();
son.address.push('Beyond the Hill');

grandSon.whereToLive();   // The other side of the mountain

Copy the code

Another tidbit here is that reference types exist in heap memory, and applications in different places actually refer to the same heap memory. So if you try to change the application type in the prototype object, it will cause global contamination, which is a fatal shortcoming of the prototype pattern.

Use a combination of constructor and stereotype patterns

Sit tight. I’m going to introduce some new points. We can use shorthand to avoid the verbose problem of the stereotype pattern assigning methods to prototype objects.

function Person(name, age, address) {
        this.name = name;
        this.age = age;
        this.address = address;
}
Person.prototype = {
    constructor : Person,  // Manually change the constructor pointing
    whereToLive : function () {
        alert(this.address); 
    },
    howOld : function () {
        alert(this.age); }}Copy the code

Does the combination of the constructor pattern and the prototype pattern circumvent the problem of both? You can share common functions while allowing each object to have its own attributes.

Note that when we overwrote Person.prototype, we actually made constructor point to Object, so I made a manual fix here.

Parasitic constructor pattern

function PersonList (name, age, address){
    var o = new Array(a); o.push.apply(o,arguments);
    o.consoleString = function () {
       return this.join(",");
    };
    return o;
}

var list = new PersonList('Fool boy'.'Silly Little Man');
alert(list.consoleString());
Copy the code

Does it look familiar? It’s the same as factory mode, but with the new keyword when called. With this pattern, we can add additional capabilities to objects. In this case, we’re adding a custom method to the array to give it new capabilities.

conclusion

In the actual development or according to the actual scene flexible use, there is always a suitable one for you. That’s all for today. We welcome your comments and corrections.