JavaScript Quest: Powerful prototypes and prototype chains

Source: Internet
Author: User
Tags hasownproperty function calculator

The foo variable is the for (var i in foo) {    if (Foo.hasownproperty (i)) {        console.log (i)) {if (i)    }, in the above example;}

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 was just learning JavaScript, I used to write code in the following ways:

<pre name= "Code" class= "javascript" >var decimaldigits = 2,tax = 5;function Add (x, y) {    return x + y;} function subtract (x, y) {    return x-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.

How to use prototypes 1

Before using the prototype, we need to make a small change to the code:

var Calculator = function (decimaldigits, tax) {    this.decimaldigits = decimaldigits;    This.tax = tax;};


The prototype of the Calculator object is then set by assigning a value object literal to the prototype property of the Calculator object.

Calculator.prototype = {    add:function (x, y) {        return x + y;    },    subtract:function (x, y) {        return x -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.
How to use Prototypes 2

The second way is to assign a value using the expression immediately executed by the function when the value prototype prototype, that is, the following format:

Calculator.prototype = function () {} ();
its benefits in the previous post has been known, is to encapsulate the private function, through the form of return to expose the simple use of the name, to achieve public/private effect, the modified code is as follows:
Calculator.prototype = function () {    add = function (x, y) {        return x + y;    },    subtract = function (x, y) {        return x-y;    }    return {        add:add,        subtract:subtract    }} (),//alert ((New Calculator ()). Add (11, 3));


in the same way, we can call the Add method after the new Calculator object to calculate the result. Step declaration

When using prototypes, one limitation is to set up prototype objects at once, so let's take a look at how to set each property of the prototype.

var basecalculator = function () {    //Declare a decimal place for each instance    this.decimaldigits = 2;};        Using prototypes to extend 2 object methods to Basecalculator BaseCalculator.prototype.add = function (x, y) {    return x + y;}; BaseCalculator.prototype.subtract = function (x, y) {    return x-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.

var basecalculator = function () {    this.decimaldigits = 2;};  Basecalculator.prototype = {    add:function (x, y) {        return x + y;    },    subtract:function (x, y) {        return X-y;    }};

Once you've created the above code, let's start:

var Calculator = function () {    //Declare a tax number for each instance    This.tax = 5;};        Calculator.prototype = new Basecalculator ();

We can see that the prototype of calculator is pointing to an instance of Basecalculator, with the intention of having calculator integrate its add (x, y) and subtract (x, Y) 2 function, and one thing to say, Since its prototype is an instance of Basecalculator, no matter how many Calculator object instances you create, their prototypes point to the same instance.



The above code, after running, we can see that because Calculator's prototype is pointing to the Basecalculator instance, it can access his Decimaldigits property value, What if I don't want calculator to access the property values declared in Basecalculator's constructor? this:

var Calculator = function () {    this.tax= 5;}; Calculator.prototype = Basecalculator.prototype;

By assigning the prototype of the Basecalculator to the calculator prototype, you will not be accessing that decimaldigits value on the calculator instance, and if you access the following code, it will raise the error.

var calc = new Calculator (); Alert (Calc.add (1, 1)); alert (calc.decimaldigits);


Rewriting prototypes

In the use of third-party JS library, often sometimes they define the prototype method is not to meet our needs, but inseparable from this class library, so at this time we need to rewrite their prototype of one or more properties or function, We can do this by continuing to declare the same add code in the form of overwrite rewrite before the Add function, the code is as follows:

The Add () function Calculator.prototype.add = function (x, y) {    return x + y + this.tax;}, covering the preceding Calculator; var calc = new Calculator (); Alert (Calc.add (1, 1));


In this way, 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 go through the code:

function Foo () {    this.value = 42;} Foo.prototype = {    method:function () {}};function bar () {}//Sets the prototype property of bar as an instance object of Foo Bar.prototype = new Foo (); Bar.prototype.foo = ' Hello world ';//fix Bar.prototype.constructor for Bar itself Bar.prototype.constructor = bar;var test = new Bar ()///Create a new instance of bar//prototype chain test [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 that the new bar () does not create an instance of Foo, but instead 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-that is, object.prototype-but still does not find the specified property, it returns undefined, Let's look at an example:

function foo () {    This.add = function (x, y) {        return x + y;    }} Foo.prototype.add = function (x, y) {    return x + y + 10;} Object.prototype.subtract = function (x, y) {    return x-y;} var f = new Foo (); alert (F.add (1, 2)); The result is 3, not 13alert (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, the efficiency is also a problem when traversing properties with a for in statement.

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:

function Foo () {}foo.prototype = 1; Invalid


hasOwnProperty function

hasOwnProperty is a way of object.prototype, it's a good thing, he can tell if an object contains a custom attribute, not a property on the prototype chain, because hasOwnProperty is a JavaScript The only function that handles properties but does not look for a prototype chain.

Modify Object.prototypeObject.prototype.bar = 1; var foo = {Goo:undefined};foo.bar; 1 ' bar ' in Foo; Truefoo.hasownproperty (' Bar '); Falsefoo.hasownproperty (' goo '); True


Only 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.

var foo = {    hasownproperty:function () {        return false;    },    bar: ' Here is Dragons '};foo.hasownproperty (' Bar '); Always return false//using the {} object's hasOwnProperty and set it down to Foo{}.hasownproperty.call (foo, ' Bar '); True


hasOwnProperty is the only available method when checking for the existence of an attribute on an object. It is also recommended to always use the hasOwnProperty method when traversing an object using the for in loop, which avoids the interference caused by the prototype object extension, let's take a look at the example:

Modify Object.prototypeObject.prototype.bar = 1;var foo = {moo:2};for (var i in foo) {    console.log (i);//Output two properties: Bar and Moo


We have no way to 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:


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.

JavaScript Quest: Powerful prototypes and prototype chains

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.