JavaScript 函数对象

发布于 2024-07-18 17:48:16 字数 5698 浏览 5 评论 0原文

我编辑了这个问题,使它更有意义。
我有一个需要几个参数的函数 - 我们称之为 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 的解决方案更新了我的代码。 我对 Jason Bunting 的非黑客解决方案感兴趣。 请记住,这些函数中的每一个也可以从其他函数和事件中调用。

从 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
}

I edited the question so it would make more sense.
I have a function that needs a couple arguments - let's call it fc(). I am passing that function as an argument through other functions (lets call them fa() and fb()). Each of the functions that fc() passes through add an argument to fc(). How do I pass fc() to each function without having to pass fc()'s arguments separately? Below is how I want it to work.

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

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

function fc(){
   doessomething with myvar and myothervar
}

Below is how I do it now. As I add arguments, it's getting confusing because I have to add them to preceding function(s) as well. fb() and fc() get used elsewhere and I am loosing some flexibility.

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
}

Thanks for your help


Edit 3 - The code

I updated my code using JimmyP's solution. I'd be interested in Jason Bunting's non-hack solution. Remember that each of these functions are also called from other functions and events.

From the HTML page

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

Set event handlers when section is loaded

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 event builds list

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
}

Create the list

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;
}

Position and size the list

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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

风铃鹿 2024-07-25 17:48:16

好吧,那么 - 从哪里开始呢? :) 这是开始的部分函数,​​你将需要这个(现在和将来,如果你花很多时间破解 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;

我没有看到您在任何其他代码中挂钩该 Container 属性。 除非你需要这条线,否则你应该能够摆脱它。

setDiv() 函数可以保持不变。


不太令人兴奋,但你明白了 - 你的代码确实需要一些清理 - 你是否避免使用像 jQuery 或 MochiKit 有充分的理由吗? 这会让你的生活变得更加轻松......

Okay, so - where to start? :) Here is the partial function to begin with, you will need this (now and in the future, if you spend a lot of time hacking 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);
  };
}

I see a lot of things about your code that make me cringe, but since I don't have time to really critique it, and you didn't ask for it, I will suggest the following if you want to rid yourself of the hack you are currently using, and a few other things:

The setDynamicSelectElements() function

In this function, you can change this line:

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

To this:

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

The selectList() function

In this function, you can get rid of this code where you are using eval - don't ever use eval unless you have a good reason to do so, it is very risky (go read up on it):

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

And use this instead:

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

Then, change this line:

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

To this:

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

Now, in that code I provided, I have "configureSelectListAlternate" - that is a function that is the same as "configureSelectList" but has the parameters in the reverse order - if you can reverse the order of the parameters to "configureSelectList" instead, do that, otherwise here is my version:

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

The configureSelectList() function

In this function, you can eliminate this line:

if(!fnOnClick) fnOnClick=configureSelectList.clickEvent

That isn't needed any longer. Now, I see something I don't understand:

if (!oDiv) oDiv = configureSelectList.Container;

I didn't see you hook that Container property on in any of the other code. Unless you need this line, you should be able to get rid of it.

The setDiv() function can stay the same.


Not too exciting, but you get the idea - your code really could use some cleanup - are you avoiding the use of a library like jQuery or MochiKit for a good reason? It would make your life a lot easier...

故事灯 2024-07-25 17:48:16

函数的属性不能作为局部作用域中的变量使用。 您必须将它们作为属性来访问。 因此,在“fc”中,您可以通过以下两种方式之一访问“myvar”:

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

都可以......

A function's properties are not available as variables in the local scope. You must access them as properties. So, within 'fc' you could access 'myvar' in one of two ways:

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

Either's fine...

别低头,皇冠会掉 2024-07-25 17:48:16

尝试继承 - 通过传递您的任何对象作为参数,您可以访问内部的任何变量,例如:

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 的形式,因此您可以访问内部的变量。

Try inheritance - by passing your whatever object as an argument, you gain access to whatever variables inside, like:

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 will take the form of myObj, so you can access the variables inside.

桃酥萝莉 2024-07-25 17:48:16

也许您正在寻找 < strong>部分函数应用,或者可能柯里化?

以下引用自关于差异的博客文章 :

部分应用程序采用一个函数,并从中构建一个采用较少参数的函数,而柯里化则通过组合每个采用单个参数的函数来构建采用多个参数的函数。

如果可能的话,如果您可以简化您的示例和/或提供实际的 JS 代码而不是伪代码,这将有助于我们帮助您。

Maybe you are looking for Partial Function Application, or possibly currying?

Here is a quote from a blog post on the difference:

Where partial application takes a function and from it builds a function which takes fewer arguments, currying builds functions which take multiple arguments by composition of functions which each take a single argument.

If possible, it would help us help you if you could simplify your example and/or provide actual JS code instead of pseudocode.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文