Today, my colleague Xiaoying asked me a question:



function Foo(firstName, lastName){
    this.firstName = firstName;
    this.lastName = lastName; 
}
Foo.prototype.logName = function(){
    Foo.combineName();
    console.log(this.fullName);
}
Foo.prototype.combineName = function(){
    this.fullName = `The ${this.firstName} The ${this.lastName}`
}

var foo = new Foo('Sanfeng'.'Zhang');
foo.logName(); // Uncaught TypeError: Foo.combineName is not a functionCopy the code

Small English children’s shoes think the prototype object Foo is Foo prototype, so Foo will inherit Foo. The properties of the prototype, calls Foo.com bineName () is equivalent to calling Foo.prototype.com bineName (), But Foo.combineName() turns out not to be a method.

The reason for this problem must be that Xiaoying has confused some principles of prototype and inheritance. Let’s sort out the relevant principles of prototype and inheritance and find out the root cause of the problem.

prototype

Prototype is a property of an object with a [[Construct]] inner method.

Such as functions, methods on objects, classes in ES6. Note that the arrow function in ES6 has no [[Construct]] method and therefore no prototype property unless you add one to it.

When you create a function, JavaScript automatically adds a prototype property to the function, which points to a prototype object functionName.prototype. We can add properties or objects to the prototype object, or even point to an existing object.

__proto__

Next, inheritance. Each object has a __proto__ attribute that identifies the stereotype it inherits from.

Note: Every object in JavaScript has a built-in property [[Prototype]]. Prior to ES5 there was no standard way to access this built-in property, but most browsers supported __proto__ access. The following uses __proto__ to access [[Prototype]], which is not available in real development.

Prototype chain

JavaScript can create an association between two objects using prototype and __proto__ so that one object can delegate to the other object’s properties and functions.

Such an association is a stereotype chain, a finite chain of objects that implements inheritance and shared properties.

The constructor creates an object instance

JavaScript functions have two different internal methods: [[Call]] and [[Construct]].

If the function is not called through the new keyword, the [[Call]] function is executed, thus directly executing the function body in the code.

When a function is called with the new keyword, the [[Construct]] function executes, which creates an instance object and inherits all the properties and methods of prototype by pointing its __proto__ attribute at the prototype constructor. Bind this to the instance, and then execute the function body.

Simulate a constructor:



function createObject(proto) {
    if(! (proto ===null || typeof proto === "object" || typeof proto === "function") {throw TypeError('Argument must be an object, or null');
    }
    var obj = new Object(a); obj.__proto__ = proto;return obj;
}

var foo = createObject(Foo.prototype);Copy the code

Now that we know what Prototype and __proto__ do and what they point to when we use constructors to create object instances, here’s a diagram summarizing how prototype chains can be implemented with Prototype and __proto__.

From the above we can find the prototype chain of foo object and foo function:



foo.__proto__ == Foo.prototype;
foo.__proto__.__proto__ == Foo.prototype.__proto__ == Object.prototype;
foo.__proto__.__proto__.__proto__ == Foo.prototype.__proto__.__proto__ == Object.prototype.__proto__ == null;Copy the code



Foo.__proto__ == Function.prototype;
Foo.__proto__.__proto__ == Function.prototype.__proto__;
Foo.__proto__.__proto__.__proto__ == Function.prototype.__proto__.__proto__ == Object.prototype.__proto__ == null;Copy the code

Constructor Foo does not have Foo. Prototype on its prototype chain, so it cannot inherit properties and methods from Foo. Prototype. Instance foo, on the other hand, has foo. Prototype on its prototype chain, so foo can inherit properties and methods from foo. Prototype.

Foo. Prototype is not in the prototype chain of Foo. Prototype, can not inherit Foo. Foo.binename is not a function. To use combineName method, it can be Foo.prototype.com bineName. Call (this), or such this.com bineName () (this point to instance objects).

Welcome to Leechikit: SegmentFault.com

The end of this article, questions and comments are welcome. Writing original articles is not easy, if this article is helpful to you, please like, recommend and follow the author to support.