2

我一直无法找到答案。JavaScript 中的对象有一个继承链;任何函数Function => Object的链是 ,is 的实例的链,以及TypeErrorisTypeError => Error => Object的链TypeError,奇怪的是,Function => Function => Object

除了直接构造函数之外,我还查找了如何使构造对象从另一个函数继承属性,期望得到的继承链是这样object => constructor => second function的,并且这是一个构造函数扩展另一个构造函数的方式。我找到的解决方案是<second function>.<call or apply>(this[, optional arguments...])在构造函数的主体内调用,但object instanceof <second function>最终返回false.

进一步的研究揭示了大多数使用类语法的答案 or Object.create,但这些都是新的,并且自 JavaScript 语言创建以来,一个“类”扩展了另一个在 JavaScript 中的“类”就已经存在,因此还有其他一些方法可以做到这一点。这些信息应该与 JavaScript 构造函数的基本解释一起提到,但事实并非如此。扩展“类”(不是实际的类语法)导致更深的继承链的主要方法是什么?

示例结果:

// Square is the subclass
// Rectangle is the superclass

var rectangle = new Rectangle(1, 1);
var square = new Square(1);

rectangle instanceof Rectangle; // true
rectangle instanceof Square; // false
square instanceof Rectangle; // true
square instanceof Square; // true
Square instanceof Rectangle; // true

错误的解决方案:

function F () {
    this.value = 0;
}

function G () {
    F.apply(this);
}

var f = new F();
var g = new G();

// g gets the same properties from F that f gets.
"value" in f; // true
"value" in g; // true

// But neither g nor G are instances of F.
g instanceof G; // true
g instanceof F; // false
G instanceof F; // false
4

2 回答 2

3

自从语言创建以来,一个“类”在 JavaScript 中扩展了另一个

不,它没有。JavaScript 从来都不是(现在仍然不是)基于类的语言。您拥有的唯一工具是.prototypenew

之前的“课程”是如何扩展的Object.create

基本上使用相同的方法。建立原型链的关键是

Subclass.prototype = Object.create(Superclass.prototype);

如果没有Object.create,人们只是使用创建该对象

Subclass.prototype = new Superclass;

请参阅如何从 javascript 中的类继承中的2010 年的答案?举些例子。
是的,这是一个坏主意,但它激增了。设计了不会执行超类构造函数的更好的解决方案,这就是Douglas Object.createCrockford推广的方式(另请参阅Crockford 的对象创建技术发生了什么?)。

于 2021-08-10T15:19:24.057 回答
0

所以我想我会在我的旧项目中的 javascript 中包含几个“扩展”示例,以防万一这是正在寻找的。

valueOf这是通过修改函数“扩展”所有对象的示例。首先它将内置.valueOf定义复制到新的函数/属性 -> ,然后在内置.originalvalueOf定义上添加我的自定义。.valueOf我这样做是为了让 JS 数字会抛出一个错误,比如 NaN 或除以零。如您所见,它是通过修改 来完成的Object.prototype,而我的 new.valueOf实际上是通过.originalvalueOf.

/*  ****    Object extensions    ****    

    Check for NaN and DivZeros
    (adapted from: https://stackoverflow.com/a/20535480/109122)
*/
 Object.prototype.originalValueOf = Object.prototype.valueOf;

 Object.prototype.valueOf = function() {

     if (typeof this == 'number') {
        if (!isFinite(this)) {throw new Error('Number is NaN or not Finite! (RBY)');}
     }

     return this.originalValueOf();
 }

// var a = 1 + 2; // -> works
// console.log(a); // -> 3

// var b = {};
// var c = b + 2; // -> will throw an Error

这是我的“类”的构造函数示例,名为 Pe2dSpatialState。请注意,我在这里添加了所有对象的字段:

// Constructor for Dynamic Spatial State
//( physical properties that change according to Newtonian Mechanics )
var Pe2dSpatialState = function(point2dPosition, 
                                point2dVelocity, 
                                point2dAcceleration, 
                                interval,
                                rotationDegrees,
                                rotationDegreesPerSec) {
    this.position = point2dPosition;            // position of this state
    this.velocity = point2dVelocity;            // velocity of this state
    this.acceleration = point2dAcceleration;    // acceleration to be applied
    
    this.interval = interval;                   // time to the next state

    this.rotationD = (rotationDegrees ? rotationDegrees : 0);
                                                // degrees rotated (because SVG uses degrees)
    this.rotationDPerSec = (rotationDegreesPerSec ? rotationDegreesPerSec : 0);
                                                // degrees per sec (because SVG uses degrees)
}

我通过原型给 Pe2dSpatialState 对象添加了函数:

Pe2dSpatialState.prototype.clone = function() {
    var tmp = new Pe2dSpatialState( this.position.clone(),
                                this.velocity.clone(),
                                (this.acceleration ? this.acceleration.clone() : undefined),
                                this.interval,
                                this.rotationD,
                                this.rotationDPerSec);
    return tmp;
}

然后我使用 Object.defineProperty 添加了获取/设置类型“属性”:

Object.defineProperty(Pe2dSpatialState.prototype, "rotationR", {
    get()  {return this.rotationD * Math.PI * 2 / 360;},
    set(v) {this.rotationD = v * 360 / (Math.PI * 2);}
});
Object.defineProperty(Pe2dSpatialState.prototype, "rotations", {
    get()  {return this.rotationD / 360;},
    set(v) {this.rotationD = v * 360;}
});

检查我的清单,我总是按以下顺序定义我的“类”:构造函数与字段,然后将函数/方法添加到原型,最后添加属性Object.defineProperty。只有在那之后,我才能在任何地方使用它。

我不记得为什么我以这三种不同的方式做每一件事,除了我经历了很多不同的尝试和迭代,这就是我最终为我工作的地方。(这在 ES6 下可能要容易得多)。

我还发现了一个非常复杂的函数,它可以列出任何对象的对象-函数-原型树,这对我弄清楚真正发生了什么以及什么会起作用非常有帮助。因为篇幅太长,我没有收录,如果你想看的话,我会放在这里。

(我不能保证这是最好的方法,也不能保证这段代码没有任何错误。事实上,现在看,我怀疑我的一些字段应该是属性......)

于 2021-08-11T13:48:36.537 回答