Introduction to javascript prototype and prototype chain instances

Source: Internet
Author: User
Tags inheritance uppercase letter hasownproperty


Basic concepts

The prototype chain has an object for each constructor, and the prototype object contains a pointer to the constructor, and the instance contains an internal pointer to the prototype object. So, if the prototype object equals another instance of the prototype, then the prototype object will contain a pointer to another prototype, and, correspondingly, a pointer to another constructor is included in the other prototype. If another prototype is an instance of another prototype, the relationship is still valid. Such layers of progression form the chain of examples and prototypes.

The "Prototype object" object contains properties and methods that can be shared by all instances of a particular type. All reference types inherit object by default, and this inheritance is also implemented through a prototype chain. The default prototypes for all functions are instances of object, so the default stereotype contains an internal pointer to Object.prototype, which is why all custom types inherit the ToString (), valueof () method

The difference between the constructor constructor and other functions is that they are invoked in a different way. In general, a function can be used as a constructor if it is called by the new operator, and it will not be the same as a normal function if it is not invoked through the new operator.

[note] user-defined functions and built-in constructors in JavaScript can be used as constructors

The constructor constructor should always start with an uppercase letter, not a constructor that starts with a lowercase letter. This approach is drawn from other OO languages, primarily to distinguish them from other functions in ECMAScript, because the constructor itself is a function, but it can be used to create objects.

"Three usage scenarios for constructors"

[A] used as a constructor

var person = new Person ("Nicholas", "Software Engineer");
Person.sayname ();

[b] called as a normal function

Person ("Greg", "Doctor");//Add to Window
Window.sayname ()//"Greg"

[C] is called in the scope of another object

var o = new Object ();
Person.call (O, "Kristen", "Nurse");
O.sayname ()//"Kristen"


The prototype property creates a prototype attribute for the function based on a specific set of rules, which points to the prototype object of the function, whenever a new function is created.

[note] Only functions have prototype properties, object has no prototype property

Constructor property By default, all prototype objects automatically get a constructor (constructor) property that contains a pointer to the function where the prototype property is located

[note] After the custom constructor has been created, its prototype object will only get the constructor property, and the other methods are inherited from Object


"_proto_ and [[[prototype]]" When a new instance is created by the calling constructor, the internal of the instance contains a pointer (internal property) that points to the stereotype object of the constructor. ECMA-262 5th Edition Tube This pointer is called [[prototype]]. Although [[prototype]] is accessed in a standard way in scripts, Firefox\safari\chrome supports a property _proto_ on each object, and in other implementations, this property is completely invisible to the script. This connection exists between the instance and the stereotype object of the constructor, not between the instance and the constructor

Basic Operations

Prototype chain query performs a search whenever the code reads an attribute of an object that has a property of the given name. The search starts first from the object instance itself, if a property with the given name is found in the instance, the value of the property is returned, or if it is not found, continues the search for the prototype object to which the pointer points, looks for a property with the given name in the prototype object, and returns the value of the property if it is found.


Add Instance property when you add a property to an object instance, the This property masks the attributes of the same name saved in the prototype object; in other words, adding this property will only prevent us from accessing that property in the prototype, but not modifying that property, even if this property is set to NULL, and it will only be set in the instance. The connection to the prototype is not restored. However, using the delete operator allows you to completely remove the instance properties, allowing us to regain access to the properties in the prototype.

"The dynamics of the prototype" because the process of looking up values in the prototype is a search, so any changes we make to the prototype object are immediately reflected from the instance, even if the instance is created first and then the prototype is modified.

[note] It is not recommended to modify the prototype of a native object in a production program

function person () {};
var friend = new person ();
Person.prototype.sayHi = function () {
alert (' Hi ');
}
Friend.sayhi ()//"HI"


Overriding a stereotype calls a constructor to add a [[prototype]] pointer to the original prototype, and modifying the stereotype to another object is tantamount to cutting off the relationship between the constructor and the original prototype. The pointer in the instance points only to the stereotype, not to the constructor.

Basic methods

[1]isprototypeof (): To determine whether the instance object and the prototype object exist in the same prototype chain, as long as the prototype in the prototype chain, can be said to be the prototype chain derived from the prototype of the instance

function person () {};
var person1 = new Person ();
var person2 = new Object ();
Console.log (Person.prototype.isPrototypeOf (Person1));//true
Console.log (Object.prototype.isPrototypeOf ( Person1));//true
Console.log (Person.prototype.isPrototypeOf (Person2));//false
Console.log ( Object.prototype.isPrototypeOf (Person2));//true


[2] ECMAScript5 New Method Object.getprototypeof (): This method returns the value of [[Prototype]]

function person () {};
var person1 = new Person ();
var person2 = new Object ();
Console.log (object.getprototypeof (Person1)); person{}
Console.log (object.getprototypeof (person1) = = Person.prototype);//true
Console.log ( Object.getprototypeof (person1) = = = Object.prototype); False
Console.log (object.getprototypeof (Person2));//object{}


[3]hasownproperty (): detects whether a property exists in the instance

function person () {
Person.prototype.name = ' Nicholas ';
}
var person1 = new Person ();
There are no instances, but there are
console.log ("name") in the prototype,//false
//No instances, and there is no console.log in the prototype
( Person1.hasownproperty ("no"));//false
person1.name = ' Greg ';
Console.log (person1.name);//' Greg '
console.log (person1.hasownproperty (' name '));//true
Delete Person1.name;
Console.log (person1.name);//"Nicholas"
console.log (Person1.hasownproperty (' name '));//false



