In-depth understanding of the JavaScript series (5): Powerful prototypes and prototype chains

Source: Internet
Author: User
Tags hasownproperty

preface JavaScript does not contain the traditional class inheritance model, but rather uses the Prototypal prototype model. Although this is often referred to as a disadvantage of JavaScript, the prototype-based inheritance model is more powerful than traditional class inheritance. Implementing the traditional class inheritance model is simple, but it is much more difficult to implement the prototype inheritance in JavaScript. Since JavaScript is the only widely used prototype-based language, it takes some time to understand the differences between the two inheritance patterns, and today we'll look at prototypes and prototype chains. Prototype 10 years ago, when I first learned JavaScript, I used to write code in the following ways:varDecimaldigits = 2, tax= 5; functionAdd (x, y) {returnX +y; }        functionsubtract (x, y) {returnX-y; }        //Alert (Add (1, 3));by executing the various function to get the result, after learning the prototype, we can use the following ways to beautify the code. Prototype Usage 1: Before using the prototype, we need to make a small change to the code:varCalculator =function(decimaldigits, tax) { This. decimaldigits =decimaldigits;  This. Tax =Tax ;        Then, the prototype of the Calculator object is set by assigning a value object literal to the prototype property of the Calculator object. Calculator.prototype={add:function(x, y) {returnX +y; }, Subtract:function(x, y) {returnX-y;        }        }; //Alert ((New Calculator ()). Add (1, 3));in this way, we can call the Add method to evaluate the result after the new Calculator object. Prototype Usage 2: The second way is to assign a value using the expression immediately executed by the function in the prototype of the value of the prototype, that is, the following format: Calculator.prototype=function() {} (); its benefits are already known in the previous post, which is the ability to encapsulate private function, exposing a simple use name in return form to public/private effect, the modified code is as follows:Calculator.prototype=function() {Add=function(x, y) {returnX +y; }, Subtract=function(x, y) {returnX-y; }            return{add:add, subtract:subtract}}        (); //Alert ((New Calculator ()). Add (one, 3));in the same way, we can call the Add method after the new Calculator object to calculate the result. One more step: the use of prototypes, there is a limitation is a one-time setting of the prototype object, let's say how to set the prototype of each property bar. varBasecalculator =function () {    //declare a decimal number for each instance     This. decimaldigits = 2;}; //using prototypes to extend 2 object methods to a BasecalculatorBaseCalculator.prototype.add =function(x, y) {returnX +y;}; BaseCalculator.prototype.subtract=function(x, y) {returnX-y;}; First, a Basecalculator object is declared, the constructor initializes the attribute decimaldigits of a decimal place, and then sets the 2 functions by the prototype attribute, which are add (x, y) and subtract (x, y), respectively. Of course you can also use any of the 2 ways mentioned earlier, our main purpose is to see how to set the Basecalculator object to the real calculator prototype. varBasecalculator =function() {     This. decimaldigits = 2;}; Basecalculator.prototype={add:function(x, y) {returnX +y; }, Subtract:function(x, y) {returnX-y; }}; Once you've created the above code, let's start:varCalculator =function () {    //declare a tax number for each instance     This. Tax = 5;}; Calculator.prototype=NewBasecalculator (); we can see that calculator's prototype is pointing to an instance of Basecalculator, with the goal of allowing calculator to integrate its add (x, y) and subtract (x, y) The 2 function, and one thing to say, is that since its prototype is an instance of Basecalculator, no matter how many Calculator object instances you create, their prototypes point to the same instance. varCalc =NewCalculator (); Alert (Calc.add (1, 1));//The decimaldigits attribute declared in the Basecalculator is accessible in calculatoralert (calc.decimaldigits); The above code, after running, we can see that because Calculator's prototype is on an instance of Basecalculator, the value of his Decimaldigits property can be accessed, What if I don't want calculator to access the property values declared in Basecalculator's constructor? This:varCalculator =function () {     This. tax= 5;}; Calculator.prototype=basecalculator.prototype: By assigning Basecalculator's prototype to Calculator's prototype, you won't be accessing that decimaldigits value on the calculator instance. If you access the following code, it will raise an error. varCalc =NewCalculator (); Alert (Calc.add (1, 1) ; alert (calc.decimaldigits); rewrite the prototype: in the use of third-party JS class library, sometimes they define the prototype method is not enough to meet our needs, but can not be separated from this class library, So at this point we need to rewrite one or more of the properties or functions in their prototype, and we can reach overwrite rewrite the previous add function by continuing to declare the same add code, the code is as follows://overwrite the Add () function of the front calculatorCalculator.prototype.add =function(x, y) {returnX + y + This. Tax;};varCalc =NewCalculator (); Alert (Calc.add (1, 1) , so that we calculate the result is more than the original tax value, but one thing to note: that is, the rewritten code needs to be put in the last, so as to overwrite the previous code. Prototype chain before we put the prototype chain, we'll start with a piece of code:functionFoo () { This. Value = 42;} Foo.prototype={method:function() {}};functionBar () {}//set the prototype property of bar to an instance object of FooBar.prototype =NewFoo (); Bar.prototype.foo= ' Hello world ';//fix Bar.prototype.constructor for bar itselfBar.prototype.constructor =Bar;varTest =NewBar ()//Create a new instance of bar//prototype chaintest [instance of Bar] Bar.prototype [instance of foo] {foo:' Hello World '} foo.prototype {method: ...}; Object.prototype {toString: .../*etc.*/in the example above, the test object inherits from Bar.prototype and Foo.prototype, so it can access the prototype method of Foo. It also has access to the Foo instance attribute value defined on the prototype. It is important to note thatNewBar () does not create a new instance of Foo, but reuses the instance on its prototype, so all bar instances share the same Value property. Property Lookup: When looking up a property of an object, JavaScript traverses the prototype chain up until it finds the property of the given name, until the lookup reaches the top of the prototype chain-namely Object.prototype-However, the specified property is still not found, and the undefined is returned, let's look at an example:functionfoo () { This. Add =function(x, y) {returnX +y; }} Foo.prototype.add=function(x, y) {returnx + y + 10; } Object.prototype.subtract=function(x, y) {returnX-y; }        varf =Newfoo (); Alert (F.add (1, 2));//The result is 3, not theAlert (F.subtract (1, 2));//The result is -1 .running through the code, we found that subtract is installing what we call upward lookup to get results, but the Add method is a little different, which is what I want to emphasize, is that the property in the search is the first to find their own properties, if not to find the prototype, no, then go up, has been plugged into the prototype of object, so at some level, forIn statement Traversal property, efficiency is also a problem. Another thing we need to note is that we can assign any type of object to the prototype, but cannot assign a value of the atomic type, such as the following code is invalid:functionFoo () {}foo.prototype= 1;//Invalidhasownproperty function: hasOwnProperty is a method of Object.prototype, it is a good thing, he can judge whether an object contains custom properties, not the properties on the prototype chain, because hasOwnProperty is the only function in JavaScript that handles properties but does not look for a prototype chain. //Modify Object.prototypeObject.prototype.bar = 1; varFoo ={goo:undefined};foo.bar;//1' Bar 'inchFoo//trueFoo.hasownproperty (' Bar ');//falseFoo.hasownproperty (' goo ');//trueonly hasownproperty can give correct and expected results, which is useful when traversing the properties of an object. There is no other way to exclude the properties on the prototype chain, rather than the properties defined on the object itself. But the disgusting thing is that JavaScript does not protect hasOwnProperty from being illegally occupied, so if an object happens to have this property, you need to use an external hasownproperty function to get the correct result. varFoo ={hasownproperty:function() {        return false; }, Bar:' Here is Dragons '};foo.hasownproperty (' Bar ');//always returns false//use the {} object's hasOwnProperty and set it up and down to Foo{}.hasownproperty.call (foo, ' Bar ');//truehasOwnProperty is the only available method when checking for the existence of an attribute on an object. While in use for inchwhen loop traverses an object, it is recommended to always use the hasOwnProperty method, which avoids the interference caused by the prototype object extension, let's take a look at the example://Modify Object.prototypeObject.prototype.bar = 1;varFoo = {Moo:2}; for(varIinchfoo) {Console.log (i);//output two properties: Bar and MooWe can't change the behavior of the for in statement, so we can only use the hasOwnProperty method to filter the results, the code is as follows://The foo variable is in the previous example for(varIinchfoo) {    if(Foo.hasownproperty (i)) {console.log (i); }} This version of the code is the only correct notation. Since we used the hasownproperty, we only output moo this time. If you do not use hasOwnProperty, this code may go wrong when the native object prototype (such as Object.prototype) is extended. Summary: It is recommended to use hasOwnProperty, do not make any assumptions about the environment in which the code runs, and do not assume that native objects have been extended. Summing up the prototype greatly enriched our development code, but in peacetime use of the process must pay attention to the above mentioned considerations. Content reference to: http://bonsaiden.github.com/javascript-garden/zh/synchronization and recommendation this article has been synchronized to the directory index: in-depth understanding of JavaScript series in-depth understanding of the JavaScript series, including the original, translation, reprint and other types of articles, if it is useful to you, please recommend supporting a, to the power of the uncle writing. 

In-depth understanding of the JavaScript series (5): Powerful prototypes and prototype chains

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.