Inheritance with Knockout.js

2019-02-26 15:58发布

问题:

I have some code like this:

var A = function(a,b,c) {
  var self = this;
  self.a = ko.observable(a);
  ... 


  self.function1 = ko.computed(function () {
      dothing(a);
      ...
  } 

  self.function2 = ko.computed(function () {
      dothing(b);
      ...
  }
}

var B = function(a,b,c,d) {
    var self = this;
  self.a = ko.observable(a);
  ... 


  self.function1 = ko.computed(function () {
      dothing(a);
      ...
  } 

  self.function2 = ko.computed(function () {
      dothing(b);
      ...
  }
}

How can I "extract" function1 and function2 to a function that A and B can share?

回答1:

That's just where prototypes fit in:

function AB()
{};//empty object
AB.prototype.function1 = function()
{
    var self = this;//doesn't have access to self, but `this` will point to either A or B
    //do stuff
};
var A = function()
{
    var self = this;//constructor
}
var B = function()
{
    var self = this;//constructor
}
A.prototype = new AB;
A.prototype.constructor = A;
B.prototype = new AB;
B.prototype.constructor = B;
//marginally shorter:
A.prototype = B.prototype = new AB;
A.prototype.constructor = A;
B.prototype.constructor = B;
//instances:
var foo = new A();
var bar = new B();
console.log(foo.function1 === bar.function1);//logs true

Having said that, personally, I prefer to define my constructors regularly:

function A()
{
    var self = this;
}
foo = new A();
console.log(Object.getPrototypeOf(foo).constructor.name);//logs A

Whereas your code assigns an anonymous function to a variable, which means that the constructor doesn't have a name:

foo = new A();
console.log(Object.getPrototypeOf(foo).constructor.name);//logs ''

It's not that big of a deal, but just so you know...


Reference a method from the global (or any other) scope:

var virtualNewFunction = new A();//create object
virtualNewFunction = virtualNewFunction.function1;//virtualNewFunction now references function1
virtualNewFunction();

The closure will be accessible (exposed), still, but be very careful with this:

A = function()
{
    var self = this;
    this.function1 = function()
    {
        console.log(this);
        console.log(self);
    };
}
foo = new A();
foo.function1();//logs A twice
foo = foo.function1
foo();//logs this -> window! self => A

An other possibility is "borrowing" a function:

A = function()
{
    var self = this;
    this.function1 = function()
    {
        console.log(this);
        console.log(self);
    };
}
B = function()
{//no method
    var self = this;
}
foo = new A();
bar = new B();
foo.function1.apply(bar,[]);//call as though function1 was method of B

Again, be careful: in this case this logs B, but self still references A! You could build in certain "safety nets":

    this.function1 = function()
    {
        self = this !== window && this !== self ? this : self;//redefine self to current caller object, unless it's window 
        console.log(this);
        console.log(self);
    };

But honestly, you might do well reading up on the this operator to grasp all this referencing trickery. It's not that hard once you get the basics. Also check the call and apply methods for more details on how to "share/borrow" methods



回答2:

You could change the scope of the function by pulling it out of that object.

var function1 = function() {

}

var function2 = function() {

}

var A = function(a,b,c) {
  var self = this;
  self.a = ko.observable(a);
  ... 


  self.function1 = ko.computed(function1)

  self.function2 = ko.computed(function2)
}


回答3:

You could try using the underscore.js extend functionality to do the inheritance.



回答4:

    var AB=function(){
    self=this;
    self.function1=function(){
                   //----something------
                  }
    self.function1=function(){
                   //----something------
                  }

   }


     var A=function(){
     var self=this;
     AB.apply(self,arguments);
     } 

    var B=function(){
     var self=this;
     AB.apply(self,arguments);
        }