[4] ECMAScript5 object.getownpropertydescriptor (): Can only be used to get the descriptor of the instance property, to obtain the descriptor of the prototype property, The Object.getownpropertydescription () method must be invoked directly on the prototype object

function person () {
Person.prototype.name = ' Nicholas ';
}
var person1 = new Person ();
Person1.name = ' Cook ';
Console.log (Object.getownpropertydescriptor (Person1, "name");//object {value: "Cook", Writable:true, Enumerable: True, configurable:true}
Console.log (Object.getownpropertydescriptor (Person.prototype, "name"));//object { Value: "Nicholas", Writable:true, Enumerable:true, configurable:true}


[5]in operator: Returns True when an object is able to access a given property, whether it exists in an instance or in a prototype

function person () {}
var person1 = new Person ();
Person1.name = ' Cook ';
Console.log ("name" in Person1),//true
console.log ("name" in Person.prototype),//false
var person2 = new Person ();
Person.prototype.name = ' Cook ';
Console.log ("name" in Person2);//true
console.log ("name" in Person.prototype);//true


[6] using both the hasOwnProperty () method and the in operator to determine whether the attribute exists in the instance

hasOwnProperty () returns false and the In operator returns TRUE, the function returns True, which is determined to be a property
function Hasprototypeproperty (object,name) in the prototype {
return!object.hasownproperty (name) && (name in object);
}
function person () {
Person.prototype.name = ' Nicholas ';
}
var person1 = new Person ();
Console.log (Hasprototypeproperty (person1, ' name '));//true
person1.name = ' Cook ';
Console.log (Hasprototypeproperty (person1, ' name '));//false
delete person1.name;
Console.log (Hasprototypeproperty (person1, ' name '));//true
delete Person.prototype.name;
Console.log (Hasprototypeproperty (person1, ' name '));//false


[7] ECMAScript5 Object.keys () method: Receives an object as an argument and returns an array of strings containing all enumerable properties

[note] Be sure to new the instance object before using the method, otherwise null

function person () {
Person.prototype.name = ' Nicholas ';
Person.prototype.age =;
Person.prototype.job = ' Software Engineer ';
Person.prototype.sayName = function () {
alert (this.name);
}    
};
var keys = Object.keys (Person.prototype);
Console.log (keys);//[]
var p1 = new Person ();
P1.name = "Rob";
P1.age =;
var keys = Object.keys (Person.prototype);
Console.log (keys);//["Name", "Age", "job", "Sayname"]
var p1keys = Object.keys (p1);
Console.log (P1keys);//["Name", "Age"


[8] ECMAScript5 Object.getownpropertynames () method: Receives an object as an argument and returns an array of strings containing all the attributes

[note] Be sure to new the instance object before using this method, otherwise only constructor

function person () {    Person.prototype.name 
=  ' Nicholas ';
    Person.prototype.age = 29;
    Person.prototype.job =  ' Software engineer ';     person.prototype.sayname = function () {      
  alert (this.name);
    }    };
Var keys = object.getownpropertynames (Person.prototype);
Console.log (keys);//["Constructor"] Var p1 = new person ();
Var keys = object.getownpropertynames (Person.prototype); Console.log (keys);//["constructor",  "name",  "Age",  "job",  "Sayname"] 




Deep understanding of JavaScript's powerful prototypes and prototype chains

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:

var decimaldigits = 2,
tax = 5;
function add (x, y) {return
x + y;
}
function subtract (x, y) {return
xy;
}
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:

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.

Calculator.prototype = {
add:function (x, y) {return
x + y;
},
subtract:function (x, y) {return
xy;
}
};
Alert ((New Calculator ()). Add (1, 3));


In this way, we can then call the Add method to compute the result after we have new Calculator the object.

prototype Usage 2:

The second way is to assign a value with an expression that is executed immediately when the prototype is assigned, that is, the following format:

Calculator.prototype = function () {} ();

Its benefits are already known in previous posts, that is, you can encapsulate a private function, expose a simple use name through return, to achieve public/private effect, and modify the following code:

 Calculator.prototype = function  ()  {             add = function  (x, y)  {      
          return x + y;            &NBSP},              subtract = function  (x, y)  {   
             return x - y;             }              return {                 add: add,                 &nbsP;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.

var basecalculator = function () {
//) declares 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.

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


After creating the above code, let's start:

var Calculator = function () {
//) declares 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.

var calc = new Calculator ();
Alert (Calc.add (1, 1));
The Decimaldigits attribute declared in the Basecalculator is an
alert (calc.decimaldigits) that can be accessed in calculator;


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:

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.

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:

Overlay the previous Calculator Add () function
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:

Function foo ()  {    this.value = 42;}
foo.prototype = {    method: function ()  {}};
Function bar ()  {}//  Set the prototype property of Bar to the instance object Bar.prototype = new foo () of Foo;
bar.prototype.foo =  ' Hello world ';
  Correction Bar.prototype.constructor for Bar itself bar.prototype.constructor = bar; Var test = new bar ()  //  Create a new instance of Bar//  prototype chain Test [bar instance]      bar.prototype [foo's example]          { 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:

function foo () {
This.add = function (x, y) {return
x + y;
}
Foo.prototype.add = function (x, y) {return
x + y +;
}
Object.prototype.subtract = function (x, y) {return
xy;
}
var f = new Foo ();
Alert (F.add (1, 2)); The result is 3, rather than
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:

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.

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.

var foo = {
hasownproperty:function () {return
false;
},
bar: ' Here is Dragons '
};
Foo.hasownproperty (' Bar '); Always returns false
//using the hasOwnProperty of the {} object and setting it up 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:

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:

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


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.