In-depth understanding of JavaScript series (46): code reuse mode (recommended)

Source: Internet
Author: User
Tags hasownproperty
Introduction

Four typesCodeThe reuse mode is the best practice and is recommended for programming.

Mode 1: Prototype inheritance

Prototype Inheritance refers to the prototype of parent objects as sub-objects to achieve the purpose of inheritance:

 Function Object (o ){
Function F (){
}

F. Prototype = O;
Return New F ();
}

// Parent object to be inherited
VaR Parent = {
Name: "Papa"
};

// New Object
VaR Child = Object (parent );

// Test
Console. Log (child. Name ); // "Papa"


// Parent Constructor
Function Person (){
// An "own" Property
This . Name = "Adam ";
}
// Add new attributes to the prototype
Person. Prototype. getname = Function (){
Return This . Name;
};
// Create a new person
VaR Papa = New Person ();
// Inheritance
VaR KID = Object (PAPA );
Console. Log (kid. getname ()); // "Adam"


// Parent Constructor
Function Person (){
// An "own" Property
This . Name = "Adam ";
}
// Add new attributes to the prototype
Person. Prototype. getname = Function (){
Return This . Name;
};
// Inheritance
VaR KID = Object (person. Prototype );
Console. Log ( Typeof Kid. getname ); // "Function", because it is defined in the prototype
Console. Log ( Typeof Kid. Name ); // "Undefined", because only the prototype is inherited

At the same time, ecmascript5 provides a similar method called object. Create to inherit objects. The usage is as follows:

/*Use functions provided by ecmascript 5 in the new version*/
VaRChild = object. Create (parent );

VaRChild = object. Create (parent ,{
Age: {value: 2}//Ecma5 Descriptor
});
Console. Log (child. hasownproperty ("Age "));//True

In addition, attributes can be defined on the second parameter in a more fine-grained manner:

 //  First, define a new object man  
VaR Man = object. Create ( Null );

// Next, create configuration settings that contain attributes.
// Set the attribute to writable, enumerable, and configurable.
VaR Config = {
Writable: True ,
Enumerable: True ,
Retriable: True
};

// Generally, object. defineproperty () is used to add new attributes (supported by ecmascript5)
// Now, for convenience, we can customize an encapsulation function.
VaR Defineprop = Function (OBJ, key, value ){
Config. value = value;
Object. defineproperty (OBJ, key, config );
}

Defineprop (man, 'car', 'delorean ');
Defineprop (man, 'dob', '123 ');
Defineprop (man, 'beard ', False );

Therefore, inheritance can be done as follows:

VaRDriver = object. Create (man );
Defineprop (driver, 'topspeed', '100mph ');
Driver. topspeed//100mph

However, you must note thatObject. Create (null)The prototype of the created object isUndefined, That is, noTostringAndValueofMethod, soAlert (man );ButAlert (man. Car );No problem.

Mode 2: Copy all attributes for inheritance

In this way, all attributes of the parent object are copied to the sub-object. Generally, the sub-object can use the data of the parent object.

Let's look at an example of a shallow copy:

 /*  Shortest copy  */ 
Function Extend (parent, child ){
VaR I;
Child = Child | {};
For (I In Parent ){
If (Parent. hasownproperty (I )){
Child [I] = parent [I];
}
}
Return Child;
}

VaR Dad = {name: "Adam "};
VaR KID = extend (DAD );
Console. Log (kid. Name ); // "Adam"

VaR Dad = {
Counts: [1, 2, 3],
Reads: {paper: True }
};
VaR KID = extend (DAD );
Kid. counts. Push (4 );
Console. Log (DAD. counts. tostring ()); // "1, 2, 3, 4"
Console. Log (DAD. Reads === kid. Reads );// True

In the last line of the code, you can find that the reads of Dad and kid are the same, that is, they use the same reference, which is the problem caused by the shallow copy.

Let's take a look at the deep copy:

 /*  Deep copy  */ 
Function Extenddeep (parent, child ){
VaR I,
Tostr = object. Prototype. tostring,
Astr = "[object array]";

Child = Child | {};

For (I In Parent ){
If (Parent. hasownproperty (I )){
If ( Typeof Parent [I] === 'object '){
Child [I] = (tostr. Call (parent [I]) === astr )? []: {};
Extenddeep (parent [I], child [I]);
} Else {
Child [I] = parent [I];
}
}
}
Return Child;
}

VaR Dad = {
Counts: [1, 2, 3],
Reads: {paper: True }
};
VaR KID = extenddeep (DAD );

