Several patterns of JavaScript creation objects

Source: Internet
Author: User
Tags instance method hasownproperty

While the object constructor or object literal can be used to create a single object, there are obvious drawbacks to these approaches: creating many objects using the same interface produces a lot of duplicate code. To solve this problem, people began to use a variant of the factory model.

1. Factory mode

function Createperson (name, age, job) {      var o=new Object ();      O.name = name;      O.age = age;      O.job = job;      O.sayname = function () {            alert (this.name);      };      return o;}  var person1 = Createperson (' zcy ', +, ' software Engineer '); var person2 = Createperson (' bb ', "software Engineer ');              

The function Createperson () is able to construct a person object that contains all the necessary information based on the parameters that are Accepted. This function can be called countless times, and each time it returns an object that contains a method of three Attributes. Although the factory model solves the problem of creating multiple similar objects, but does not solve the problem of object recognition (that is, How to know the type of an Object), a new pattern emerges as JavaScript progresses.

2. Constructor mode

function Person (name, age, job) {      this.name = name;      This.age = age;      This.job = job;      This.sayname = function () {            alert (this.name);      };}  var person1 = new person (' zcy ', +, ' software Engineer '), var person2 = new Person (' bb ', ', ' software Engineer ');

The constructor pattern differs from the Factory mode in the following ways:

Object not explicitly created;

The properties and methods are assigned directly to the this object;

There is no return statement.

To create a new instance of person, you must use the new Operator. This method of calling the constructor actually goes through the following 4 steps:

(1) Create a new object;

(2) assigns the scope of the constructor to the new object (so this points to the new object);

(3) executing the code in the constructor (adding attributes to the new object);

(4) returns the new Object.

In the previous example, Person1 and Person2 each hold a different instance of Person. Both objects have a constructor (constructor) property that points to Person.

Alert (person1.constructor = = person); True

Alert (person2.constructor = = person); True

To detect the object type, you can use the instanceof operator, which is an example of an object created by the Chinese year, and an instance of the Person.

Creating a custom constructor means that its instance can be identified as a specific type in the future, and that is where the constructor pattern is better than the factory Pattern.

The only difference between constructors and other functions is that they are called in different ways. however, The constructor is also a function, there is no special syntax to define the constructor, any function as long as the new operator is called, it can be used as a constructor, and any function, if not called by the new operator, it is not the same as the normal Function. The person () function defined earlier can be called in any of the following ways.

Use Var as the constructor function = new person (' zcy ', ' software Engineer ');p erson.sayname ();//"zcy"//as a normal function call
When a function is called in the global scope, the This object always points to the Global Object (the window object in the browser) person (' zcy ', ' software ', ' Engineer '); window.sayname ();//" Zcy "//in The scope of another object call Var o= new Object (); Person.call (o, ' zcy ', +, ' software Engineer '); o.sayname ();//"zcy"

  The main problem with constructors is that each method is recreated on each instance, in the previous example, Person1 and Person2 have a method named Sayname (), but the two methods are not instances of the same function. Don't forget that the function in ECMAScript is an object, so every definition of a function is an instantiation of an object.


Alert (person1.sayname = = person2.sayname); False

It is not necessary to create two function instances that accomplish the same task, and there is no need to bind the function to a specific object long before executing the Code. therefore, The function definition can be transferred to the outside of the constructor to solve the Problem.

function Person (name, age, job) {      this.name = name;      This.age = age;      This.job = job;      This.sayname = sayname;}  function Sayname () {            alert (this.name);} var person1 = new person (' zcy ', +, ' software Engineer '), var person2 = new Person (' bb ', ', ' software Engineer ');

This does solve the problem of two functions doing the same thing, but the new problem comes again: functions defined in the global scope can actually be called only by an object, which makes the global scope a bit of a misnomer. What is even more unacceptable is that if an object needs to define many methods, it is necessary to define many global functions, so we have no encapsulation of this custom reference type . fortunately, These problems can be solved by using prototype Mode.

3. Prototype mode

  Each function we create has a prototype (prototype) attribute, which is a pointer to an object, and the purpose of this object is to include properties and methods that can be shared by all instances of a particular type. If it is understood literally, then prototype is the prototype object of the object instance created by invoking the Constructor. The advantage of using a prototype object is that you can have all object instances share the properties and methods that it contains. In other words, instead of defining the information for an object instance in the constructor, you can add that information directly to the prototype Object. As shown below. (personal understanding, properties and methods in prototypes are equivalent to static properties and methods in Java classes)

function person () {}person.prototype.name = ' Zcy '; Person.prototype.age = 26; Person.prototype.job = ' Software Engineer '; Person.prototype.sayName = function () {      alert (this.name);  } var person1 = new person ();p erson1.sayname (); ' Zcy ' var person2 = new person ();p erson2.sayname (); ' zcy ' alert (person1.sayname = = Person2.sayname);//true

Whenever a new function is created, a prototype property is created for the function based on a specific set of rules, which points to the prototype object of the Function. By default, all prototype objects automatically get a constructor (constructor) property, which is a pointer to the function where the prototype property is Located. As in the previous example, Person.prototype.constructor points to Person. With this constructor, we can also continue to add additional properties and methods to the prototype Object.

Once a custom constructor has been created, its prototype object will only get the constructor property by default, and the other methods are inherited from Object. When the constructor is called to create a new instance, the inside of the instance contains a pointer (internal property) that points to the Constructor's prototype Object. ECMA-262 the 5th edition of this pointer is called [[Prototype]]. To be clear, this connection exists between the instance and the Constructor's prototype object, rather than between the instance and the Constructor.

 

Each time the code reads a property of an object, the search is performed once, and the target is a property with the given Name. The search begins first from the object instance Itself. If a property with the given name is found in the instance, the property is returned, if it is not found, the prototype object pointed to by the pointer continues to be searched, a property with the given name is found in the prototype object, and the value of the property is returned if the property is located in the prototype Object.

Although the values saved in the prototype can be accessed through an object instance, the values in the prototype cannot be overridden through an object instance. If we add an attribute to the instance with the same name as an attribute in the instance prototype, we create the property in the instance that will mask that property in the Prototype. Adding a property with the same name as the prototype in the instance will only prevent us from accessing that property in the prototype, but it will not modify that Property. Even if this property is set to null, this property is set only in the instance, not its connection to the Prototype. Using the delete operator, however, allows you to completely remove the instance properties, allowing us to revisit the properties in the Prototype.

Use the hasOwnProperty () method to detect whether a property exists in an instance or in a prototype, and this method returns true only if the given property exists in the object instance.

In addition, there are two ways to use the in operator, used separately and in the For-in loop. When used alone, the in operator returns True when the given property is accessible through the object, whether the attribute exists in an instance or in a prototype. So using both the hasOwnProperty () method and the in operator, you can determine whether the attribute is present in the object or in the Prototype.

When you use the for-in loop, you return all the enumerable (enumerated) properties that can be accessed through the object, including the attributes that exist in the instance and the properties that exist in the Prototype. Instance properties that block non-enumerable properties in the prototype (properties that will be marked as false for [[Enumerable]]) are also returned in the for-in loop because, as a rule, all developer-defined properties are enumerable-----except in IE8 and earlier Versions.

There is a bug in the implementation of earlier versions of IE that the instance properties that mask non-enumerable properties do not appear in the for-in loop.

A simpler example of the previous prototype is this

function person () {}person.prototype = {       name: ' zcy ',       age:26,       job: ' software Engineer ',       sayname: function () {            alert (this.name);       }  };

This is different from the previous One: the constructor property no longer points to Person. Because each function is created, its prototype object is created at the same time, and the object automatically obtains the constructor Property. The syntax we use here essentially completely overrides the default prototype object, so the constructor property becomes the constructor property of the new object (pointing to the object Constructor) and no longer points to the person Function. If the value of constructor is really important, you can deliberately set it back to the appropriate value as Follows.

function person () {}person.prototype = {       constructor:person,       name: ' zcy ',       age:26,       job: ' software Engineer ',       sayname:function () {            alert (this.name);       }  };

Note that resetting the constructor property in this way causes its [[Enumerable]] attribute to be set to True. By default, the native constructor property is not Enumerable.

There is a loose connection between the instance and the prototype, and any modifications to the prototype object can be immediately reflected from the instance, even if the prototype was modified before the instance was Created. Because the connection between the instance and the prototype is a pointer, not a copy.

But if you re-write the entire prototype object, the situation will be different. We know that calling a constructor will add a [[Prototype]] pointer to the instance that points to the original prototype, and modifying the prototype to another object is tantamount to cutting off the connection between the constructor and the original prototype, and keep in mind that the pointer in the instance points only to the prototype, not to the Constructor.

function person () {}var friend = new person (); Person.prototype = {       name: ' zcy ',       age:26,       job: ' software Engineer ',       sayname:function () {            Alert (this.name);       }  }; Friend.sayname ();  Error

In this example, we first created an instance of person and then rewritten its prototype object, and then an error occurred when calling Friend.sayname () because the prototype that the friend pointed to did not contain the attribute named in that Name.

Before overriding a prototype object

After overriding the prototype object

It can be seen that the rewrite prototype object cuts off the connection between the existing prototype and any previously existing object instances, and they still refer to the original Prototype.

Prototyping mode is also not without drawbacks. first, it omits the process of passing initialization parameters to the constructor, resulting in all instances getting the same property value by Default. While this will somehow bring some inconvenience, it's not the biggest problem with Prototypes. The biggest problem with prototype patterns is the nature of their sharing.

  all the properties in the prototype are shared by many instances, which is appropriate for the function, and for those attributes that contain the base value, the past, after all, by adding the same name property on the instance to hide the corresponding attribute in the Prototype. however, for attributes that contain reference types, the problem is more Prominent. the following example.

function person () {}person.prototype = {       constructor:person,       name: ' zcy ',       age:26,       job: ' software Engineer ',       friends:{' Shelby ', ' Court '},       sayname:function () {            alert (this.name);       }  }; var person1 = new Person (), var person2 = new person ();p erson1.friends.push (' Van '); alert (person1.friends)  ; "shelby,court,van" Alert (person2.friends);  "shelby,court,van" alert (person1.friends = = person2.friends);  True

As can be seen, reference type modifications in the prototype are reflected on all Instances. If our intention is to share an array in all instances like this, then this result is Fine. however, The example is generally to have all of their own properties, and this problem is that we rarely see someone to use the prototype model alone for the Reason. (the reference type in the modified prototype here differs from the base Type property assignment in the example given in the instance to the original in the prototype, where assigning a value to a base type property in an instance only masks the same name attribute in the prototype, and does not modify the value of the property with the same name in the prototype).

4. Combination of constructor mode and prototype mode

The most common way to create a custom type is to combine the constructor pattern with the prototype Pattern. The constructor pattern is used to define instance properties, and the prototype schema is used to define methods and shared Properties. As a result, each instance has its own copy of the instance properties, but at the same time it shares a reference to the method, saving memory to a minimum. In addition, this blending mode supports passing parameters to the constructor, which is the length of the two Modes. The following Example.

function Person (name,age,job) {       this.name = name;       This.age = age;       This.job = job;       This.friends = {' Shelby ', ' Court '};} Person.prototype = {       constructor:person,       sayname:function () {            alert (this.name);       }  }; var person1 = new person (' zcy ', +, ' software Engineer '), var person2 = new person (' bb ', ' Doctor ');p erson1.friends.push ( ' Van ');

Alert (person1.friends);  "shelby,court,van" Alert (person2.friends);  "shelby,court" alert (person1.friends = = person2.friends);  False
Alert (person1.sayname = = person2.sayname);  True

This compositing pattern is the most widely used and most recognized method of creating custom types in Ecmascript. It can be said that this is a default pattern for defining reference Types.

5. Dynamic Prototype Mode

Developers with other OO language experiences are likely to be very confused when they see independent constructors and Prototypes. Dynamic prototyping is a solution to this problem by encapsulating all the information in the constructor, and by initializing the prototype in the constructor (only if necessary), while preserving the advantages of using both constructors and Prototypes. In other words, you can determine whether a prototype needs to be initialized by checking that a method that should exist is VALID. Take a look at an example.

function Person (name,age,job) {       //attribute       this.name = name;       This.age = age;       This.job = job;              //method       if (typeof this.sayname! = "function") {               Person.prototype.sayName = function () {                            alert (this.name) ;               };       }} var friend= new person (' zcy ', +, ' software Engineer '); friend.sayname ();   

The bold part of the constructor code that is added to the prototype only if the Sayname () method does not Exist. This code will only be executed when the constructor is first Called. And the modifications made to the prototype here are immediately reflected in all Instances. Where the If statement checks for any properties or methods that should exist after initialization, you do not have to examine each property and each method with a large heap of if statements, and check only one of Them.

When using dynamic prototype mode, You cannot rewrite the prototype with object literals, because if you rewrite the prototype with the instance already created, the connection between the existing instance and the new prototype is Severed.

6. Parasitic structural function mode

It is common to use the parasitic (parasitic) constructor pattern in cases where none of the above-mentioned centralized modes are APPLICABLE. The basic idea of this pattern is to create a function that encapsulates the code that creates the object and then returns the newly created object, which, on the surface, looks like a typical Constructor. The following Example.

function Person (name, age, Job) {      var o=new Object ();      O.name = name;      O.age = age;      O.job = job;      O.sayname = function () {            alert (this.name);      };      return o;}  var friend = new person (' zcy ', +, ' software Engineer '); friend.sayname (); "zcy"

In addition to using the new operator and using the wrapper function called the constructor, this pattern is exactly the same as the factory Pattern. The constructor returns the new object instance by default, without returning a worthy case. instead, you can override the value that is returned when the constructor is called by adding a return statement at the end of the constructor Function.

This pattern can be used to create constructors for objects in special Cases. Suppose we want to create a special array with extra METHODS. This pattern can be used because the array constructor cannot be modified Directly.

function Specialarray () {    //create array    var values = new Array ();         Add Value    values.push.apply (values,arguments);    Add method     values.topipedstring = function () {            return this.join ("|");    };    Returns the array return    values;} var colors = new Specialarray ("red", "blue", "green"), alert (colors.topipedstring ()); "red|blue|green"

  With regard to the parasitic constructor pattern, it is important to note that the object returned first is not related to the constructor or to the stereotype property of the constructor, that is, the object returned by the constructor is no different from the object created outside the Constructor. To do this, you cannot rely on the instanceof operator to determine the object Type.

7. Secure Structural function mode

A secure object (durable Objects) refers to an object that has no public properties and whose methods do not refer to This. Secure objects are best suited for use in some secure environments where this and new are prohibited, or when data is being altered by other applications, such as mashup programs. The secure constructor follows a pattern similar to the parasitic constructor, but has a difference of two points: one is that the instance method of the newly created object does not refer to this, and the second is that the new operator is not used to call the Constructor. The following Example.

function person (name,age,job) {    //create object to return    var o = new Object ();         Private variables and functions can be defined here    //add methods     o.sayname = function () {           alert (name);    };    Return the object return    o;} var friend = person ("zcybb", "software Engineer"); friend.sayname (); "zcybb"

In the object created by this pattern, the variable friend holds a secure object, and in addition to using the Sayname () method, there is no other way to access the value of Name. Even if other code adds methods or data members to the object, there is no way to access the raw data passed into the Constructor.

Similar to the parasitic constructor pattern, objects created with the secure constructor pattern have little to do with constructors, so the instanceof operator does not make sense for such objects.

Several patterns of JavaScript creation objects

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.