I recently worked on a project with a client that needs to be fully utilized by ECMAScript 5, where I met a very interesting question. The problem stems from a very common pattern: mixin, which mixin the attributes or methods of an object to another in JavaScript.
Most mixin features look like this:
Copy Code code 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 it to the receiver object. Almost all JavaScript libraries have some form of similar functionality that allows you to write code like this:
Copy Code code as follows:
Mixin (object, {
Name: "Nicholas",
Sayname:function () {
Console.log (this.name);
}
});
Object.sayname (); Outputs "Nicholas"
In this example, object objects receive the property name and Method Sayname (). This works well in ECMAScript 3, but not so optimistic on ECMAScript 5.
This is the problem I encountered:
Copy Code code as follows:
(function () {
To is 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 for mixin use the new feature of ECMAScript 5: A getter property accessor. The getter references an uninitialized local variable name, so this property does not define undefined.
Later, name is assigned a value so that the accessor getter can return a valid value. Unfortunately, Object.name (the mixin attribute) always returns to undefined.
What the hell is going on here?
We carefully analyze the mixin () function. In fact, in a loop statement, the attribute is not assigned to another object from one object. It actually creates an attribute with the same name and assigns the return value of the accessor method getter for the supplier object to it. The target object does not get the Getter method, but it gets the return value of the Getter method. @justjavac)
In this example, the process of mixin () is actually this:
Copy Code code as follows:
Receiver.name = Supplier.name;
The property Receiver.name is created and is assigned a value of Supplier.name. Of course, Supplier.name has a getter method to return the value of the local variable name. At this point, 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 the attribute descriptor (descriptor) to mixin attributes from one object to another. A pure ECMAScript 5 version of Mixin () should be written like this:
Copy Code code 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 this function, Object.keys () is used to get an array containing all the enumeration properties of the Supplier object. The foreach () method is then used to traverse these properties. Call the Object.getownpropertydescriptor () method to get each property descriptor (descriptor) of the Supplier object.
Because the descriptor (descriptor) contains all the property information, including the getter and setter methods, the descriptor (descriptor) can be passed directly to Object.defineproperty (), which is used to receiver object to create the same properties on the Using this new version of Mixin (), you can solve the problems you've encountered before and get the results you expect. The getter method is correctly passed from supplier to the receiver.
Of course, if you still need to support old browsers, then you'll need a function that falls back on the ECMAScript 3:
Copy Code code 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) {
&nbs p; if (supplier.hasownproperty) {
Receiver[property] = Supplier[property];
}
}
}
}
If you need to use a mixin () function, be sure to double-check that it works in ECMAScript 5, especially the getter and setter methods. Otherwise, you will find yourself in a mistake like mine.