在Javascript

时间:2018-02-27 20:25:01

标签: javascript subclass

我正在尝试创建image library on github called Jimp的子类。据我所知,你不会以通常的方式实例化这个类。似乎该类有一个名为new Jimp()的静态方法,而不是说read,它充当构造函数。来自文档...

Jimp.read("./path/to/image.jpg").then(function (image) {
    // do stuff with the image
}).catch(function (err) {
    // handle an exception
});

从文档中可以看出,image返回的read()是允许调用者执行image.resize( w, h[, mode] );等内容的实例。

我想允许我的子类调用者以一个不同的静态方法开始,该方法读取一个图像并做一堆东西,总结如下......

class MyJimpSubclass extends Jimp {

    static makeAnImageAndDoSomeStuff(params) {
        let image = null;
        // read in a blank image and change it
        return Jimp.read("./lib/base.png").then(_image => {
            console.log(`image is ${_image}`);
            image = _image;
            let foo = image.bar();  // PROBLEM!
            // ...
            // ...
        .then(() => image);
    }

    bar() {
        // an instance method I wish to add to the subclass
    }

// caller
MyJimpSubclass.makeAnImageAndDoSomeStuff(params).then(image => {
    //...
});

您可能会猜到nodejs在let foo = image.bar();行上生气,说

  

TypeError image.bar不是函数

我认为这是可以理解的,因为我使用Jimp.read()获得了该图像。当然,这不会返回我的子类的实例。

  1. 第一个想法:将其更改为MyJimpSubclass.read()。同样的问题。
  2. 第二个想法:实现我自己的静态读取方法。同样的问题。

    static read(params) {
        return super.read(params);
    }
    
  3. 第三个想法:问SO

3 个答案:

答案 0 :(得分:1)

implementation of Jimp.read具体指Jimp,所以你必须在你的子类中复制和更改它(ick,但不会破坏任何东西,因为构造函数也是API的一部分)或者发出pull请求将其更改为this并明确支持子类:

static read(src) {
    return new Promise((resolve, reject) => {
        void new this(src, (err, image) => {
            if (err) reject(err);
            else resolve(image);
        });
    });
}

或者,您可以将所有功能实现为模块上的一组功能。在发出拉取请求后,这将是我的列表中的下一个。不推荐代理。

const makeAnImageAndDoSomeStuff = (params) =>
    Jimp.read("./lib/base.png").then(image => {
        console.log(`image is ${image}`);
        let foo = bar(image);
        // …
        return image;
    });

function bar(image) {
    // …
}

module.exports = {
    makeAnImageAndDoSomeStuff,
    bar,
};

即使更改原型也会比代理更好(但这只是第一个选项的更糟糕的版本,重新实现read):

static read(src) {
    return super.read(src)
        .then(image => {
            Object.setPrototypeOf(image, this.prototype);
            return image;
        });
}

答案 1 :(得分:1)

你有几个选择。最干净的可能是创建一个像你一样的子类,但是然后在它上面实现Jimp静态方法,以及你自己的方法。在这种情况下,它不是真正的继承,所以不要使用extends

class MyJimp {
  static read(...args) {
    return Jimp.read.apply(Jimp, args);
  }

  static makeAnImage(params) {
    return this.read(params)
      .then(image => {
        // do stuff
        return image
      });
  }
}

从那里开始,我会创建一个包含所有要应用于image的新函数的对象:

const JimpImageExtension = {
  bar: () => { /* do something */ }
};

最后,在静态方法中,获取图片并使用Object.assign()将新功能应用于其中:

class MyJimp {
  static read(...args) {
    return Jimp.read.apply(Jimp, args)
      .then(image => Object.assign(image, JimpImageExtension));
  }

  static makeAnImage(params) {
    return this.read(params)
      .then(image => {
        // do stuff
        image.bar();
        return image;
      });
  }
}

这应该通过将额外的功能应用于图像来实现。您只需要确保在每个可以生成图像的点上应用它(如果不仅仅是read)。因为在其他函数中,它使用的是read()版本,所以只需要在一个函数中添加函数。

另一种方法是如果Jimp使他们的图像类可访问,你也可以将它们添加到它的原型中(虽然通常在像这样的库中,该类经常是不可访问的或根本不是一个类)

答案 2 :(得分:1)

这可能是一种方法。从您自己的<div class="form-group"> <select class="selectpicker search-fields" id="ct" name="ct" data-live-search="true" data-live-search-placeholder="Search value" style='z-index:999 !important'> <option value="">Contract Types</option> @foreach (\App\ContractType::all() as $ct) <option value="{{ $ct->id }}">{{ $ct->type }}</option> @endforeach </select> </div> 方法开始,让它更改返回对象的原型。

read