Deep understanding of the JavaScript series (6) powerful prototypes and prototype chain _javascript techniques

Source: Internet
Author: User
Tags hasownproperty
Objective
JavaScript does not contain the traditional class inheritance model, but rather uses the Prototypal prototype model.

Although this is often referred to as the shortcoming of JavaScript, a prototype based inheritance model is more powerful than traditional class inheritance. It is easy to implement the traditional class inheritance model, but it is much more difficult to implement prototype inheritance in JavaScript.

Since JavaScript is the only widely used language based on prototype inheritance, it takes 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:
Copy Code code as follows:

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 each function to get the result, after learning the prototype, we can use the following methods to beautify the code.

Prototype use mode 1:
Before using prototypes, we need to make small changes to the code:
Copy Code code as follows:

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

The prototype of the Calculator object is then set by assigning the object literal to the prototype property of the Calculator object.
Copy Code code as follows:

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 then call the Add method to compute the result after the new Calculator object.

Prototype use Mode 2:
The second way is to assign a value by using an expression that is immediately executed by the function when the prototype is assigned, that is, the following format:

Calculator.prototype = function () {} ();
Its advantages in the previous posts have been known, that is, can encapsulate private function, through the form of return to expose a simple use of the name, to achieve public/private effect, the modified code is as follows:
Copy Code code 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 to compute the result after the new Calculator object.

A little more.
Step-by-Step statement:
When using the prototype, one of the limitations is to set the prototype object at once, and let's say how to set each property of the prototype.
Copy Code code as follows:

var basecalculator = function () {
Declare a decimal number 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, and the constructor initializes an attribute decimaldigits of a decimal number, and then sets 2 functions through the prototype property, respectively, add (X,y) and subtract (x,y). Of course you can also use any of the 2 ways mentioned earlier, our main goal is to see how to set the Basecalculator object to the real calculator prototype.
Copy Code code as follows:

var basecalculator = function () {
This.decimaldigits = 2;
};

Basecalculator.prototype = {
Add:function (x, y) {
return x + y;
},
Subtract:function (x, y) {
return x-y;
}
};

After creating the above code, let's start:
Copy Code code as follows:

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

Calculator.prototype = new Basecalculator ();

We can see that Calculator's prototype is directed to an instance of Basecalculator to allow calculator to integrate its add (X,y) and Subtract (x,y) 2 function, and one thing to say is that Because its prototype is an instance of Basecalculator, their prototypes point to the same instance regardless of how many calculator object instances you create.
Copy Code code as follows:

var calc = new Calculator ();
Alert (Calc.add (1, 1));
The Decimaldigits attribute declared in the Basecalculator, which is accessible in calculator
alert (calc.decimaldigits);

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

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

Calculator.prototype = Basecalculator.prototype;

By assigning the prototype of Basecalculator to calculator, you will not be able to access that decimaldigits value on an instance of calculator, if you access the following code, that would raise an error.
Copy Code code as follows:

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

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

Overwrite the Add () function of the front calculator
Calculator.prototype.add = function (x, y) {
return x + y + this.tax;
};

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

In this way, we can calculate the result is more than the original tax value, but one thing to note: that the rewrite code needs to put in the end, so as to overwrite the previous code.

Prototype chain
Before we put the prototype chain together, we'll start with a code:
Copy Code code as follows:

function Foo () {
This.value = 42;
}
Foo.prototype = {
Method:function () {}
};

function Bar () {}

Set the prototype property of bar to an instance object of Foo
Bar.prototype = new Foo ();
Bar.prototype.foo = ' Hello world ';

Fixed Bar.prototype.constructor for Bar itself
Bar.prototype.constructor = Bar;

var test = new Bar ()//To create a fresh instance of bar

Prototype chain
Test [instance of bar]
Bar.prototype [Instances 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 methods of Foo. It also has access to the Foo instance property value that is defined on the prototype. Note that new bar () will not create a new instance of Foo, but rather reuse that instance on its prototype, so all Bar instances share the same Value property.

Property Lookup:
When looking for an object's properties, 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 the specified attribute is still not found, and the undefined is returned. Let's take a look at an example:
Copy Code code as follows:

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 13.
Alert (F.subtract (1, 2)); The result is-1

Run through code, we found that subtract is installing what we call upward lookup to get results, but the add way is a little different, which is what I want to emphasize is that attributes find their attributes first, if no more prototypes, no more, go up, has been inserted into the prototype of object, so at some level, efficiency is also a problem when traversing a property in a for-in statement.

One more thing we need to be aware of is that we can assign any type of object to the prototype, but not the value of the atomic type, for example, the following code is invalid:
Copy Code code as follows:

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

hasOwnProperty function:
hasOwnProperty is a Object.prototype method, and it's a good thing to judge whether an object contains custom attributes rather than attributes on the prototype chain, because hasOwnProperty is JavaScript The only function that handles attributes but does not look for a prototype chain.
Copy Code code as follows:

Modify Object.prototype
Object.prototype.bar = 1;
var foo = {goo:undefined};

Foo.bar; 1
' Bar ' in Foo; True

Foo.hasownproperty (' Bar '); False
Foo.hasownproperty (' goo '); True

Only hasOwnProperty can give the correct and expected results, which is useful when traversing the properties of an object. There is no other way to exclude attributes from the prototype chain, rather than to define the properties on the object itself.

But there is a disgusting place: JavaScript does not protect hasOwnProperty from being illegally occupied, so if an object happens to have this attribute, you need to use an external hasownproperty function to get the correct result.
Copy Code code as follows:

var foo = {
Hasownproperty:function () {
return false;
},
Bar: ' Here is Dragons '
};

Foo.hasownproperty (' Bar '); Always return False

Use the hasOwnProperty of the {} object, and set it down to Foo
{}.hasownproperty.call (foo, ' Bar '); True

hasOwnProperty is the only available method when checking for the existence of a property on an object. At the same time, when traversing an object using a for-in loop, the recommendation always uses the hasOwnProperty method, which avoids the interference caused by the extension of the prototype object, let's take a look at the example:
Copy Code code as follows:

Modify Object.prototype
Object.prototype.bar = 1;

var foo = {Moo:2};
for (var i in Foo) {
Console.log (i); Output two properties: Bar and Moo
}

We can't change the behavior of the for in statement, so the only way to filter the results is to use the hasOwnProperty method, as follows:
Copy Code code as follows:

The Foo variable is the example in the
for (var i in Foo) {
if (Foo.hasownproperty (i)) {
Console.log (i);
}
}

This version of the code is the only correct way to spell it. Since we used hasownproperty, we only output moo this time. If you do not use hasOwnProperty, this code may have an error when the native object prototype (such as Object.prototype) is extended.

Summary: The recommended use of hasOwnProperty, do not make any assumptions about the environment in which the code is run, and do not assume that the native object has been extended.

Summarize
The prototype greatly enriched our development code, but in peacetime use of the process must pay attention to some of the above mentioned considerations.
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.