Объекты функций Javascript - PullRequest
0 голосов
/ 01 мая 2009

Я отредактировал вопрос, чтобы он стал более понятным.
У меня есть функция, которая нуждается в паре аргументов - давайте назовем ее fc(). Я передаю эту функцию в качестве аргумента через другие функции (давайте назовем их fa() и fb()). Каждая из функций, через которые проходит fc(), добавляет аргумент к fc(). Как передать fc() каждой функции без необходимости передавать аргументы fc() отдельно? Ниже я хочу, чтобы это работало.

function fa(fc){
   fc.myvar=something
   fb(fc)
}

function fb(fc){
   fc.myothervar=something
   fc()
}

function fc(){
   doessomething with myvar and myothervar
}

Ниже, как я это делаю сейчас. Когда я добавляю аргументы, это сбивает с толку, потому что я должен добавить их и к предыдущим функциям. fb() и fc() привыкают в другом месте, и я теряю некоторую гибкость.

function fa(fc){
   myvar=something
   fb(fc,myvar)
}

function fb(fc,myvar){
   myothervar=something
   fc(myvar,myothervar)
}

function fc(myvar,myothervar){
   doessomething with myvar and myothervar
}

Спасибо за вашу помощь


Редактировать 3 - Код

Я обновил свой код, используя решение JimmyP. Я был бы заинтересован в нехакерском решении Джейсона Бантинга. Помните, что каждая из этих функций также вызывается из других функций и событий.

со страницы HTML

<input type="text" class="right" dynamicSelect="../selectLists/otherchargetype.aspx,null,calcSalesTax"/>

Установка обработчиков событий при загрузке раздела

function setDynamicSelectElements(oSet) {
    /**************************************************************************************
    * Sets the event handlers for inputs with dynamic selects
    **************************************************************************************/
    if (oSet.dynamicSelect) {
        var ySelectArgs = oSet.dynamicSelect.split(',');
        with (oSet) {
            onkeyup = function() { findListItem(this); };
            onclick = function() { selectList(ySelectArgs[0], ySelectArgs[1], ySelectArgs[2]) }
        }
    }
}

onclick список построений событий

function selectList(sListName, sQuery, fnFollowing) {
    /**************************************************************************************
    * Build a dynamic select list and set each of the events for the table elements
    **************************************************************************************/
    if (fnFollowing) {
        fnFollowing = eval(fnFollowing)//sent text function name, eval to a function
        configureSelectList.clickEvent = fnFollowing
    }
    var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', configureSelectList); //create the div in the right place
    var oSelected = event.srcElement;
    if (oSelected.value) findListItem(oSelected)//highlight the selected item
}

Создать список

function setDiv(sPageName, sQuery, sClassName, fnBeforeAppend) {
    /**************************************************************************************
    * Creates a div and places a page in it.
    **************************************************************************************/
    var oSelected = event.srcElement;
    var sCursor = oSelected.style.cursor; //remember this for later
    var coords = getElementCoords(oSelected);
    var iBorder = makeNumeric(getStyle(oSelected, 'border-width'))
    var oParent = oSelected.parentNode

    if (!oParent.id) oParent.id = sAutoGenIdPrefix + randomNumber()//create an ID
    var oDiv = document.getElementById(oParent.id + sWindowIdSuffix)//see if the div already exists
    if (!oDiv) {//if not create it and set an id we can use to find it later
        oDiv = document.createElement('DIV')
        oDiv.id = oParent.id + sWindowIdSuffix//give the child an id so we can reference it later    
        oSelected.style.cursor = 'wait'//until the thing is loaded
        oDiv.className = sClassName
        oDiv.style.pixelLeft = coords.x + (iBorder * 2)
        oDiv.style.pixelTop = (coords.y + coords.h + (iBorder * 2))
        XmlHttpPage(sPageName, oDiv, sQuery)
        if (fnBeforeAppend) {
            fnBeforeAppend(oDiv)
        }
        oParent.appendChild(oDiv)
        oSelected.style.cursor = ''//until the thing is loaded//once it's loaded, set the cursor back
        oDiv.style.cursor = ''
    }
    return oDiv;
}

Расположение и размер списка

