Comprehensive understanding of object-oriented JavaScript

Source: Internet
Author: User

Objective

Today's JavaScript is a great way to rely on a wide range of applications. Web programmers have become accustomed to using a variety of excellent JavaScript frameworks to quickly develop WEB applications, ignoring the learning and deep understanding of native JavaScript. So, often the case is that many of the programmers who have done it for many years are always unclear about closures, functional programming, and prototypes, even if the framework is used, and the code is poorly organized. This is an expression of insufficient understanding of native JavaScript language features. To master JavaScript, the first thing is to discard some other high-level languages such as Java, C # and other classes of object-oriented thinking of the interference, a comprehensive view of the functional language from the perspective of JavaScript prototype object-oriented features. With this in mind, it is possible to use the language better. This article is suitable for groups: programmers who have used the JS framework but do not understand the nature of JS language, have Java, C + + and other language development experience, ready to learn and use JavaScript programmer, and always to JavaScript is object-oriented ambiguous, but want to know the truth of JS enthusiasts 。

Re-understanding Object-oriented

To illustrate that JavaScript is a thoroughly object-oriented language, it is necessary to start with object-oriented concepts and explore some of the concepts in object-oriented:

    • All things Are object
    • object has encapsulation and inheritance attributes
    • Use message communication between objects and objects, each with information hiding

Based on these three points, C + + is a semi-object-oriented semi-oriented process language because, although he implements encapsulation, inheritance, and polymorphism of classes, there are global functions and variables of non-object nature. Java, C # is a complete object-oriented language that organizes functions and variables in the form of classes so that they cannot be separated from the object's existence. But here the function itself is a process, just attached to a class.

However, object-oriented is just a concept or a programming idea, and it should not depend on the existence of a language. For example, Java uses object-oriented thinking to construct its language, which implements such mechanisms as class, inheritance, derivation, polymorphism, and interface. But these mechanisms are just a means of implementing object-oriented programming, not a necessity. In other words, a language can choose the right way to implement object-oriented according to its own characteristics. So, because most programmers first learn or use a similar Java, C + + and other advanced compiler language (Java Although semi-compiled semi-interpretation, but generally as a compilation to explain), so the preconceived acceptance of the "class" this object-oriented implementation, in learning the scripting language, It is customary to use the concept of a class-oriented object language to determine whether the language is an object-oriented language or whether it has object-oriented characteristics. This is one of the important reasons that hinder programmers from learning and mastering JavaScript.

In fact, the JavaScript language implements object-oriented programming in a way called prototypes (prototype) . The following is a discussion of class-based (class-based) object -oriented and prototype-based (prototype-based) object-oriented The difference between the two approaches in constructing an objective world.

Class-based object-oriented and prototype-based object-oriented approach comparison

