Chapter 6 Object-Oriented Programming JavaScript Advanced Programming

Source: Internet
Author: User
Tags hasownproperty

The ECMA-262 defines the object:A set of unordered attributes, which can contain basic values, objects, or functions.

An object is a group of values with no specific sequence. Each property or method of an object has a name, and each name is mapped to a value.

Object: Hash list (a group of name-value pairs, where values can be data or functions)

Each object is created based on a reference type.

6.1 create an object

Create an object instance and add attributes and methods to it:

6_1_my.html

<script>var person = new Object();person.name = "Nicholas";person.age = 29;person.job = "Software Engineer";person.sayName = function(){console.log(this.name);}person.sayName();</script>

Running result:

Nicholas

Disadvantage: using the same interface to create many objects will produce a lot of repeated code.

6.1.1 factory mode (the same as the parasitic constructor mode and the robust constructor mode)

The factory mode abstracts the process of creating a specific object.

<script>function createPerson(name,age,job){var o = new Object();o.name = name;o.age = age;o.job = job;o.sayName = function(){console.log(this.name);};return o;}var person1 = createPerson("Nicholas",29,"Software Engineer");var person2 = createPerson("Greg",27,"Doctor");person1.sayName(); //Nicholasperson2.sayName(); //"Greg"</script>

Running result:

NicholasGreg

Although the factory mode solves the problem of creating multiple similar objects, it does not solve the problem of Object Recognition (that is, how to know the type of an object)

6.1.2 constructor Mode

The constructor in ecmascript can be used to create specific types of objects. Native constructor such as object and array will automatically appear in the execution environment at runtime.

<SCRIPT> function person (name, age, job) {This. name = Name; this. age = age; this. job = job; this. sayname = function () {console. log (this. name) ;};}var person1 = new person ("Nicolas", 29, "software engineer"); var person2 = new person ("Greg", 27, "Doctor"); person1.sayname (); // "Nicklas" person2.sayname (); // "Greg" // The constructor attribute of the object was originally used to identify the object type. However, the instanceof operator must be more reliable when detecting object types. log (person1.constructor = person); // trueconsole. log (person2.constructor = person); // trueconsole. log (person1 instanceof object); // trueconsole. log (person1 instanceof person); // trueconsole. log (person2 instanceof object); // trueconsole. log (person2 instanceof person); // true </SCRIPT>

Features:

  • The object is not displayed;
  • Attributes and methods are directly assigned to this object;
  • No return statement.

Constructors should always start with an upper-case letter, while non-constructors should start with a lower-case letter.

To create an object by calling the constructor, follow these steps:

  • Create a new object;
  • Assign the scope of the constructor to the object (so this points to this new object );
  • Execute the code in the constructor (add attributes for the new object );
  • Returned object.

Creating a custom constructor means that its instance can be identified as a specific type in the future.