function configureSelectList(oDiv, fnOnClick) {
    /**************************************************************************************
    * Build a dynamic select list and set each of the events for the table elements
    * Created in one place and moved to another so that sizing based on the cell width can
    * occur without being affected by stylesheet cascades
    **************************************************************************************/
    if(!fnOnClick) fnOnClick=configureSelectList.clickEvent
    if (!oDiv) oDiv = configureSelectList.Container;
    var oTable = getDecendant('TABLE', oDiv)
    document.getElementsByTagName('TABLE')[0].rows[0].cells[0].appendChild(oDiv)//append to the doc so we are style free, then move it later
    if (oTable) {
        for (iRow = 0; iRow < oTable.rows.length; iRow++) {
            var oRow = oTable.rows[iRow]
            oRow.onmouseover = function() { highlightSelection(this) };
            oRow.onmouseout = function() { highlightSelection(this) };
            oRow.style.cursor = 'hand';
            oRow.onclick = function() { closeSelectList(0); fnOnClick ? fnOnClick() : null };
            oRow.cells[0].style.whiteSpace = 'nowrap'
        }
    } else {
        //show some kind of error
    }
    oDiv.style.width = (oTable.offsetWidth + 20) + "px"; //no horiz scroll bars please
    oTable.mouseout = function() { closeSelectList(500) };
    if (oDiv.firstChild.offsetHeight < oDiv.offsetHeight) oDiv.style.height = oDiv.firstChild.offsetHeight//make sure the list is not too big for a few of items
}

Ответы [ 4 ]

2 голосов
/ 02 мая 2009

Хорошо, так - с чего начать? :) Вот частичная функция для начала, она вам понадобится (сейчас и в будущем, если вы тратите много времени на взлом JavaScript):

function partial(func /*, 0..n args */) {
  var args = Array.prototype.slice.call(arguments, 1);
  return function() {
    var allArguments = args.concat(Array.prototype.slice.call(arguments));
    return func.apply(this, allArguments);
  };
}

Я вижу много вещей в вашем коде, которые заставляют меня съеживаться, но, поскольку у меня нет времени, чтобы действительно его критиковать, а вы не просили об этом, я предложу следующее, если вы хотите избавиться от себя. о хаке, которым вы сейчас пользуетесь, и о нескольких других вещах:

Функция setDynamicSelectElements ()

В этой функции вы можете изменить эту строку:

onclick = function() { selectList(ySelectArgs[0], ySelectArgs[1], ySelectArgs[2]) }

К этому:

onclick = function() { selectList.apply(null, ySelectArgs); }

Функция selectList ()

В этой функции вы можете избавиться от этого кода там, где вы используете eval - никогда не используйте eval, если у вас нет веских причин для этого, это очень рискованно (прочитайте об этом):

if (fnFollowing) {
   fnFollowing = eval(fnFollowing)
   configureSelectList.clickEvent = fnFollowing
}

И используйте это вместо:

if(fnFollowing) {
   fnFollowing = window[fnFollowing]; //this will find the function in the global scope
}

Затем измените эту строку:

var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', configureSelectList);

На это:

var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', partial(configureSelectListAlternate, fnFollowing));

Теперь, в этом коде, который я предоставил, у меня есть «configureSelectListAlternate» - это функция, которая аналогична «configureSelectList», но имеет параметры в обратном порядке - если вы можете изменить порядок параметров на «configureSelectList» вместо этого сделайте это, иначе вот моя версия:

function configureSelectListAlternate(fnOnClick, oDiv) {
   configureSelectList(oDiv, fnOnClick);
}

Функция configureSelectList ()

В этой функции вы можете исключить эту строку:

if(!fnOnClick) fnOnClick=configureSelectList.clickEvent

Это больше не нужно. Теперь я вижу то, чего не понимаю:

if (!oDiv) oDiv = configureSelectList.Container;

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

Функция setDiv () может оставаться прежней.


Не слишком захватывающе, но вы поняли - ваш код действительно может использовать некоторую очистку - вы избегаете использования библиотеки, такой как jQuery или MochiKit по уважительной причине? Это сделало бы вашу жизнь намного проще ...

1 голос
/ 01 мая 2009

Свойства функции недоступны как переменные в локальной области видимости. Вы должны получить к ним доступ как свойства. Таким образом, в «fc» вы можете получить доступ к «myvar» одним из двух способов:

// #1
arguments.callee.myvar;
// #2
fc.myvar;

Либо в порядке ...

0 голосов
/ 02 мая 2009

Попробуйте наследование - передав любой объект в качестве аргумента, вы получите доступ к любым переменным внутри, например:

function Obj (iString) { // Base object
    this.string = iString;
}
var myObj = new Obj ("text");

function InheritedObj (objInstance) { // Object with Obj vars
    this.subObj = objInstance;
}
var myInheritedObj = new InheritedObj (myObj);

var myVar = myInheritedObj.subObj.string;
document.write (myVar);

subObj примет форму myObj, так что вы сможете получить доступ к переменным внутри.

0 голосов
/ 01 мая 2009

Может быть, вы ищете Приложение с частичной функцией или, возможно, карри?

Вот цитата из сообщения в блоге о разнице :

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

Если возможно, это поможет нам, если вы упростите свой пример и / или предоставите реальный код JS вместо псевдокода.

...