In class-based object-oriented mode, objects (object) are generated by classes (class) . In the prototype-based object-oriented approach, the object is dependent on the constructor (constructor) to exploit The prototype (prototype) is constructed. Give an example of an objective world to illustrate the differences in cognition in two ways. For example, a factory build a car, on the one hand, workers must refer to a drawing, design rules how the car should be manufactured. The engineering drawing here is like the classin the language, and the car is in accordance with this class (class) Manufactured, on the other hand, workers and machines (equivalent to constructor) use various components such as engines, tires, and steering wheels (the equivalent of prototype's various properties) to construct the car.

In fact, there is a debate about who has expressed the object-oriented idea more thoroughly in both ways. But I think the prototype object-oriented is a more thorough object-oriented approach, for the following reasons:

First of all, the object in the objective world is the result of other physical object constructs, and the abstract "drawing" cannot produce "automobile", that is to say, the class is an abstract concept rather than an entity, and the object is produced by an entity;

Second, according to the most basic object-oriented law of all things, the class itself is not an object, but the constructors (constructor) and prototypes (prototype) in the prototype form are themselves objects that other objects have been constructed by way of prototype.

Again, in a class-oriented object language, the state of an object is held by an object instance (instance), and the object's behavior method is held by the class that declares the object, and only the structure and methods of the object can be inherited, whereas in the prototype object-oriented language, the object's behavior, States belong to the object itself, and can be inherited together (reference resources), which is also closer to the objective reality.

Finally, the class-oriented object language, such as Java, allows for the declaration of static and static methods in a class in order to compensate for the inconvenience of using global functions and variables in a procedural language. In fact, the objective world does not exist the so-called static concept, because all things are objects! In the prototype object-oriented language, the existence of global objects, methods or properties is not allowed, and there is no static concept except for the built-in objects (Build-in object). All language elements (primitive) must depend on the existence of an object. However, due to the characteristic of functional language, the object that the language element relies on is changed with the runtime (runtime) context, which is reflected in the change of this pointer. It is this characteristic that is closer to the natural view of "All things belong, the universe is the root of all things". In program Listing 1, window is similar to the concept of the universe.

Listing 1. The context dependency of the object
<script>varstr = "I am a String object, I declare it here, but I am not independent of existence!" "varobj = {des: "I am an object, I declare here, I do not exist independently." " }; varFun =function() {Console.log ("I am a Function Object!" Who calls me, who I belong to: ", This );  }; Obj.fun=Fun ; Console.log ( This= = = window);//Print TrueConsole.log (window.str = = = str);//Print TrueConsole.log (window.obj = = = obj);//Print TrueConsole.log (Window.fun = = = Fun);//Print TrueFun ();//Print I am a Function Object! Who calls me, who I belong to: WindowObj.fun ();//Print I am a Function Object! Who calls me, who I belong to: objFun.apply (str);//Print I am a Function Object! Who calls me, who I belong to: Str</script>

After accepting the fact that object-oriented exists in a way known as prototype-based implementation, we can delve into how ECMAScript constructs its own language in this way.

The most basic object-oriented

ECMAScript is a thorough object-oriented programming language (reference Resource), and JavaScript is a variant (variant). It provides 6 basic data types, Boolean, number, String, Null, Undefined, Object. In order to achieve object-oriented,ECMAScript designed a very successful data structure-JSON (JavaScript Object Notation), this classic structure can be removed from the language and become a widely used data interchange format (Refer to resources).

It should be said that ECMAScript with the basic data types and the JSON construction syntax have basically been able to implement object-oriented programming. Developers can arbitrarily construct an object in a literal declaration (literal notation) , assign a value directly to a property that does not exist, or delete the property with delete (note: The Delete in JS Keywords are used to delete object properties, often mistakenly as delete in C + +, which is used to free objects that are no longer used, such as Listing 2.

Listing 2. Literal (literal notation) object declaration
var person = {     name: "Zhang San",     +,     Gender: "Male",     function(stuff) {         + stuff);     }  };   = 176;   Delete person["age"];

In the actual development process, most beginners or developers who do not have too high requirements for JS application basically only use the ECMAScript definition of this part of the content, can meet the basic development needs. However, such code reusability is very weak, and other implementations of inheritance, derivation, polymorphism, and so on the class-oriented object of the strongly typed language is somewhat withered, can not meet the complex JS application development. So ECMAScript introduced prototypes to solve object inheritance problems.

Constructing an object using the function builder

In addition to the literal declaration (literal-notation) approach, ECMAScript allows objects to be created through the constructor (constructor) . Each constructor is actually a functionobject that contains a "prototype" property for implementing prototype-based inheritance ( prototype-based inheritance) and share properties (Shared property). objects can be created by the "New keyword + constructor call", as in Listing 3:

Listing 3. Creating an object using the constructor (constructor)
 //  The constructor person is itself a function object  function   person () { //  Here you can do some initialization work   " //  It has a property called prototype  person.prototype = {name:" Zhang San ", Age:  26, Gender: "Male", Eat:  function   (stuff) {     Alert ("I'm Eating"  + stuff); }}  //  Constructs an object using the New keyword  var  p = new  person (); 

Since the inventor of the early JavaScript was trying to get the language to relate to the famous Java (although it is now known that the relationship between Lei Feng and Lei Feng Tower), the new keyword was used to qualify the constructor call and create the object so that it can be syntactically created with Java object Look similar in the way. However, it is necessary to point out that the new meaning of the two languages has nothing to do with it, because the mechanism of its object construction is completely different. It is precisely because of the grammatical similarities here, many programmers who are accustomed to the way objects are created in the class-oriented language have difficulty in understanding the way in which JS objects are prototyped, because they always do not understand why "function names can be used as class names" in the JS language. And in essence, JS here just borrowed the keyword new, that's all; in other words, ECMAScript can create an object with the call constructor with other non- new expressions.

Thorough understanding of the prototype chain (prototype chain)

In ECMAScript, each object created by the constructor has an implicit referenceto the constructor prototype property value (implicit reference), which is referred to as the Prototype (prototype). Further, each prototype can have an implicit reference to its own prototype (the prototype of that prototype), and so on, this is called the prototype chain (prototype chain) (Refer to resources). In a specific language implementation, each object has a __proto__ property to implement an implicit reference to the prototype. This is illustrated in Listing 4 of the procedure.

Listing 4. __proto__ properties and implicit references for objects
functionPerson (name) { This. Name =name; }  varp =NewPerson (); //An implicit reference to an object points to the prototype property of the constructor, so printing true hereConsole.log (p.__proto__ = = =Person.prototype); //The prototype itself is an object, so his implicit reference points to the //the prototype property of the Object constructor, and therefore prints trueConsole.log (person.prototype.__proto__ = = =Object.prototype); //The constructor person is itself a function object, so printing true hereConsole.log (person.__proto__ = = = Function.prototype);

With the prototype chain , you can define a so-called property-hiding mechanism and implement inheritance through this mechanism. ECMASCRIPT specifies that when you assign a value to an object's properties, the interpreter finds the first object in the prototype chain that contains the attribute (note: The prototype itself is an object, and the prototype chain is a chain of objects. The first object in the prototype chain of the object is the object itself) to assign the value. Conversely, if you want to get the value of an object property, the interpreter naturally returns the object property value that first has that property in the prototype chain of the object. Figure 1 says that the hidden mechanism is called:

Figure 1. The property hiding mechanism in the prototype chain

In Figure 1, object1->prototype1->prototype2 forms the prototype chain of the object Object1, and according to the above attribute hiding mechanism, it is clear to see the Property4 attribute and Prototy in Prototype1 object. The Property3 property in the Pe2 object is hidden. Understanding the prototype chain, it will be very easy to understand the prototype based on the implementation of the principle of inheritance, listing 5 is a simple example of the use of the prototype chain to implement inheritance.

Listing 5. Using prototype chain Horse->mammal->animal to implement inheritance
//declaring the Animal object constructor functionAnimal () {}//point the Prototype property of Animal to an object, //can also be directly understood as the prototype of the specified Animal objectAnimal.prototype ={name:animal", weight:0, Eat:function () {alert ("Animal is eating!" ); }}//Declare Mammal object constructor function mammal () {this.name ="Mammal"; }//Specifies that the mammal object is prototyped as a Animal object.  This is actually the prototype chain between the creation of the mammal object and the Animal object mammal.prototype = new Animal (); Declares the Horse object constructor function Horse (height, weight) {this.name ="Horse";     This.height = height;  This.weight = weight;  }//Specify the prototype of the Horse object as a Mamal object and continue to build the prototype chain between Horse and mammal Horse.prototype = new mammal (); Re-Specify the Eat method, which overrides the Eat method inherited from the Animal prototype Horse.prototype.eat = function () {alert ("Horse is eating grass!" );  }//Verify and understand the prototype chain var horse = new Horse (100, 300);  Console.log (horse.__proto__ = = = Horse.prototype);  Console.log (horse.prototype.__proto__ = = = Mammal.prototype); Console.log (mammal.prototype.__proto__ = = = Animal.prototype);

The key to understanding the implementation of the object prototype inheritance logic in Listing 5 is the code horse.prototype = new Mammal () and mammal.prototype = new Animal (). First, the result of the right side of the equation is to construct a temporary object and then assign the object to the prototype property of the object on the left of the equation. This means that the newly created object on the right is the prototype of the left object. The reader can replace these two equations with the corresponding program listing 5 code in the last two lines of the equation to self-comprehend.

Implementation of JavaScript-class inheritance

As can be seen from code Listing 5, based on the inheritance of the prototype, although the implementation of code reuse, but its text is loosely and not fluent, poor readability, not conducive to the implementation of the extension and the source code to effectively organize management. It has to be admitted that class-style inheritance is more robust in language implementations and has a distinct advantage in building reusable code and organizational architecture programs. This makes it possible for programmers to find a way to encode in a class-like inheritance style in JavaScript. From an abstract point of view, since both class-based and prototype inheritance are designed to implement object-oriented, and their respective implementation of the carrier language is equivalent to the computational power (since the computational power of Turing is equivalent to the computational power of Lambda calculus), then can you find a transformation, So that the prototype inherits the language through this transformation implementation has the class inheritance coding style?

At present, some mainstream JS frameworks provide this transformation mechanism, that is, the class declaration method, such as Dojo.declare (), Ext.entend () and so on. Using these frameworks, users can organize their own JS code in an easy and friendly manner. In fact, before the advent of many frameworks, JavaScript master Douglas Crockford first used three functions to extend the function object, the implementation of this transformation, about its implementation details can (reference resources). There is also a well-known base.js (reference Resource) implemented by Dean Edwards . It is worth mentioning that the father of JQuery, John resig , after the long time of the family, in less than 30 lines of code to achieve their own simple inheritance. Declaring a class with the Extend method it provides is straightforward. Listing 6 is an example of a declaration using the simple Inheritance Library implementation class. The final statement of the printout is the best description of simple inheritance implementation of class inheritance.

Listing 6. Using simple inheritance to implement class-like inheritance
//declaring the person class varperson =class.extend ({_issleeping:true, Init:function(name) { This. _name =name; }, Issleeping:function() {         return  This. _issleeping;  }  } ); //declare the Programmer class and inherit the person varProgrammer =person.extend ({init:function(name, issleeping) {//calling the parent class constructor         This. _super (name); //set your own State         This. _issleeping =issleeping;  }  } ); varperson =NewPerson ("Zhang San" ); varDiors =NewProgrammer ("Zhangjiang male",false ); //Print TrueConsole.log (person.issleeping ()); //Print FalseConsole.log (diors.issleeping ()); //true here, so print trueConsole.log (personinstanceofPerson && PersoninstanceofClass&& DiorsinstanceofProgrammer &&diorsinstanceofPerson && diorsinstanceofClass);

If you have a good understanding of prototypes, function constructors, closures, and context-based this, it is not very difficult to understand how simple inheritance is implemented. In essence,var person = class.extend (...) In this statement, the person on the left actually obtains a constructor that is returned by the Class call extend method, which is also a reference to a function object. Along this line of thought, we continue to introduce how simple inheritance can do this, and then realize the transformation from the prototype inheritance mode to the class-type inheritance mode. Figure 2 is the source of simple inheritance and its accompanying annotations. In order to facilitate understanding, the code is supplemented by line in Chinese.

Figure 2.Simple Inheritance Source parsing

Throw out the second part of the code, the first and third chapters are examined in a coherent way. The fundamental purpose of the Extend function is to construct a new constructor with a new prototype property. We cannot help but lament John resig 's master handwriting and his grasp of the nature of the JS language delicate degree. As for how John Resig to think of such a subtle approach to implementation, interested readers can read this article (reference resources), which has a detailed introduction to the original design simple inheritance thinking process.

JavaScript Private Member implementation

So far, if you're still skeptical about JavaScript object-oriented, then this suspicion must be that JavaScript does not implement object-oriented information hiding, private and public. Unlike other classes of object-oriented objects that explicitly declare private public members, the information hiding of JavaScript is implemented by closures. See Program Listing 7:

Listing 7. Using closures for information hiding
 //declaring the User constructor functionUser (pwd) {//Defining private Properties    varPassword =pwd; //Defining Private Methods    functionGetPassword () {//returns the password in the closure        returnpassword; }     //privileged function declaration, which is used by other public methods of the object to access private members through this privileged method     This. Passwordservice =function() {         returnGetPassword (); }  }  //Public member DeclarationUser.prototype.checkPassword =function(pwd) {return  This. Passwordservice () = = =pwd;  }; //verifying the hidden nature varU =NewUser ("123456" ); //Print TrueConsole.log (U.checkpassword ("123456" ) ); //Print undefinedConsole.log (U.password); //Print TrueConsole.log (typeofU.gepassword = = = "undefined");

JavaScript must rely on closures to implement information hiding, as determined by its functional language characteristics. This article does not discuss the two topics of functional language and closures, as you will see by default in JavaScript, as described in context-based this. For information hiding in JavaScript,Douglas Crockford has more authoritative and detailed descriptions in the article Private members in JavaScript (reference resources).

Comprehensive understanding of object-oriented JavaScript

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.