【问题标题】:jQuery Iteration FunctionsjQuery 迭代函数
【发布时间】:2014-02-07 00:42:54
【问题描述】:

each 这样的 jQuery 迭代器函数的语法类似于:

.each(function(index, element))

这似乎意味着与此声明匹配的函数必须采用 2 个参数。比如:

function my_func(index, element){
  alert(index+":"+element);
}

对我来说,这给出了 2 个可能的声明:

$("li").each(my_func);

$("li").each(function(index, element) {alert(index+":"+element);});

第一个让我感到困惑,因为我没有看到 indexelement 传递给 my_func。 jQuery 中是否有一些魔术知道 my_func 采用 each 提供的 2 个参数?

其次,如果我声明了

var my_func= function(index, element){
  alert(index+":"+element);
}

这会改变什么吗?我的理解是第一个是Declarative,第二个是Expressive,但是,在这种情况下,他们应该表现得一样吗?

最后,我看到的大多数 each 实现都是这样的:

$("li").each(function(){alert(this)});

each 回调的所有参数都是可选的吗?

【问题讨论】:

  • 您不会“看到”在任何一种情况下传递的参数。您传递的函数在集合中的每个项目内部调用,并且是传递参数的内部代码。如果函数首先存储在变量中,则没有任何区别。

标签: javascript jquery function expression declarative


【解决方案1】:

将函数作为回调传递的方法

在这个:

$("li").each(my_func);

您只是将my_func 的引用传递给.each() 方法。每个方法本身在调用它时会将两个参数传递给该函数。如果您想访问这两个参数,那么您可以在您自己的my_func 定义中将它们声明为参数,但您不必这样做。不管你声明与否,参数都会在那里。

您可以通过多种不同的方式声明 my_func:

// somewhat normal way and you can easily access the index and element arguments
function my_func(index, element) {
     // code here
}

// if you don't need index and element, you don't need to declare them
// but they are still actually there and can be reached via the arguments object
function my_func() {
     // code here
     console.log(arguments[0]);   // index
}

var声明函数

两者的区别:

var my_func= function(index, element){
  alert(index+":"+element);
}

function my_func(index, element){
  alert(index+":"+element);
}

很大程度上是时机之一。在第二个中,my_func 被定义为一个函数,只要它所在的 javascript 文件被定位和解析,并且它所定义的范围变得活跃并且“好像”它是在最顶部声明​​的一样可用定义它的范围。这通常称为“提升”,其中定义被提升到定义它的范围的顶部。

首先,my_func 不是一个函数,直到该行 JS 在该 javascript 文件的正常执行流程中执行。

除了时间之外,您几乎可以互换使用这两者。如果个人更喜欢 function xxx() 表单,因为我不必担心函数在声明运行之前是否被调用 - 但这确实是个人风格偏好。


你必须声明回调参数吗

对于你的最后一个问题,如果你想使用它们,你只需要声明你的回调参数。在 javascript 中,无论您是否使用参数声明一个函数(在 C++ 等语言中并非如此),函数都是完全相同的函数,因此您只需在要按名称访问它们时声明它们。

javascript 中的函数参数声明是可选的。您可以声明多于传递给函数的内容,也可以声明少于传递给函数的内容。两者都不会导致 javascript 出现任何类型的错误。

假设你有这个代码:

 function callWithDelay(t, fn, arg1, arg2) {
     setTimeout(function() {
         fn(arg1, arg2);
     }, t);
 }

使用它的预期方法是定义一个接受两个参数并将其作为fn 参数传递的函数。

 function myFunc(msg, color) {
     var obj = document.getElementById("error")
     obj.innerHTML = msg;
     obj.style.color = color;
 }

 callWithDelay(2000, myFunc, "Both first and last name are required", "red");

但是,您不必传递具有这些参数的函数。您可以这样做(通过arguments 对象而不是名称访问参数):

 function myFunc() {
     var obj = document.getElementById("error")
     obj.innerHTML = arguments[0];
     obj.style.color = arguments[1];
 }

 callWithDelay(2000, myFunc, "Both first and last name are required", "red");

或者,您可以传递一个甚至不需要这些参数的函数:

 function myFunc() {
     document.getElementById("error").style.display = "none";
 }

 callWithDelay(2000, myFunc);

callWithDelay 函数并不关心你传递给它的是什么类型的函数引用。它实际上可以是任何功能。 callWithDelay 函数会将两个参数传递给调用它时传递给它的回调,但它是否使用这些参数完全取决于接收函数。在最后一个示例中,我在调用 callWithDelay 时省略了最后两个参数。当您省略一个参数时(在调用列表的末尾),该参数就是undefined。在 javascript 中,undefined 是一个合法值。因此,当我将它们从对callWithDelay(2000, myFunc) 的调用中删除时,它们是undefined,因此undefined 是作为其两个参数传递给myFunc 回调的内容。在这种情况下,由于没有使用这些参数,因此没有人关心它们是 undefined


函数重载 - 检查传递了哪些类型的参数

在 javascript 中,您还可以检查传递给函数的参数类型并相应地调整您的行为。例如,假设您有一个隐藏 DOM 元素的简单函数:

function hide(elem) {
    elem.style.display = "none";
}

// usage
var obj = document.getElementById("test");
hide(obj);

这个函数假定 elem 是一个 DOM 元素,并且只有当它被传递时才会起作用。但是,如果我们还想允许某人传递一个元素的 id 怎么办。我们可以检查传递给 hide 的参数,看看它是否是一个字符串,如果是,我们可以将它视为一个 id 值。

function hide(elem) {
    // if a string was passed, find the DOM object using that string as an id
    if (typeof elem === "string") {
        elem = document.getElementById(elem);
    }
    elem.style.display = "none";
}

// first usage
var obj = document.getElementById("test1");
hide(obj);

// second uage
hide("test2");

现在,假设我们希望不仅允许传递单个 DOM 元素,还允许传递一个 DOM 元素数组,以便函数对数组中的每个 DOM 元素进行操作。

function hide(elem) {
    // if a string was passed, find the DOM object using that string as an id
    if (typeof elem === "string") {
        document.getElementById(elem).style.display = "none";
    } else if (typeof elem === "object" && Object.prototype.toString.call(elem) === "[object Array]") {
        // an array was passed
        for (var i = 0; i < elem.length; i++) {
            elem[i].style.display = "none";
        }
    } else {
        // only a single DOM element was passed
        elem.style.display = "none";
    }
}

// usages
hide(obj);
hide([obj1, obj2, obj3]);
hide("test");

【讨论】:

  • 我假设当您声明“my_func”变量时,它也是作用域的——而不是本质上是全局的。对吗?
  • @drew_w - 是的,var my_func = function() {} 仅存在于声明它的范围内,但对于定义函数的另一种方式也是如此。函数可以在其他函数中定义,然后它们的范围仅限于该函数中。这两种方法的范围没有真正的区别。
  • @jfriend00 感谢您的精彩回答。您能否详细说明“无论您是否使用参数声明函数都是完全相同的函数”位?我的脑子里更多的是 Java/C 世界,我不太明白这意味着什么。
  • @TylerDeWitt - 我在答案末尾添加了更多关于“完全相同的功能”的信息。
  • @jfriend00 这现在更有意义了!再次感谢您的出色回答。我会给你一个赏金,但看起来你的积分比我多:)
猜你喜欢
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 2010-12-14
  • 2018-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多