The constructor defined in this way is defined in the Global Object (window object in the browser. Therefore, unless otherwise stated, the instanceof operator and the constructor attribute always assume that the constructor is queried globally.

1. Use constructor as a function

The only difference between constructors and other functions is that they are called differently. Constructor is also a function, and there is no special syntax for defining constructor. Any function can be called through the new operator as a constructor. If any function is called without the new operator, it is no different from a common function.

<SCRIPT> function person (name, age, job) {This. name = Name; this. age = age; this. job = job; this. sayname = function () {console. log (this. name) ;}}// use VaR person = new person ("Nicolas", 29, "software engineer"); person as a constructor. sayname (); // "Nicolas" // call person ("Greg", 27, "doctor") as a common function; // Add to windowwindow. sayname (); // "Greg" // call var o = new object (); person. call (O, "Kristen", 25, "nurse"); O. sayname (); // "Kristen" </SCRIPT>

When a function is called in the global scope, this object always points to the Global Object (window object in the browser)

2. constructor Problems

The main problem with using constructors is that each method must be re-created on each instance.

In the previous example, person1 and person2 both have a method named sayname (), but the two methods are not instances of the same function. The functions in ecmascript are objects. Therefore, each function is defined, that is, an object is instantiated.

<SCRIPT> function person (name, age, job) {This. name = Name; this. age = age; this. job = job; this. sayname = new function ("console. log (this. name) "); // logically equivalent to the declarative function} var person1 = new person (" nicklar ", 29," software engineer "); vaR person2 = new person ("Greg", 27, "doctor"); console. log (person1.sayname = person2.sayname); // false </SCRIPT>

Creating two function instances for the same task is indeed unnecessary. Besides, this object does not need to bind the function to a specific object before executing the code. Therefore, this problem is solved by moving the function definition to the external part of the constructor:

<script>function Person(name,age,job){this.name = name;this.age = age;this.job = job;this.sayName = sayName;}function sayName(){console.log(this.name);}var person1 = new Person("Nicholar",29,"Software Engineer");var person2 = new Person("Greg",27,"Doctor");person1.sayName(); //"Nicholas"person2.sayName(); //"Greg"console.log(person1 instanceof Object); //trueconsole.log(person1 instanceof Person); //trueconsole.log(person2 instanceof Object); //trueconsole.log(person2 instanceof Person); //trueconsole.log(person1.constructor == Person); //trueconsole.log(person2.constructor == Person); //trueconsole.log(person1.sayName == person2.sayName);true</script>

New problem: the function defined in the global scope can only be called by an object, which makes the global scope a bit out of name. What is even more unacceptable is that if an object needs to define many methods, many global functions must be defined. Therefore, the custom reference type has no encapsulation.

6.1.3 prototype mode

Each function has a prototype attribute. This attribute is an object and its purpose is to include attributes and methods that can be shared by all instances of a specific type. If you understand it by character, prototype is the prototype of the object created by calling the constructor. The advantage of using a prototype is that all object instances can share its attributes and methods. In other words, the object information does not need to be defined in the constructor, but can be directly added to the prototype object.

<script>function Person(){}Person.prototype.name = "Nicholas";Person.prototype.age = 29;Person.prototype.job = "Software Engineer";Person.prototype.sayName = function(){console.log(this.name);};var person1 = new Person();person1.sayName(); //"Nicholas"var person2 = new Person();person2.sayName(); //"Nicholas"console.log(person1.sayName == person2.sayName); //true</script>
1. Understand prototype

Whenever a new function is created, a prototype attribute is created for the function based on a specific set of rules. By default, all prototype attributes will automatically obtain a constructor (constructor) attribute, which contains a pointer to the function of the prototype attribute.

After a custom constructor is created, only the constructor attribute is obtained by default. Other methods are inherited from objects. After a constructor is called to create a new instance, the instance contains a pointer (internal attribute) pointing to the constructor's prototype attribute. In many implementations, the internal attribute name is _ PROTO __and can be accessed through scripts (in Firefox, Safari, chrome, and Flash, you can use scripts to access _ PROTO _). In other implementations, this attribute is completely invisible to the script. However, it should be clear that the connection exists between the prototype attribute of the instance and the constructor, rather than between the instance and the constructor.

Although the internal _ PROTO _ attribute cannot be accessed in some implementations, The isprototypeof () method can be used in all implementations to determine whether this relationship exists between objects. Essentially, if the object _ PROTO _ points to the object (person. Prototype) that calls the isprototypeof () method, this method returns true.

<script>function Person(){}Person.prototype.name = "Nicholas";Person.prototype.age = 29;Person.prototype.job = "Software Engineer";Person.prototype.sayName = function(){console.log(this.name);};var person1 = new Person();var person2 = new Person();console.log(Person.prototype.isPrototypeOf(person1));//trueconsole.log(Person.prototype.isPrototypeOf(person2));//true</script>

Here, we tested person1 and person2 using the isprototypeof () method of the prototype object. Because they all have a pointer to person. prototype, true is returned.

Each time the Code reads an attribute of an object, a search is executed, and the target is an attribute with a given name. Search starts with the object instance itself. If a property with a given name is found in the instance, the value of the property is returned. If no property is found, the search continues for the prototype object pointed to by the pointer, search for attributes with a given name in the prototype object. If this attribute is found in the prototype object, the value of this attribute is returned. This is the basic principle of attributes and methods stored by Multiple object instances sharing prototype.

The prototype initially only contains the constructor attribute, which is also shared and can be accessed through an object instance.

Although the values stored in the prototype can be accessed through the object instance, the values in the prototype cannot be overwritten through the object instance.. If we add an attribute to the instance and it has the same name as an attribute in the instance prototype, we create this attribute in the instance, this property will shield the property in the prototype.

<SCRIPT> function person () {} person. prototype. name = "Nicolas"; person. prototype. age = 29; person. prototype. job = "software engineer"; person. prototype. sayname = function () {console. log (this. name) ;}; var person1 = new person (); var person2 = new person (); person1.name = "Greg"; console. log (person1.name); // "Greg" --- from the instance console. log (person2.name); // "Nicolas" ---- from prototype </SCRIPT>

When an attribute is added to an object instance, this attribute shields the attributes of the same name stored in the prototype object. In other words, adding this attribute will only prevent us from accessing the attribute in the prototype, but the attribute will not be modified. Even if this attribute is set to null, only this attribute is set in the instance, and the connection to the prototype is not restored. However, you can use the delete operator to completely delete instance attributes so that we can re-access attributes in the prototype.

<SCRIPT> function person () {} person. prototype. name = "Nicolas"; person. prototype. age = 29; person. prototype. job = "software engineer"; person. prototype. sayname = function () {console. log (this. name) ;}; var person1 = new person (); var person2 = new person (); person1.name = "Greg"; console. log (person1.name); // "Greg" --- from the instance console. log (person2.name); // "Nicolas" ---- From the prototype Delete person1.name; console. log (person1.name); // "Nicolas" ---- from prototype </SCRIPT>

The hasownproperty () method can be used to check whether an attribute exists in the instance or in the prototype. This method (inherited from the object) returns true only when the specified property exists in the object instance.

<SCRIPT> function person () {} person. prototype. name = "Nicolas"; person. prototype. age = 29; person. prototype. job = "software engineer"; person. prototype. sayname = function () {console. log (this. name) ;}; var person1 = new person (); var person2 = new person (); console. log (person1.hasownproperty ("name"); // falseperson1.name = "Greg"; console. log (person1.name); // "Greg" ------ From the instance console. log (person1.hasownproperty ("name"); // trueconsole. log (person2.name); // "Nicolas" ---- From the prototype console. log (person2.hasownproperty ("name"); // falsedelete person1.name; console. log (person1.name); // "Nicolas" ---- From the prototype console. log (person1.hasownproperty ("name"); // falsea </SCRIPT>

Shows the link:

2. Prototype And in Operator

There are two ways to use the in OPERATOR: separate use and use in the for-in loop. When used independently, the in operator returns true when a given attribute can be accessed through an object, regardless of whether the attribute exists in the instance or in the prototype.

<SCRIPT> function person () {} person. prototype. name = "Nicolas"; person. prototype. age = 29; person. prototype. job = "software engineer"; person. prototype. sayname = function () {console. log (this. name) ;}; var person1 = new person (); var person2 = new person (); console. log (person1.hasownproperty ("name"); // falseconsole. log ("name" in person1); // trueperson1.name = "Greg"; console. log (person1.name); // "Greg" ------ From the instance console. log (person1.hasownproperty ("name"); // trueconsole. log ("name" in person1); // trueconsole. log (person2.name); // "Nicolas" ---- From the prototype console. log (person2.hasownproperty ("name"); // falseconsole. log ("name" in person2); // truedelete person1.name; console. log (person1.name); // "Nicolas" ---- From the prototype console. log (person1.hasownproperty ("name"); // falseaconsole. log ("name" in person1); // true </SCRIPT>

By using the hasownproperty () method and the in operator, you can determine whether the property exists in the object or in the prototype.

<script>function hasPrototypeProperty(object,name){return !object.hasOwnProperty(name) && (name in object)}function Person(){}Person.prototype.name = "Nicholas";Person.prototype.age = 29;Person.prototype.job = "Software Engineer";Person.prototype.sayName = function(){console.log(this.name);};var person = new Person();console.log(hasPrototypeProperty(person,"name"));person.name = "Greg";console.log(hasPrototypeProperty(person,"name"));</script>

When a for-in loop is used, all enumerated attributes that can be accessed through objects are returned, including attributes that exist in instances, it also includes attributes that exist in the prototype.The instance attribute (that is, the overwritten attribute) of the non-enumerated attribute (that is, the attribute marked by [[dontenum]) in the prototype is blocked)It will also be returned in the for-in loop, because according to the regulations, all the attributes defined by developers are enumerable-only with the exception of IE.

There is a bug in the JScript Implementation of IE, that is, the instance attributes that cannot be enumerated will not appear in the for-in loop.

<SCRIPT> var o = {tostring: function () {return "My object" ;}}for (VAR prop in O) {If (prop = "tostring ") {// comment out if, only once alert ("found tostring"); // It is not displayed in IE (ie9 has been fixed) }</SCRIPT>

3. Simpler prototype syntax

<script>function Person(){}Person.prototype = {name = "Nicholas";age = 29;job = "Software Engineer";sayName = function(){console.log(this.name);}}</script>

In the above Code, we set person. prototype to be equal to a new object created in the form of an object literally. The final result is the same, but there is an exception: the constructor attribute no longer points to the person. Each time a function is created, its prototype object will be created at the same time, and this object will automatically obtain the cosntructor attribute. The syntax we use here completely overwrites the default prototype object. Therefore, the constructor attribute becomes the constructor attribute of the new object (pointing to the object constructor) and does not point to the person function. At this time, although the instanceof operator can return the correct results, the constructor can no longer determine the object type.

<script>function Person(){}Person.prototype = {name : "Nicholas",age : 29,job : "Software Engineer",sayName : function(){console.log(this.name);}}var person = new Person();console.log(person instanceof Object); //trueconsole.log(person instanceof Person); //trueconsole.log(person.constructor == Person); //falseconsole.log(person.constructor == Object); //true</script>

Corrected the constructor's point:

<script>function Person(){}Person.prototype = { constructor : Person,name : "Nicholas",age : 29,job : "Software Engineer",sayName : function(){console.log(this.name);}}var person = new Person();console.log(person instanceof Object); //trueconsole.log(person instanceof Person); //trueconsole.log(person.constructor == Person); //falseconsole.log(person.constructor == Object); //true</script>

4. Dynamic Prototype

Because the process of searching values in the prototype is a search, therefore, any modifications we make to the prototype object can be immediately reflected from the instance-either by creating the instance first and then modifying the prototype.

<SCRIPT> function person () {} person. prototype = {constructor: person, name: "Nicolas", age: 29, job: "software engineer", sayname: function () {console. log (this. name) ;}} var person = new person (); person. prototype. sayhi = function () {console. log ("hi");} person. sayhi (); // "hi" (No problem !) </SCRIPT>

The reason is the loose connection between the instance and the prototype. When we call person. sayhi (), we first search for the property named sayhi In the instance. If the property is not found, we will continue searching for the prototype. Because the connection between the instance and the prototype is only a pointer rather than a copy, you can find the new sayhi attribute in the prototype and return the function stored there.

Although attributes and methods can be added to the prototype at any time, and modifications can be immediately displayed in all object instances, if the entire prototype object is rewritten, the situation is different. We know that when calling the constructor, A _ PROTO _ pointer pointing to the original prototype will be added to the instance, changing the prototype to another object will cut off the relationship between the constructor and the original prototype. Remember:The pointer in the instance only points to the prototype, not the constructor.

<script>function Person(){}var person = new Person();Person.prototype = { constructor : Person,name : "Nicholas",age : 29,job : "Software Engineer",sayName : function(){console.log(this.name);}}person.sayHi();//error</script>

:

5. prototype of the native object

The importance of the prototype mode is not only reflected in the creation of custom types, but also all native reference types are created in this mode. All native types (object, array, string, and so on) define methods on the prototype of their constructor.

<script>alert(typeof Array.prototype.sort); //"function"alert(typeof String.prototype.substring); //"function"</script>

The prototype of the native object not only obtains reference of all default methods, but also defines new methods. You can modify the prototype of a native object just like the prototype of a custom object, so you can add methods at any time.

<script>String.prototype.startsWith = function(text){return this.indexOf(text) == 0;}var msg = "Hello world!";console.log(msg.startsWith("Hello")); //true</script>

6. Problems with prototype objects

It skips the process of passing initialization parameters for the constructor. As a result, all instances obtain the same attribute value by default. The biggest problem with a prototype model is its shared nature.

<script>function Person(){}Person.prototype = { constructor : Person,name : "Nicholas",age : 29,job : "Software Engineer",friends : ["Shelby","Court"],sayName : function(){console.log(this.name);}}var person1 = new Person();var person2 = new Person();person1.friends.push("Van");console.log(person1.friends); //"Shelby,Court,Van"console.log(person2.friends); //"Shelby,Court,Van"console.log(person1.friends == person2.friends); //true</script>
6.1.4 use the constructor mode and prototype mode in combination.

The constructor mode is used to define instance attributes, while the prototype mode is used to define methods and shared attributes. As a result, each instance has its own copy of the Instance attribute, but it also shares the reference to the method, saving the memory to the maximum extent. In addition, this mixed mode also supports passing parameters to the constructor.

<script>function Person(name,age,job){this.name = name;this.age = age;this.job = job;this.friends = ["Shelby","Court"];}Person.prototype ={constructor : Person,sayName : function(){console.log(this.name);}}var person1 = new Person("Nicholas",29,"Software Engineer");var person2 = new Person("Greg",29,"Doctor");person1.friends.push("Van");console.log(person1.friends); //"Shelby,Count,Van"console.log(person2.friends); //"Shelby,Count"console.log(person1.friends === person2.friends); //falseconsole.log(person1.sayName === person2.sayName); //true</script>
6.1.5 Dynamic Prototype

The dynamic prototype mode encapsulates all information in the constructor, and initializes the prototype in the constructor (only if necessary ), it also maintains the features of using constructor and prototype at the same time. In other words, you can determine whether to initialize the prototype by checking whether a method that should exist is valid.

<SCRIPT> 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 () {console. log (this. name) ;}}}var person = new person ("Nicolas", 29, "software engineer"); person. sayname (); </SCRIPT>

The IF statement checks any attributes or methods that should exist after initialization. You do not need to use a large number of IF Statements to check each attribute and each method. You only need to check one of them.

When using the dynamic prototype mode, you cannot use the object literal to override the prototype. If the prototype is rewritten when an instance has been created, the connection between the existing instance and the new original type is cut off.

6.1.6 parasitic constructor mode (same as the factory Mode)

The basic idea of this mode is to create a function. The function is only used to encapsulate the code for creating an object and then return the newly created object. But on the surface, this function looks like a typical constructor.

<script>function Person(name,age,job){var o = new Object();o.name = name;o.age = age;o.jbo = job;o.sayName = function(){console.log(this.name);};return o;}var person = new Person("Nicholas",29,"Software Engineer");person.sayName(); //"Nicholas"</script>

If no value is returned, the constructor returns a new object instance by default. By adding a return statement at the end of the constructor, You can override the value returned when calling the constructor.

Suppose we want to create a special array with additional methods. Because you cannot directly modify the array constructor, you can use this mode:

<SCRIPT> function specialarray () {// create an array VaR values = new array (); // Add the value values. push. apply (values, arguments); // Add the values method. topipedstring = function () {return this. join ("|") ;}; // return array return values;} var colors = new specialarray ("red", "blue", "green"); console. log (colors. topipedstring (); // "Red | Blue | green" </SCRIPT>

First, there is no relationship between the returned object and the constructor or the prototype attribute of the constructor. That is, the object returned by the constructor is no different from the object created outside the constructor. Therefore, the instanceof operator cannot be used to determine the object type.

6.17 safe constructor mode (same as the factory Mode)

Secure object: there is no public attribute, and its method does not reference this object. Secure objects are best suited to some secure environments (this and new are not allowed in these environments), or to prevent data from being changed by other applications (such as mashup programs.

The safe constructor follows a pattern similar to the parasitic constructor, but there are two differences: first, the instance method of the newly created object does not reference this; second, the constructor is not called using the new operator.

<SCRIPT> function person (name, age, job) {// create the object var o = new object () to be returned; // Private face changing and function this can be defined here. name = Name; this. age = age; this. jbo = job; // Add method o. sayname = function () {console. log (name) ;}; // return object return O;} var person = person ("Nicolas", 29, "software engineer"); person. sayname (); // "Nicolas" '</SCRIPT>

Similar to the parasitic constructor mode, the objects created in the safe constructor mode have no relationship with the constructor. Therefore, the instanceof operator has no significance for this object.

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.