Introduction
As mentioned above, there are literal and factory modes and constructor modes for creating objects. It is found that they have their own shortcomings. So I will introduce several ways to create objects to try to find a painless mode (vii).
Prototype pattern
There will be a very obscure paragraph below, so keep up with it and don't roll over.
Each function we create has a prototype attribute, which is a pointer (address) to an object that contains properties and methods that can be shared by all instances of a particular type.
function Person () { } Person.prototype.name = 'Li Xiaohua'; Person.prototype.age = '60'; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); person1.sayName(); //Li Xiaohua var person2 = new Person(); person2.sayName(); //Li Xiaohua
In the prototype attribute of Person, the constructor is empty. Attributes and instances on new objects are shared. Now one thing we need to do is understand the prototype object.
Understanding prototype objects
Whenever a new function is created, a prototype attribute is created for the function according to a set of specific rules. This attribute points to the prototype object of the function. All prototypes will get a constructor attribute, pointing to the pointer of the function where the prototype attribute is located. We use this constructor to add other methods and attributes to the prototype object. When an object is created, its prototype object defaults to only the constructor attribute. When the constructor creates a new instance, the interior of the instance will contain a pointer to the prototype of the constructor. Although there is no standard way to access [[Prototype]] in scripts, there is support for a _proto_ except IE. This property exists directly on the prototype object of the instance and constructor, but not between the instance and the constructor.
Are you dizzy? Let me show you the corresponding concern between each other with a picture below. Look, I want to show my superb drawing skills.
Soul picture has been displayed, I believe you have understood it. It should be noted that although neither of these instances contains attributes or methods, we can invoke methods on the prototype on the instance, which is achieved through the process of finding object attributes.
To extend, since js cannot instance [[Prototype], this relationship can be determined by isPrototype().
console.log(Person.prototype.isPrototypeOf(person1)); // true
In es5, a new method called Object.getPrototype() is added, which returns the value of [[Prototype]], for example,
console.log(Object.getPrototypeof(person1) == Person.prototype) //true console.log(Object.getPrototypeof(person1).name) //Li Xiaohua
Similarly, browsers below IE8 do not support this attribute.
Every time the code reads an attribute of an object, it performs a search. The goal is an attribute with a given name. The search begins with the instance itself. If the attribute is found in the instance itself, the value of the attribute is returned. If not, the prototype object pointed by the pointer is continued. If found, the value of the attribute is returned.
Although the values stored in the prototype can be accessed through object instances, the values in the prototype can not be overridden by objects. If we add an attribute to an instance with the same name as an attribute in the instance prototype, this attribute masks that attribute in the prototype.
function Person () { } Person.prototype.name = 'Li Xiaohua'; Person.prototype.age = '29'; Person.prototype.job = 'Class flower'; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = 'Zhang Quanegg'; console.log(person1.name); // Zhang Quanegg console.log(person2.name); // Li Xiaohua
When an attribute is added to an object, it masks the same-name attribute of the prototype object. Adding this attribute only prevents us from accessing that attribute of the prototype, but does not modify that attribute. Using delete attribute allows us to access the attributes in the prototype.
function Person () { } Person.prototype.name = 'Li Xiaohua'; Person.prototype.name = '29'; Person.prototype.job = 'Class flower'; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = 'Zhang Quanegg'; console.log(person1.name); // Zhang Quanegg console.log(person2.name); // Li Xiaohua delete person1.name console.log(person1.name); // Li Xiaohua
When traversing the attributes of an object, we often need to determine whether the attributes come from the prototype or attributes of the object.
function Person () { } Person.prototype.name = 'Li Xiaohua'; Person.prototype.name = '29'; Person.prototype.job = 'Class flower'; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); var person2 = new Person(); console.log(person1.hasOwnProperty('name')); // false person1.name = 'Zhang Quanegg'; console.log(person1.hasOwnProperty('name')); // true console.log(person1.name); // Zhang Quanegg console.log(person2.name); // Li Xiaohua delete person1.name console.log(person1.name); // Li Xiaohua
We have a magic artifact, the hasOwnProperty method, which returns true only when the attribute is the attribute of the instance.
In Method in Prototype Operator
I described how to use hasOwnProperty method to determine whether attributes come from object attributes, and how to determine whether attributes come from prototype chains.
Here is a grand introduction to the in operator, but attributes from attributes or attributes from prototype chains will return true. We use this attribute combined with hasOwnProperty method to determine whether attributes come from prototype chains.
function hasPrototypeproperty(obj, name) { return !object.hasOwnProperty(name) && (name in obj) }
function Person () { } Person.prototype.name = 'Li Xiaohua'; Person.prototype.name = '29'; Person.prototype.job = 'Class flower'; Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person(); console.log(hasPrototypeproperty(person, 'name')); // true person1.name = 'Zhang Quanegg'; console.log(hasPrototypeproperty(person, 'name')); // false
When using the for-in loop, the returned properties can be accessed through the object, enumerable attributes, including the attributes in the instance, also include the attributes existing in the prototype, and the non-enumerable attributes in the shielded prototype will also be returned in the for-in. An array of strings containing all enumerable properties can be returned through the Object.keys method in es5.
function Person () { } Person.prototype.name = 'Li Xiaohua'; Person.prototype.age = '29'; Person.prototype.job = 'Class flower'; Person.prototype.sayName = function () { console.log(this.name); }; var keys = Object.keys(Person.prototype); console.log(keys); //name age job sayName var p1 = new Person(); p1.name = 'Whole egg'; p1.age = 20; var p1keys = Object.keys(p1); console.log(p1keys); // name,age