Several commonly used object creation modes
Create with new keyword
The most basic way to create objects is nothing more than what most languages say: if you don’t have objects, you can get new!
var gf = new Object();gf.name = "tangwei";gf.bar = "c++";gf.sayWhat = function() { console.log(this.name + "sad:love you forever");}Create with literals
This seems to be true, but how can geeks like such complex and low-level way of defining variables? As a scripting language, it should have the same style as other brothers, so the way of defining object literals appears:
var gf = { name : "tangwei", bar : "c++", say What : function() { console.log(this.name + "sad:love you forever"); }}Factory model
Actually, this is the most commonly used object definition method in reality, but what should I do if I have many objects with similar attributes (it's exciting to think about it...)? If one definition is made one by one, a large amount of code will be generated. Why not build a factory and mass produce our objects? So, the first inflatable baby in the javascript world. . . No, the "factory model" is born!
function createGf(name, bar) { var o = new Object(); o.name = name; o.bar = bar; o.sayWhat = function() { alert(this.name + "sad:love you forever"); } return o;}var gf1 = createGf("bingbing","d");var gf2 = createGf("mimi","a");Constructor
The factory pattern solves the problem of creating multiple similar objects, but the problem comes again. These objects are all formed by Objects. How to distinguish the specific types of their objects? At this time, we need to switch to another mode, constructor mode:
function Gf(name,bar){ this.name = name; this.bar = bar; this.sayWhat = function(){ alert(this.name + "said:love you forever"); }}var gf1 = new Gf("vivian","f");var gf2 = new Gf("vivian2","f");Here we use a constructor starting with capital letters to replace createGf in the above example. Note that the first letter of the constructor should be capitalized according to the convention. Here we create a new object, then assign the scope of the constructor to the new object, and call the methods in the constructor.
There seems to be nothing wrong with the above method, but we can find that the sayWhat method in the constructor called in the two instances is not the same Function instance:
console.log(gf1.sayWhat == gf2.sayWhat); //false
Calling the same method but declaring different instances is a waste of resources. We can optimize the statement of the sayWhat function outside the constructor:
function Gf(name,bar){ this.name = name; this.bar = bar; this.sayWhat = sayWhat}function says What(){ alert(this.name + "sad:love you forever");}This solves the problem of defining the same method instance multiple times, but a new problem comes again. The saying What we defined is a global scope method, but this method cannot be called directly, which is a bit contradictory. How to more elegantly define an object with certain encapsulation? Let's take a look at the JavaScript prototype object pattern.
Prototype object pattern
Understand prototype objects
When we create a function, the function will have a prototype attribute, which points to the prototype object of the function created through the constructor. In layman's terms, prototype objects are objects in memory that provide shared properties and methods for other objects.
In the prototype mode, there is no need to define instance attributes in the constructor, and the attribute information can be directly assigned to the prototype object:
function Gf(){ Gf.prototype.name = "vivian"; Gf.prototype.bar = "c++"; Gf.prototype.sayWhat = function(){ alert(this.name + "sad:love you forever"); }}var gf1 = new Gf();gf1.sayWhat();var gf2 = new Gf();The difference from the constructor is that the properties and methods of the new object can be shared by all instances. In other words, gf1 and gf2 access the same properties and methods. In addition to the attributes we have assigned, there are also some built-in attributes in the prototype object. All prototype objects have a constructor attribute, which is a pointer to a function containing the prototype attribute (whether you dare to go around the point again!). Through a picture, let’s clearly sort out the process of this twisting:
All objects have a prototype object (prototype). There is a constructor attribute in the prototype object pointing to a function containing the prototype attribute. Gf's instances gf1 and gf2 both contain an internal attribute pointing to the prototype object (proto appears as a private attribute in the firefox browser). When we access the attribute in an object, we will first ask whether the instance object has this attribute. If not, we will continue to look for the prototype object.
Using prototype objects
In the previous example, we noticed that when adding properties to the prototype object, we need to add Gf.prototype to each. This work is very repetitive. In the above object creation pattern, we know that an object can be created in the form of literals. Here we can also improve it:
function Gf(){}Gf.prototype = { name : "vivian", bar : "c++", say What : function(){ alert(this.name + "sad:love you forever"); }}There is a place where we need to pay special attention to. The constructor attribute no longer points to the object Gf, because every time a function is defined, a prototype object will be created for it at the same time, and this object will automatically obtain a new constructor attribute. In this place, we use Gf.prototype to essentially overwrite the original prototype object, so the constructor has also become the constructor attribute of the new object, no longer pointing to Gf, but Object:
var gf1 = new Gf();console.log(gf1.constructor == Gf);//falseconsole.log(gf1.constructor == Object)//true
Generally, this subtle change will not affect us, but if you have special needs for constructor, we can also explicitly specify the constructor property of Gf.prototype:
Gf.prototype = { constructor : Gf, name : "vivian", bar : "c++", say What : function() { alert(this.name + "said:love you forever"); }}var gf1 = new Gf();console.log(gf1.constructor == Gf);//trueThrough a preliminary understanding of the prototype object pattern, we found that all instance objects share the same attributes, which is the basic feature of the prototype pattern, but often this is a "double-edged sword" for developers. In actual development, the instances we hope should have their own attributes, which is also the main reason why few people use the prototype pattern alone in actual development.
Constructor and prototype combination pattern
In actual development, we can use constructors to define the properties of objects and use prototypes to define shared properties and methods, so that we can pass different parameters to create different objects, while having shared methods and properties.
function Gf(name,bar){ this.name = name; this.bar = bar;}Gf.prototype = { constructor : Gf, say What : function() { alert(this.name + "sad:love you forever"); }}var gf1 = new Gf("vivian", "f");var gf2 = new Gf("vivian1", "c");In this example, we define the respective property values of the objects in the constructor function, and define the constructor attribute and say What function in the prototype object, so that there will be no impact between the gf1 and gf2 attributes. This pattern is also the most commonly used object definition method in actual development, including the default mode adopted by many js libraries (bootstrap, etc.).