Подтвердить что ты не робот

Полиморфизм наследования JQuery UI

Есть ли способ иметь полиморфизм в наследовании виджета в пользовательском интерфейсе jQuery?

Например, я хочу сделать что-то вроде:

$.widget('tr.fatherClass', {
  getValue: function() {
    return null;
  }
  ...
});
// sonClass1: extends from the father
$.widget('tr.sonClass1', $.tr.fatherClass, {
  getValue: function() {
    return this._fooFunction1();
  }
  ...
});
// sonClass2: extends from the father
$.widget('tr.sonClass2', $.tr.fatherClass, {
  getValue: function() {
    return this._fooFunction2();//
  }
  ...
});
// create an instance of a "sonClass"
$('#foo1').sonClass1(options);  
$('#foo2').sonClass2(options);  

Затем я хочу использовать метод getValue без знания имени класса son:

$('#foo1').fatherClass('getValue'); // run _fooFunction1() of sonClass1
$('#foo2').fatherClass('getValue'); // run _fooFunction2() of sonClass2

Но это невозможно:

jquery.js:250 Uncaught Error: cannot call methods on variable prior to initialization; attempted to call method 'getValue'

В форуме JQuery Скотт Гонсалес объясняет, что "Создание виджета создает только один виджет, а не каждый виджет в цепочке прототипов" ссылка

Есть ли способ обхода или решения, чтобы сделать это элегантным способом?

4b9b3361

Ответ 1

Вы можете сохранить fatherClass как элемент data для элемента с некоторым ключом, например fatherObject, он должен пойти в отце _create()...

$.widget('tr.fatherClass', {
  _create: function(){
    $(this.element).data( 'fatherObject', $.tr.fatherClass.prototype );
  },
  ...
};

И позже получить значения, используя...

$('#foo').data('fatherObject').getValue()

или

$('#bar').data('fatherObject').getValue()

$.widget('tr.fatherClass', {
  _create: function(){
    $(this.element).data( 'fatherObject', $.tr.fatherClass.prototype );
  },
  getValue: function() {
    return 'yellow'; // Father likes yellow
  }
});

// extends from the father
$.widget('tr.sonClass', $.tr.fatherClass, {
  getValue: function() {
    return 'blue'; // Son likes blue
  }
});

// extends from the father
$.widget('tr.daughterClass', $.tr.fatherClass, {
  getValue: function() {
    return 'pink'; // Daughter likes pink
  }
});

// This is son
$('#foo').sonClass();

// This is daughter
$('#bar').daughterClass();

// Son fav color
console.log( $('#foo').sonClass('getValue') );

// Son FATHER fav color
console.log( $('#bar').data('fatherObject').getValue() );

// Daughter fav color
console.log( $('#bar').daughterClass('getValue') );

// Daughter FATHER fav color
console.log( $('#bar').data('fatherObject').getValue() );
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id='foo'></div>
<div id='bar'></div>

Ответ 2

В OOD важно поддерживать композицию над наследованием. Но если вы все еще хотите полиморфизм, вместо переключения плагинов вы можете создать функцию в качестве переменной плагина, которую вы можете перезаписать в логике вашего приложения.

Пример:

$.widget('myWidget', {
    getValue: function() {
      if(userfunc != null)
         return userfunc();
      return null;
   }
   userfunc: null
  });

а затем вы можете создавать разные версии для userfunc

userfunc1 = function(){  return 43; }
userfunc2 = function(){  return 38; }

$('#foo').myWidget({userfunc : userfunc1})
value = $('#foo').myWidget('getValue') <= returns 47

$('#foo').myWidget({userfunc : userfunc2})
value = $('#foo').myWidget('getValue') <= returns 38

Надеюсь, что это поможет

Ответ 3

Нет способа доступа к написанным родительским методам извне объявления виджета, но если вы сами написали sonClass, вы можете вызвать тот же метод из родителя с помощью this._super(), реализация в вашем sonClass будет выглядеть что-то вроде этого...

// extends from the father
$.widget('tr.sonClass', $.tr.fatherClass, {
  getValue: function( fromFather ) {
    if ( 'father' == fromFather ) { // If 'father' is passed as argument
      return this._super(); // Get the result from father method
    } else {
      return this._$input.val();
    }
  }
  ...
});

Вы можете вызвать метод от отца, как это...

console.log( $('#foo').sonClass('getValue', 'father') );

Для справки
http://api.jqueryui.com/jQuery.widget/#method-_super

UPDATE

Мы добавляем новый метод fathersMethod к отцу, который возвращает результаты от отца...

$.widget('tr.fatherClass', {
  //Add this to father to get properties from father
  fathersMethod: function(prop) {
    if ( typeof $.tr.fatherClass.prototype[prop] == 'function' )
    return $.tr.fatherClass.prototype[prop]();
  },
  getValue: function() {
    return 'yellow'; // Father likes yellow
  },
  ...
  ...
  ...
});

Теперь для любого сына (или дочери), который наследует от отца... может вызвать отцовские методы, подобные этому...

$('#foo').sonClass('fathersMethod', 'getValue');

Здесь обновленный фрагмент; -)

$.widget('tr.fatherClass', {
  fathersMethod: function(prop) {
    if ( typeof $.tr.fatherClass.prototype[prop] == 'function' )
    return $.tr.fatherClass.prototype[prop]();
  },
  getValue: function() {
    return 'yellow'; // Father likes yellow
  }
});

// extends from the father
$.widget('tr.sonClass', $.tr.fatherClass, {
  getValue: function() {
    return 'blue'; // Son likes blue
  }
});

// extends from the father
$.widget('tr.daughterClass', $.tr.fatherClass, {
  getValue: function() {
    return 'pink'; // Daughter likes pink
  }
});

// This is son
$('#foo').sonClass();

// This is daughter
$('#bar').daughterClass();

// Son fav color
console.log( $('#foo').sonClass('getValue') );

// Son FATHER fav color
console.log( $('#foo').sonClass('fathersMethod', 'getValue') );

// Daughter fav color
console.log( $('#bar').daughterClass('getValue') );

// Daughter FATHER fav color
console.log( $('#bar').daughterClass('fathersMethod', 'getValue') );
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id='foo'></div>
<div id='bar'></div>

Ответ 4

Обычно то, что вы называете здесь полиморфизмом, - это стандартное наследование и поведение экземпляров.

$('#foo1').sonClass1(options);  
$('#foo2').sonClass2(options);  

создает два отдельных экземпляра класса.

foo1.getValue выполнит созданные классы, здесь sonClass1, getValue defintion (кодовый блок), который является fooFunction1.

foo2.getValue выполнит определение instantiatedclass, здесь sonClass2, getValue (кодовый блок), который является fooFunction2.

Более поздние звонки здесь

$('#foo1').fatherClass('getValue'); // run _fooFunction1() of sonClass1
$('#foo2').fatherClass('getValue'); // run _fooFunction2() of sonClass2

- это вызовы не для определения метода sonClass1 или sonClass2 getValue, а для метода fatherClass.

Обычно вы ожидаете в обоих случаях, если используется метод def getValue для отца.

Однако ваша ошибка говорит undefined.

Я не использую JQuery, но я подозреваю, что механизм наследования не создает экземпляр родительского класса.

Все мы, которые использовали js, столкнулись с этой проблемой и решили ее различными способами.