Adding a computed observable via the prototype to

2019-04-07 10:50发布

I'm using Knockout.js 2.0 and I'm trying to extend the prototype of the constructor function I've created by adding a computed observable but its throwing up "self.IsSubDomain is not a function". How do I solve this error? Is there another way to extend a constructor function to solve this?

http://jsfiddle.net/StrandedPirate/J44S4/3/

Note: I know I could define the computed observable inside the constructor function's closure but I'm building an automated code generator for knockout view models and I need to be able to extend my objects through the prototype property.

1条回答
Luminary・发光体
2楼-- · 2019-04-07 10:58

I also answered this in the forum.

Here's one way to do it (jsFiddle example):

<div data-bind="text: fullDomainName">test</div>
<script>
function SiteModel(rootUrl, data) {
    var self = this;
    self.rootUrl = rootUrl;
    self.DomainName = ko.observable(data.DomainName);
    self.IsSubDomain = ko.observable(data.IsSubDomain);
    self.fullDomainName = ko.computed(self.fullDomainName, self);
}

SiteModel.prototype.fullDomainName = function () {
    if (this.IsSubDomain() && this.DomainName()) { // bombs out here with "self.IsSubDomain is not a function"
        return this.DomainName() + ".myCompanyWebsite.com";
    }
    else {
        return this.DomainName();
   }
}; 

var temp = new SiteModel("someurl", { DomainName: "extraCool" });

ko.applyBindings(temp);
</script>

I've defined the function in the prototype and made it a computed observable in the constructor.

Here's a way to do it a more generic way (jsFiddle example):

<div data-bind="text: fullDomainName">test</div>
<script>
Function.prototype.computed = function() {
    this.isComputed = true;
    return this;
};
Object.prototype.makeComputeds = function() {
    for (var prop in this) {
        if (this[prop] && this[prop].isComputed) {
            this[prop] = ko.computed(this[prop], this, {deferEvaluation:true});
        }
    }
};

function SiteModel(rootUrl, data) {
    var self = this;
    self.rootUrl = rootUrl;
    self.DomainName = ko.observable(data.DomainName);
    self.IsSubDomain = ko.observable(data.IsSubDomain);
    self.makeComputeds();
}

SiteModel.prototype.fullDomainName = function () {
    if (this.IsSubDomain() && this.DomainName()) { // bombs out here with "self.IsSubDomain is not a function"
        return this.DomainName() + ".myCompanyWebsite.com";
    }
    else {
        return this.DomainName();
   }
}.computed();

var temp = new SiteModel("someurl", { DomainName: "extraCool" });

ko.applyBindings(temp);
</script>

The underlying read function of the computed will be shared via the prototype although the actual computed property won't. I suppose there could be confusion if you created some objects and then changed the function in the prototype. New objects would use the new function, but old objects wouldn't.

Since computed observables are properties, you shouldn't expect to be able to add them to existing objects through the prototype.

查看更多
登录 后发表回答