Is your mixin compatible with ECMAScript 5?

Source: Internet
Author: User
Tags hasownproperty

ECMAScript 5, which I recently worked with clients, needs to be fully utilized. I encountered a very interesting problem here. This problem stems from a very common pattern: mixin, that is, adding the attribute or method of an object to the other in JavaScript.

Most mixin functions look like this:

Copy codeThe Code is as follows: function mixin (receiver, supplier ){
For (var property in supplier ){
If (supplier. hasOwnProperty (property )){
Receiver [property] = supplier [property];
}
}
}

In this mixin () function, a for loop traverses the properties of the supplier object and assigns a value to the receiver object. Almost all JavaScript libraries have some similar functions, allowing you to write such code:

Copy codeThe Code is as follows: mixin (object ,{
Name: "Nicolas ",

SayName: function (){
Console. log (this. name );
}
});

Object. sayName (); // outputs "Nicolas"

In this example, the object receives the property name and method sayName (). This works well in ECMAScript 3, but not so optimistic in ECMAScript 5.

This is my problem:

Copy codeThe Code is as follows: (function (){

// To be filled in later
Var name;

Mixin (object ,{
Get name (){
Return name;
}
});

// Let's just say this is later
Name = "Nicolas ";

}());

Console. log (object. name); // undefined

This example looks a bit pretentious, but it accurately describes the problem. The mixin attribute uses the new feature of ECMAScript 5: A getter attribute accesser. Getter references an uninitialized local variable name. Therefore, this attribute is undefined.

Later, the name is assigned a value so that the accessor getter can return a valid value. Unfortunately, object. name (the attribute of mixin) always returns undefined.

What's going on?

We carefully analyze the mixin () function. In fact, in loop statements, attributes are not re-assigned from one object to another. It actually creates an attribute with the same name, and assigns the returned value of the getter method of the supplier object to it. The target object does not obtain the getter method, but the return value of the getter method. @ Justjavac)

In this example, the mixin () process is actually like this:

Copy codeThe Code is as follows: receiver. name = supplier. name;

The property er. name is created and assigned the value of supplier. name. Of course, supplier. name has a getter method to return the value of the local variable name. In this case, the value of name is undefined, so the value stored by explorer. name is. There is no getter method created for javaser. name, so its value will never change.

To solve this problem, you need to use the attribute descriptor (: descriptor) to convert the attribute from an object mixin to another object. A pure version of ECMAScript 5 mixin () should be written as follows:

Copy codeThe Code is as follows: function mixin (receiver, supplier ){

Object. keys (supplier). forEach (function (value, property ){
Object. defineProperty (receiver, property, Object. getOwnPropertyDescriptor (supplier, property ));
});
}

In this new function, Object. keys () is used to obtain an array that contains all enumeration attributes of the supplier Object. Then, the foreach () method is used to traverse these attributes. Call Object. getOwnPropertyDescriptor () to obtain each attribute descriptor (descriptor) of the supplier Object ).

Because the descriptor (descriptor) contains all attribute information, including the getter and setter methods, this descriptor can be directly transmitted to the Object. defineProperty () is used to create the same attributes on the Explorer Object. Using this new version of mixin () can solve the previous problems and get the expected results. The getter method is correctly passed from supplier to receiver.

Of course, if you still need to support the old browser, then you need a function to fall back to ECMAScript 3:

Copy codeThe Code is as follows: function mixin (receiver, supplier ){
If (Object. keys ){
Object. keys (supplier). forEach (function (value, property ){
Object. defineProperty (receiver, property, Object. getOwnPropertyDescriptor (supplier, property ));
});
} Else {
For (var property in supplier ){
If (supplier. hasOwnProperty (property )){
Receiver [property] = supplier [property];
}
}
}
}

If you need to use a mixin () function, you must carefully check that it works normally in ECMAScript 5, especially the getter and setter methods. Otherwise, you will find yourself in the same mistake as me.

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.