Наследование прототипа jQuery частично терпит неудачу - PullRequest
4 голосов
/ 25 ноября 2011

Я хочу использовать Coffeescript для создания класса UIObject. Этот класс должен наследоваться от jQuery, чтобы экземпляры UIObject можно было использовать так, как если бы они были созданы с помощью jQuery.

class UIObject

  isObject: (val) -> typeof val is "object"

  constructor: (tag, attributes) ->
    @merge jQuery(tag, attributes), this
    @UIObjectProperties = {}

  merge: (source, destination) ->
    for key of source
      if destination[key] is undefined
        destination[key] = source[key]
      else if @isObject(source[key])
        @merge(source[key], destination[key])
    return

Это частично работает. Рассмотрим класс Foobar ниже:

class Foobar extends UIObject
  constructor: -> super("<h1/>", html: "Foobar")

$("body").append(new Foobar) отлично работает. НО: (новый Foobar) .appendTo ("body") размещает тег, но также вызывает RangeError: Maximum call stack size exceeded.

Было ли плохой идеей наследовать от jQuery? Или есть солурион?

Для тех, кто не знает CoffeeScript, источник JavaScript:

    var Foobar, UIObject;
    var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
        for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
        function ctor() { this.constructor = child; }
        ctor.prototype = parent.prototype;
        child.prototype = new ctor;
        child.__super__ = parent.prototype;
        return child;
    };

UIObject = (function () {
    UIObject.prototype.isObject = function (val) {
        return typeof val === "object";
    };

    function UIObject(tag, attributes) {
        this.merge(jQuery(tag, attributes), this);
        this.UIObjectProperties = {};
    }

    UIObject.prototype.merge = function (source, destination) {
        var key;

        for (key in source) {
            if (destination[key] === void 0) {
                destination[key] = source[key];
            } else if (this.isObject(source[key])) {
                this.merge(source[key], destination[key]);
            }
        }
    };

    return UIObject;
})();

Foobar = (function () {
    __extends(Foobar, UIObject);

    function Foobar() {
        Foobar.__super__.constructor.call(this, "<h1/>", {
            html: "Foobar"
        });
    }

  return Foobar;
})();

1 Ответ

0 голосов
/ 25 ноября 2011

Это действительно немного сложно достичь (но творчески!), Так как классы jQuery и CoffeeScript имеют свои представления о методе .constructor().

В jQuery 1.6.4 (который используется сегодня на домашней странице CoffeeScript) бесконечная рекурсия создается в строке 246 самого jQuery, в этой строке кода:

var ret = this.constructor();

this здесь указывает на ваш конструктор, но jQuery ожидает, что он будет указывать на себя. Ваш @merge() метод не заменяет конструктор правильно. Есть еще более хакерский выход, измените ваш @merge() метод на:

merge: (source, destination) ->
  for key of source
    if destination[key] is undefined
      destination[key] = source[key]
    else if @isObject(source[key])
      @merge(source[key], destination[key])
  @constructor = jQuery

Случайное тестирование в «Попробуйте coffeescript» показало, что оно работает, но я бы опасался, что странные эффекты могут проявиться позже, поэтому, если вы продолжите использовать этот подход, протестируйте его тщательно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...