At the bottom of the knockoutjs docs for extending observables it states...
More than one extender can be applied in a single call to the .extend method of a
The order is undefined in the current Knockout (3.4.0 as of this writing), because JavaScript object properties had no defined order prior to ES2015, and even in ES2015, for-in
and Object.keys
have no order.
The current Knockout loops through those extenders like this:
function applyExtenders(requestedExtenders) {
var target = this;
if (requestedExtenders) {
ko.utils.objectForEach(requestedExtenders, function(key, value) {
var extenderHandler = ko.extenders[key];
if (typeof extenderHandler == 'function') {
target = extenderHandler(target, value) || target;
}
});
}
return target;
}
Its objectForEach
function uses for-in
:
function objectForEach(obj, action) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
action(prop, obj[prop]);
}
}
}
So, there is no defined order in which the extenders will run (even on ES2015) in the current Knockout.
In theory, a future version of Knockout could use the new Object.getOwnPropertyNames instead:
function applyExtenders(requestedExtenders) {
var target = this;
if (requestedExtenders) {
Object.getOwnPropertyNames(requestedExtenders).forEach(function(key) {
var extenderHandler = ko.extenders[key];
if (typeof extenderHandler == 'function') {
target = extenderHandler(target, requestedExtenders[key]) || target;
}
});
}
return target;
}
getOwnPropertyNames
respects the newly-defined order of JavaScript properties, listed in §9.1.12 of the spec. In your example, that would be required
, then logChange
, because object initializers create properties in lexical order, and the order of "own" properties with names that are not all-numeric and not Symbol
s is the order of creation (but see the spec for details).
If the order is important, you can call extend
multiple times:
this.firstName = ko.observable(first)
.extend({ required: "Please enter a first name" })
.extend({ logChange: "first name" });
That being said, browsers generally process an object's properties in the same order they were defined. Thus your original method will have the same effect as this one.