1.prototype object
1.1 Cons of constructors
JavaScript generates new objects through constructors, so constructors can be considered as templates for objects. The properties and methods of the instance object can be defined inside the constructor.
function Cat (name, color) { this.name = name; this.color = color;}var cat1 = new Cat('big hair', 'white');cat1.name // 'big hair'cat1.color // 'white'The Cat function in the above code is a constructor. The name attribute and color attribute are defined internally. All instance objects will generate these two attributes. However, doing so is a waste of system resources, because properties cannot be shared between object instances of the same constructor.
function Cat(name, color) { this.name = name; this.color = color; this.meow = function () { console.log('mew, mew, mew...'); };}var cat1 = new Cat('big hair', 'white');var cat2 = new Cat('ei Mao', 'black');cat1.meow === cat2.meow// falseIn the above code, cat1 and cat2 are instances of the same constructor. However, their meow methods are different, that is, every time a new instance is created, a new meow method will be created. This is neither necessary nor wastes system resources, because all meow methods are the same behavior and should be shared completely.
1.2 The role of prototype attribute
In JavaScript language, each object has a corresponding prototype object, called a prototype object. All properties and methods defined on the prototype object can be inherited by the derived object. This is the basic design of the JavaScript inheritance mechanism.
In addition to this approach, JavaScript also provides another way to define instance objects. We know that a constructor is a function, an object, and also has its own properties and methods. One prototype attribute points to another object, which is generally called a prototype object. This object is very special. As long as the properties and methods defined on it can be shared by all instance objects. That is to say, when the constructor generates an instance object, a prototype attribute is automatically assigned to the instance object.
function Animal (name) { this.name = name;}Animal.prototype.color = "white";var cat1 = new Animal('big hair');var cat2 = new Animal('erimao');cat1.color // 'white'cat2.color // 'white'The above code adds a color attribute to the prototype object of the constructor Animal. As a result, both instance objects cat1 and cat2 carry this property.
More particularly, as long as the prototype object is modified, the changes will be immediately reflected in the instance object.
Animal.prototype.color = "yellow";cat1.color // 'yellow'cat2.color // 'yellow'
The above code changes the value of the color attribute of the prototype object to yellow, and the value of the color attribute of the two instance objects will immediately change. This is because the instance object actually has no color attribute, and they all read the color attribute of the prototype object. That is to say, when the instance object itself does not have a certain property or method, it will go to the constructor's prototype object to find the property or method. This is the special thing about prototype objects.
If the instance object itself has a certain property or method, it will no longer look for this property or method in the prototype object.
cat1.color = 'black';cat2.color // 'yellow'Animal.prototype.color // "yellow";
The above code changes the color property of the instance object cat1 to black, so that it no longer needs to read the color property from the prototype object, and the value of the latter is still yellow.
In short, the function of the prototype object is to define the properties and methods shared by all instance objects, so it is also called the prototype of the instance object, and the instance object can be regarded as derived from the prototype object.
Animal.prototype.walk = function () { console.log(this.name + ' is walking.');};The above code defines a walk method on the Animal.protype object, which will be called on all Animal instance objects.
1.3 Prototype chain
Since all objects in JavaScript have constructors, and all constructors have prototype attributes (actually all functions have prototype attributes), all objects have their own prototype prototype objects.
Therefore, the properties and methods of an object may be defined on itself or on its prototype object (like the walk method in the above code). Since the prototype itself is an object and has its own prototype, a prototype chain is formed. For example, object a is the prototype of object b, object b is the prototype of object c, and so on. Because tracing the root of the source, the objects at the source are generated from the Object constructor (using the new Object() command), so if you trace it up layer by layer, the prototype of all objects can eventually be traced to Object.prototype. So, is there a prototype for Object.prototype? The answer can be yes or no, because the prototype of Object.prototype is a null without any properties and methods.
Object.getPrototypeOf(Object.prototype)// null
The above code indicates that the prototype of the Object.prototype object is null. Since null has no properties, the prototype chain ends here.
The function of "prototype chain" is that when reading a certain attribute of an object, the JavaScript engine first looks for the attributes of the object itself. If it cannot be found, it will look for its prototype. If it still cannot be found, it will look for the prototype of the prototype. And so on, if the Object.prototype at the top level is still not found, it returns undefined.
For example, if a function's prototype attribute points to an array, it means that the function can be used as an array constructor, because the instance objects it generates can call the array method through the prototype attribute.
function MyArray (){}MyArray.prototype = new Array();MyArray.prototype.constructor = MyArray;var mine = new MyArray();mine.push(1, 2, 3);mine.length // 3mine instanceof Array // trueThe mine in the above code is an instance object of MyArray. Since the prototype property of MyArray points to an array, mine can call array methods (these methods are actually defined on the prototype object of the array). As for the last line of instanceof expression, we know that the instanceof operator is used to compare whether an object is an instance of a constructor, and the last line indicates that mine is an instance of Array.
mine instance of Array// is equivalent to (Array === MyArray.prototype.constructor) ||(Array === Array.prototype.constructor) ||(Array === Object.prototype.constructor)
The above code illustrates the essence of the instanceof operator, which is compared with the constructor attributes of all prototype objects of the instance object (for the introduction of this attribute, please see the next section). As long as there is one, it will return true, otherwise it will return false.
1.4 constructor attribute
The prototype object has a constructor attribute that points to the constructor function where the prototype object is located by default.
function P() {}P.prototype.constructor === P// trueSince the constructor attribute is defined on the prototype object, it means that it can be inherited by all instance objects.
function P() {}var p = new P();p.constructor// function P() {}p.constructor === P.prototype.constructor// truep.hasOwnProperty('constructor')// falseThe above code indicates that p is an instance object of constructor P, but p itself does not have a constructor attribute, which is actually reading the P.prototype.constructor attribute on the prototype chain.
The function of the constructor attribute is to distinguish which constructor the prototype object is defined on.
function F(){};var f = new F();f.constructor === F // truef.constructor === RegExp // falseThe above code means that using the constructor property, it is determined that the constructor function of the variable f is F, not RegExp.
2.Object.getPrototypeOf method
The Object.getPrototypeOf method returns the prototype of an object.
// The prototype of the empty object is Object.prototypeObject.getPrototypeOf({}) === Object.prototype// true// The prototype of the function is Function.prototypefunction f() {}Object.getPrototypeOf(f) === Function.prototype// true// Assume F is a constructor and f is an instance object of F// Then, the prototype of f is F.prototypevar f = new F();Object.getPrototypeOf(f) === F.prototype// true3.Object.create method
The Object.create method is used to generate a new object and can replace the new command. It accepts an object as an argument and returns a new object, which completely inherits the properties of the former, that is, the former becomes the prototype of the latter.
var o1 = { p: 1 };var o2 = Object.create(o1);o2.p // 1In the above code, the Object.create method generates o2 based on o1. At this time, o1 becomes the prototype of o2, that is, o2 inherits all the properties of o1.
The Object.create method is basically equivalent to the following code. If the old browser does not support the Object.create method, you can use the following code to deploy it yourself.
if (typeof Object.create !== "function") { Object.create = function (o) { function F() {} F.prototype = o; return new F(); };}The above code shows that the Object.create method is essentially creating a new constructor F, then allowing F's prototype attribute to point to object o as the prototype, and finally returning an instance of F, so that the instance can inherit the attributes of o.
The new objects generated in the following three ways are equivalent.
var o1 = Object.create({});var o2 = Object.create(Object.prototype);var o3 = new Object();If you want to generate an object that does not inherit any properties (such as toString and valueOf methods), you can set the Object.create parameter to null.
var o = Object.create(null);o.valueOf()// TypeError: Object [object Object] has no method 'valueOf'
The above code indicates that if the prototype of object o is null, it does not have some properties defined on the Object.prototype object, such as the valueOf method.
When using the Object.create method, an object prototype must be provided, otherwise an error will be reported.
Object.create()// TypeError: Object prototype may only be an Object or null
The new object generated by the Object.create method dynamically inherits the prototype. Adding or modifying any method on the prototype will immediately reflect on the new object.
var o1 = { p: 1 };var o2 = Object.create(o1);o1.p = 2;o2.p// 2The above code indicates that modifying the object prototype will affect the newly generated object.
In addition to the object prototype, the Object.create method can also accept a second parameter, representing the attributes object describing the attributes, which is the same format as the Object.defineProperties method used. The object properties it describes will be added to the new object.
var o = Object.create(Object.prototype, { p1: { value: 123, enumerable: true }, p2: { value: "abc", enumerable: true }});o.p1 // 123o.p2 // "abc"Since the Object.create method does not use a constructor, the instanceof operator cannot be used to determine which constructor instance the object is. At this time, you can use the following isPrototypeOf method to interpret which object the prototype is.
4.isPrototypeOf method
The isPrototypeOf method is used to determine whether an object is a prototype of another object.
var o1 = {};var o2 = Object.create(o1);var o3 = Object.create(o2);o2.isPrototypeOf(o3) // trueo1.isPrototypeOf(o3) // trueThe above code shows that isProtypeOf returns true as long as an object is on the prototype chain.
5. A simple example
var ClassDemo = function () { //static private variable var private_static_var = 'aaaa'; //static private method var private_static_func = function (key) { return key + private_static_var; } //private method, the key is to pass this var private_func = function (self, key) { return private_static_func(key + self.id); } var _class = function (id) { //constructor this.id = id; //public variable} //public method_class.prototype.public_func = function (key) { return private_func(this, key); } return _class;}();var a = new ClassDemo('hello world');alert(a.public_func('world hello'));There is no simple way to implement private variables and public static variables/methods, but encapsulation is enough to be done to this extent.