Follow me to learn JavaScript prototype use notes _javascript tips

Source: Internet
Author: User
Tags addchild closure object object

First, on the prototype to save the method

It is perfectly possible to encode JavaScript without using prototype, for example:

function User (name, PasswordHash) { 
 this.name = name; 
 This.passwordhash = PasswordHash; 
 this.tostring = function () {return 
  "[User" + THIS.name + "]"; 
 This.checkpassword = function (password) {return 
  hash (password) = = This.passwordhash;} 

var u1 = new User (/* ... */); 
var U2 = new User (/* ... */); 
var U3 = new User (/* ... */); 

When you create instances of multiple user types, there is a problem: not only the name and PasswordHash properties exist on each instance, and the ToString and Checkpassword methods have a copy on each instance. As shown in the following figure:

However, when ToString and Checkpassword are defined on the prototype, the image above becomes the following:

The ToString and Checkpassword methods are now defined on the User.prototype object, meaning that the two methods only have one copy and are shared by all the user instances.

You might think that putting a method as a copy on each instance saves the time of the method query. (When the method is defined on the prototype, it first looks for the method on the instance itself, and if it is not found, it will go to the prototype.)

But in the modern JavaScript execution engine, the query for the method is optimized so much that the query time is almost unnecessary, so putting the method on the prototype object saves a lot of memory.

Second, use closure to save private data

JavaScript's object system does not encourage the use of information hiding (information hiding) in its syntax. Because when used such as This.name,this.passwordhash, the default access level of these properties is public and can be accessed by Obj.name,obj.passwordhash at any location.

In ES5 environments, there are also ways to make it easier to access all properties on an object, such as Object.keys (), Object.getownpropertynames (). So, some developers use some protocol to define the private properties of JavaScript objects, such as the most typical use of an underscore as a prefix for attributes to tell other developers and users that this attribute should not be accessed directly.

But doing so does not fundamentally solve the problem. Other developers and users can also access the underlined attributes directly. For situations where private properties are really required, you can use closures for implementations.

In some ways, in JavaScript, closures have two extremes for accessing policies and objects for variables. Any variable in the closure is private by default and can be accessed only within the function. For example, you can implement the user type as follows:

function User (name, PasswordHash) { 
 this.tostring = function () {return 
  "[User" + name +] "; 
 }; 
 This.checkpassword = function (password) {return 
  hash (password) = = PasswordHash;} 
 

At this point, neither name nor PasswordHash is saved as an instance's property, but is saved by a local variable. Then, according to the access rules of the closures, the methods on the instance can be accessed, but not elsewhere.

One disadvantage of using this pattern is that methods that take advantage of local variables need to be defined on the instance itself and cannot be said to be defined on a prototype object. As discussed in Item34, the problem with this is that it increases memory consumption. However, in some special situations, even the definition of the method is feasible in the instance.

Third, the instance state is only guaranteed on the instance object

A "one-to-many" relationship between a prototype of a type and an instance of that type. Then, you need to ensure that the data associated with the instance is not incorrectly stored on the prototype. For example, for a type that implements a tree structure, it is incorrect to save its child nodes on that type of prototype:

function tree (x) { 
 this.value = x; 
} 
Tree.prototype = { 
 children: [],///should be instance state! 
 Addchild:function (x) { 
  this.children.push (x); 
 } 
}; 

var left = new Tree (2); 
Left.addchild (1); 
Left.addchild (3); 

var right = new Tree (6); 
Right.addchild (5); 
Right.addchild (7); 

var top = new Tree (4); 
Top.addchild (left); 
Top.addchild (right); 

Top.children; [1, 3, 5, 7, left, right] 

When the state is saved to the prototype, the state of all instances is saved centrally, and it is clearly incorrect in the above scenario that the state that belongs to each instance is incorrectly shared. As shown in the following illustration:

The correct implementation should be this:

function tree (x) { 
 this.value = x; 
 This.children = []; Instance state 
} 
tree.prototype = { 
 addchild:function (x) { 
  this.children.push (x); 
 } 
}; 

At this point, the storage of the instance state is as follows:

It can be seen that a problem may arise when the state that belongs to the instance is shared on the prototype. Be sure that the property is shared before you need to save the State property on prototype.

In general, when an attribute is immutable (stateless), it can be stored on a prototype object (for example, the method can be saved on the prototype object). Of course, stateful attributes can also be placed on prototype objects, depending on the specific scenario, typically a variable used to record the number of instances of a type. Using the Java language as an analogy, this type of variable that can be stored on a prototype object is a class variable in Java (decorated with the static keyword).

Iv. Avoid inheriting standard types

The ECMAScript Standard library is small, but provides some important types such as array,function and date. In some cases, you might consider inheriting one of these types to implement specific functions, but this practice is not encouraged.

For example, to manipulate a directory, you can have the directory type inherit the array type as follows:

function Dir (path, entries) { 
 this.path = path; 
 for (var i = 0, n = entries.length i < n; i++) { 
  this[i] = entries[i]; 
 } 
Dir.prototype = Object.create (array.prototype); 
Extends Array 

var dir = new Dir ("/tmp/mysite", ["index.html", "Script.js", "style.css"]); 
Dir.length; 0 

But it can be found that the value of Dir.length is 0, not the expected 3.

This behavior occurs because the Length property works only if the object is a true array type.

In the ECMAScript standard, an invisible internal property is defined as [[class]]. The value of this property is just a string, so don't be misled into thinking that JavaScript also implements its own type system. So, for the Array type, the value of this property is "Array", and for the function type, the value of this property is "Function." The following table is all the [[class]] values defined by ECMAScript:

So when an object's type is indeed an array, the Length property is special in that the value of length is consistent with the number of attributes indexed in that object. For example, an array object arr,arr[0] and arr[1] means that the object has two indexed properties, and the value of length is 2. When Arr[2 is added, the value of length is automatically synchronized to 3. Similarly, when the length value is set to 2 o'clock, Arr[2] is automatically set to undefined.

But when the array type is inherited and the instance is created, the [[Class]] property of the instance is not array, but object. Therefore, the length property does not work correctly.

In JavaScript, you also provide a way to query the [[Class]] property, using the Object.prototype.toString method:

var dir = new Dir ("/", []); 
Object.prototype.toString.call (dir); "[Object Object]" 

Therefore, a better way to implement this is to use a combination rather than an inheritance:

function Dir (path, entries) { 
 this.path = path; 
 this.entries = entries; Array Property 
} 
Dir.prototype.forEach = function (f, thisarg) { 
 if (typeof thisarg = = "undefined") { 
  Thisarg = this; 
 } 
 This.entries.forEach (f, Thisarg); 
}; 

The code above will no longer use inheritance, but rather a portion of the functionality is delegated to the internal entries property, which is an array-type object.

In the ECMAScript standard library, most constructors rely on intrinsic property values such as [[class]] to implement the correct behavior. They are not guaranteed to behave correctly for subtypes that inherit these standard types. Therefore, do not inherit types from the ECMAScript standard library such as:
Array, Boolean, Date, Function, number,regexp,string

The above is a summary of the use of prototype, hoping to help you correct use of prototype.

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.