Kid. counts. Push (4 );
Console. Log (kid. counts. tostring ()); // "1, 2, 3, 4"
Console. Log (DAD. counts. tostring ()); // "1, 2, 3"

Console. Log (DAD. Reads === kid. Reads ); // False
Kid. reads. Paper = False ;

After the deep copy, the two values are not equal, bingo!

Mode 3: Mix-in)

Mixing is to copy one or more (or all) attributes (or methods) of an object to another object. Let's take an example:

FunctionMix (){
VaRArg, prop, child = {};
For(ARG = 0; arg <arguments. length; Arg + = 1 ){
For(PropInArguments [Arg]) {
If(Arguments [Arg]. hasownproperty (PROP )){
Child [prop] = arguments [Arg] [prop];
}
}
}
ReturnChild;
}

VaRCake = mix (
{Eggs: 2, large:True},
{Butter: 1, salted:True},
{Flour: '3 cups '},
{Sugar: 'Sure! '}
);

Console. dir (cake );

The mix function copies the sub-attributes of all input parameters to the child object to generate a new object.

So how can we just mix some attributes? How to do this? In fact, we can use redundant parameters to define the attributes to be mixed in, such as mix (child, parent, Method1, method2) in this way, you can only mix Method1 and method2 in the parent into child. Code:

 //  Car  
VaR Car = Function (Settings ){
This . Model = settings. model | 'no model provided ';
This . Color = settings. color | 'no color provided ';
};

// Mixin
VaR Mixin = Function (){};
Mixin. Prototype = {
Driveforward: Function (){
Console. Log ('Drive forward ');
},
Drivebackward: Function (){
Console. Log ('Drive backward ');
}
};


// The two parameters defined are the reciving object and the giving object)
Function Augment (receivingobj, givingobj ){
// If the specified method name is provided, three additional parameters are required.
If (Arguments [2]) {
For ( VaR I = 2, Len = arguments. length; I <Len; I ++ ){
Receivingobj. Prototype [arguments [I] = givingobj. Prototype [arguments [I];
}
}
// If you do not specify 3rd or more parameters, all the methods are mixed.
Else {
For ( VaR Methodname In Givingobj. Prototype ){
// Check whether the names to be included are not included in the processing object.
If (! Receivingobj. Prototype [methodname]) {
Receivingobj. Prototype [methodname] = givingobj. Prototype [methodname];
}
}
}
}

// Add attributes to the car, but the values are 'driveforward 'and 'drivebackward '*/
Augment (CAR, Mixin, 'driveforward ', 'drivebackward ');

// Create a new object car
VaR Vehicle = New Car ({model: 'Ford escort', color: 'blue '});

// Test whether the mixed-in method is obtained successfully
Vehicle. driveforward ();
Vehicle. drivebackward ();

This method is flexible to use.

Mode 4: Borrow Method

An object borrows one or two methods from another object, and there is no direct connection between the two objects. There is no need to explain more. Use the code to explain it directly:

 VaR One = {
Name: 'object ',
Say: Function (GREET ){
Return Greet + ',' + This . Name;
}
};

// Test
Console. Log (one. Say ('Hi ')); // "Hi, object"

VaR Two = {
Name: 'Another Object'
};

Console. Log (one. Say. Apply (two, ['hello']); // "Hello, another object"

// Complex say to a variable. This points to the global variable.
VaR Say = one. Say;
Console. Log (say ('hoho ')); // "Hoho, undefined"

// Input a callback function callback
VaR Yetanother = {
Name: 'Et another object ',
Method: Function (Callback ){
Return Callback ('hola ');
}
};
Console. Log (yetanother. Method (one. Say ));// "Holla, undefined"

Function BIND (O, m ){
Return Function (){
Return M. Apply (O, []. Slice. Call (arguments ));
};
}

VaR Twosay = BIND (two, one. Say );
Console. Log (twosay ('yo ')); // "Yo, another object"


// Ecmascript 5 adds a BIND () method to function. prototype to make it easy to use apply () and call ().

If ( Typeof Function. Prototype. Bind === 'undefined '){
Function. Prototype. Bind = Function (Thisarg ){
VaR Fn = This ,
Slice = array. Prototype. Slice,
ARGs = slice. Call (arguments, 1 );
Return Function (){
Return FN. Apply (thisarg, argS. Concat (slice. Call (arguments )));
};
};
}

VaR Tw1_y2 = one. Say. BIND (two );
Console. Log (tw1_y2 ('bonjob ')); // "Bonjour, another object"

VaR Twpolicy3 = one. Say. BIND (two, 'enchant ');
Console. Log (twpolicy3 ());// "Enchanté, another object"

Transferred from: Uncle Tom

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.