Home  >  Article  >  Web Front-end  >  Is your mixin really ECMAScript 5 compatible?_Basics

Is your mixin really ECMAScript 5 compatible?_Basics

WBOY
WBOYOriginal
2016-05-16 17:37:421103browse

I was recently working on a project with a client that needed to take full advantage of ECMAScript 5, and I encountered a very interesting problem. The problem stems from a very common pattern: mixins, which are mixing properties or methods of one object into another in JavaScript.

The functionality of most mixins looks like this:

Copy code The code is as follows:

function mixin(receiver, supplier) {
for (var property in supplier) {
                                                                                                                                                                                                                                                                            >

In this mixin() function, a for loop iterates over the properties of the supplier object and assigns them to the receiver object. Almost all JavaScript libraries have some form of similar functionality that allows you to write code like this:


Copy code

The code is as follows:mixin(object, { name: "Nicholas ", sayName: function() {
console.log(this.name);
}
});
object.sayName(); // outputs "Nicholas"




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

This is the problem I'm having:

Copy code

The 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 = "Nicholas";

}());

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


This example looks a bit contrived, but it accurately describes the problem. The properties that are mixed in use a new feature of ECMAScript 5: a getter property accessor. The getter refers to an uninitialized local variable name, so the property is undefined.

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

What’s going on?

Let’s analyze the mixin() function carefully. In fact, in the loop statement, the properties are not reassigned from one object to another object. It actually creates a property with the same name and assigns it the return value of the supplier object's accessor method getter. (Annotation: The target object does not get the getter method, but the return value of the getter method. @justjavac)

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

Copy code

The code is as follows:receiver.name = supplier.name;
The attribute receiver.name is created and assigned the value of supplier.name. Of course, supplier.name has a getter method that returns the value of the local variable name. At this time, the value of name is undefined, so receiver.name stores the value. There is no getter method created for receiver.name, so its value never changes.

To solve this problem, you need to use property descriptors (Annotation: descriptor) to mixin properties from one object to another. A pure ECMAScript 5 version of mixin() would look like this:

Copy code

The 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 version of the function, Object.keys() is used to obtain an array containing all enumeration properties of the supplier object. The foreach() method is then used to iterate over these properties. Call the Object.getOwnPropertyDescriptor() method to obtain each property descriptor (descriptor) of the supplier object.

Since the descriptor contains all property information, including getter and setter methods, the descriptor can be passed directly to Object.defineProperty() to create the same property on the receiver object. Using this new version of mixin(), you can solve the problems encountered earlier and get the results you expect. The getter method is correctly passed from supplier to receiver.

Of course, if you still need to support older browsers, then you'll need a function that falls back to ECMAScript 3:

Copy code The 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, be sure to double check that it works properly in ECMAScript 5, especially the getter and setter methods. Otherwise, you'll find yourself falling into mistakes like I did.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn