我使用John Resig's "Simple JavaScript Inheritance"创建一个可以继承的类。我也在使用KnockoutJS来计算可观察量。问题在于尝试将这两个概念结合起来。当我尝试在计算的observable中获得对self的引用时,我得到“Window”对象而不是预期的实际对象。这是一个快速代码示例:
window.mynamespace.myclass = Class.extend({
init: function() {
},
someProperty: ko.observable(10),
someComputedProperty: ko.computed(function() {
return this.someProperty();
}, this)
});
不幸的是找不到this.someProperty(),因为'this'是对Window的引用。有什么想法或想法吗?
答案 0 :(得分:2)
我从未有过使用KnockoutJS的经验。但是我非常精通JavaScript中的继承,我不赞成John Resig的“简单JavaScript继承”模式(主要是因为它没有私有变量)。相反,我更喜欢使用自己的class pattern。我想你可能会觉得有趣:
window.mynamespace.myclass = new Class(function (uber) {
var self = this;
function constructor() {
}
this.someProperty = ko.observable(10);
this.someComputedProperty = ko.computed(function () {
return self.someProperty();
});
return constructor;
});
您也可以使用自己的方法,只需跳过创建self
即可。由于该类不是从对象创建的,因此您可以在类定义中使用this
(在John Resig的“简单JavaScript继承”模式中无法做到的事情):
window.mynamespace.myclass = new Class(function (uber) {
function constructor() {
}
this.someProperty = ko.observable(10);
this.someComputedProperty = ko.computed(function () {
return self.someProperty();
}, this);
return constructor;
});
您也可以直接将方法添加到window.mynamespace.myclass.prototype
。这样,您可以返回self.someProperty()
而不是返回myclass.prototype.someProperty()
。如果您对我的班级模式有任何帮助,请随时问我。
修改强>
Class
构造函数有两个参数:函数定义类,可选 基类派生自。第一个参数(即函数)必须返回另一个函数,该函数是类的构造函数(类似于C ++或Java构造函数)。
让我们创建一个简单的Rectangle
类:
var Rectangle = new Class(function () {
// width and height are private variables
var width;
var height;
// the class constructor accepts two arguments
function constructor(length, breadth) {
// save the parameters
width = length;
height = breadth;
}
// area is a public function
this.area = function () {
// return the area of the rectangle
return width * height;
};
return constructor; // always remember to return the constructor
});
现在您可以创建类Rectangle
的实例,如此fiddle中所示。
现在让我们做一些更有趣的事情 - 继承。 Class
构造函数的第二个参数是派生自的基类。让我们创建一个类Square
,它派生自类Rectangle
。
// notice that the class definition function accepts a parameter called uber
var Square = new Class(function (uber) {
// return the constructor of the class Square
return function (side) {
// call the base class constructor - uber
uber(side, side);
};
}, Rectangle); // Square derives from Rectangle
这是事情变得有趣的地方。好的,我们在此类模式中有4种类型的数据成员:private
,public
,shared
和static
。我们已经看过私人和公共数据成员。
共享数据成员是在类的prototype
上定义的那些属性。它们由该类的所有实例共享。
静态数据成员是在类本身上定义的那些属性。它们不是由类的实例继承的。
在Square
派生自Rectangle
的上述示例中,它继承了Rectangle
的所有共享和静态数据成员。实际上,我们还可以在Rectangle
定义 Square
之后定义一个新的共享或静态数据成员,它仍将由Square
继承。让我们用一个例子演示这个概念:
alert(Square.staticDataMember); // staticDataMember is undefined
Rectangle.staticDataMember = "It works!"; // define staticDataMember on Rectangle
alert(Square.staticDataMember); // staticDataMember is inherited from Rectangle
以上是静态数据成员。让我们看一下共享数据成员的相同内容:
var square = new Square(5); // create an instance of Square
alert(square.sharedDataMember); // sharedDataMember is undefined
Rectangle.prototype.sharedDataMember = 0; // define sharedDataMember on Rectangle
alert(square.sharedDataMember); // sharedDataMember is inherited from Rectangle
您可以在以下fiddle中看到上述程序的输出。
这很酷,但私人和公共数据成员呢?他们是如何继承的?好吧,当我们创建一个新类时,私有和公共数据成员不会被继承。它们在创建类的新实例时继承。这是因为同一个类的不同实例具有不同的私有和公共数据成员。
当我们创建派生类的实例(如Square
)时,我们不会继承它的基类(即Rectangle
)的私有和公共数据成员,直到我们调用基类构造函数为止(即uber
)。只有当我们调用基类构造函数时,私有和公共数据成员才会被继承(实际上只有公共数据成员被继承 - 其他成员因为某种原因被称为私有):
var Square = new Class(function (uber) {
return function (side) {
alert(this.area); // area is undefined
uber(side, side); // inherit public members from an instance of Rectangle
alert(this.area); // area is now defined
};
}, Rectangle);
您可以在以下fiddle中看到上述程序的输出。
现在让我们为kicks创建另一个类,当我们在它时,我们还将展示多级继承:
var Cube = new Class(function (uber) {
var side; // the length of a side of the cube
function constructor() {
side = arguments[0]; // save the first argument passed to the constructor
uber = uber(side); // call the base constructor and save its instance
}
this.area = function () {
return 6 * uber.area(); // return the surface area of the cube
};
this.volume = function () {
return side * uber.area(); // return the volume of the cube
};
return constructor; // remember to return the constructor
}, Square); // derive from Square
这是新事物。在这里,我们创建了一个新的area
函数,area
Rectangle
uber
函数在uber
中定义,但是如果我们想从派生类中访问基类方法呢?
好吧,当我们调用基类构造函数(即area
)时,它返回基类的实例。由于我们不再需要基类构造函数,因此我们将实例保存为uber.area
。然后,我们可以使用area
调用基类volume
方法,如Class
和{{1}}函数中所示。
您可以在以下shadowed中看到上述程序的输出。
因此,你可能会发现这个类模式比John Resig的“简单JavaScript继承”模式更强大,{{1}}构造函数只有47行代码(没有缩小)。
答案 1 :(得分:1)
您可以随时在init
中添加它们。在knockout's own examples中,他们在构造函数中进行绑定。
window.mynamespace.myclass = Class.extend({
init: function() {
this.someProperty = ko.observable(10);
this.someComputedProperty = ko.computed(function() {
return this.someProperty();
}, this);
}
});
或者捕获对this
的引用并忘记绑定:
window.mynamespace.myclass = Class.extend({
init: function() {
var self = this;
self.someProperty = ko.observable(10);
self.someComputedProperty = ko.computed(function() {
return self.someProperty();
});
}
});
演示如何扩展课程:
window.mynamespace.myotherclass = window.mynamespace.myclass.extend({
init: function() {
// do anything myotherclass init, like another observable
this.someOtherProperty = ko.observable(10);
// incidentally you *can* have private variables with this pattern
var imPrivate = 1;
this.getImPrivate = function() {
return imPrivate;
};
// then call super (maybe with arguments, maybe just passing them)
this._super('foobar');
}
});