【问题标题】:Cleanest workaround for incrementing function parameters递增函数参数的最简洁的解决方法
【发布时间】:2016-12-04 23:15:31
【问题描述】:

我正在尝试创建一个函数,每次运行时都会增加其参数。你总是可以手动重写函数,但我将多次运行这个函数,希望能够方便地重用代码。

$("div").each(function() {

    function rangeF(firstValue, increment) {

      var first = firstValue + "-"; //Set the first value and put a hypen after it
      firstValue += increment; //Increment it by the increment
      var second = firstValue; //Set the second value
      firstValue++; //Increment by one to avoid duplicates

      return first + second; //return both values (e.g. 1-2 or x-y)
    }

    range = rangeF(5 , 10); //5 is the value to start on, 10 + 1 is the increment (need to access both 5 + 10 & 5 + 11)
    range2 = rangeF(2, 2); //2 is the value to start on, 2 + 1 is the increment (need to access both 2 + 2 & 2 + 3)

    $(this)
    .append('<div>' + range + '</div>')
    .append('<div>' + range2 + '</div>');
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

#1 range: <div></div>
<br />
#2 range: <div></div>
<br />
#3 range: <div></div>

现在,它正在显示:

#1 range:
P 5-15
P 2-4

#2 range:
P 5-15
P 2-4

#3 range:
P 5-15
P 2-4

我想显示:

#1 range:
P 5-15
P 2-4

#2 range:
P 16-26
P 5-7

#3 range:
P 27-37
P 8-10

尽可能以最干净、可重复使用的方式。

提前致谢。

更新抱歉造成混淆,但我的意思是我不想使用重复使用的全局变量来解决...再次感谢您的所有贡献。

【问题讨论】:

  • 您当前的功能到底在做什么?你能解释或评论吗?
  • 你可以在 $("div").each(function() { 之后放一个变量吗?
  • @Daidon 他确实说过“我想保存全局变量以备不时之需。”
  • @Daidon 当然!只要我不必继续添加变量。
  • @ChrisHappy 好的,回答 commin' up

标签: javascript jquery function


【解决方案1】:

我建议通过工厂解决这个问题:

// jQuery plugin named rangify
$.fn.rangify = function rangify(ranges) {
  // factory to generate auto-incrementers
  function rangeFactory(value, increment) {
    // scoped variables `value` and `increment`
    // re-used by inner function
    
    // this is essentially the same
    // function as in original question
    return function range() {
      var first = value;

      value += increment;

      var second = value;

      value++;

      return 'P ' + first + '-' + second;
    }
  }

  // when jQuery plugin is called
  // this initializes scoped auto-incrementers
  // with arguments supplied from array of tuples
  var calls = ranges.map(function map(args) {
    return rangeFactory(args[0], args[1]);
  });
  
  // iterate through context of jQuery selector
  return this.each(function each() {
    // reference to single element in jQuery selector
    var $this = $(this);

    // for each auto-incrementer
    calls.forEach(function (call) {
      // append the generated range
      $this.append('<div>' + call() + '</div>');
    });
  });
};

// tell plugin to generate
// 1. sequential ranges of 10 starting at 5
// 2. sequential ranges of 2 starting at 2
$("div").rangify([[5, 10], [2, 2]]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

#1 range: <div></div>
<br />
#2 range: <div></div>
<br />
#3 range: <div></div>

我为您编写了一个 jQuery 插件,它使用工厂来存储作用域变量来代替您试图避免的全局变量。

更新

我刚刚创建了一个更通用的插件,您可以在其中指定给定参数返回的内容,以及每次如何增加参数:

// jQuery plugin named rangify
$.fn.rangify = function rangify(getter, increment, tuples) {
  // decorator to transform getter into auto-incrementing getter
  function decorator(tuple) {
    // scoped variable `tuple`
    // re-used by decorated function
    return function decorated() {
      // get content from getter
      var content = getter.apply(undefined, tuple);

      // increment the arguments for the getter
      tuple = increment.apply(undefined, tuple);
      
      // return the content
      return content;
    }
  }

  // when jQuery plugin is called
  // this initializes scoped auto-incrementers
  // with arguments supplied from array of tuples
  var calls = tuples.map(decorator);
  
  // iterate through context of jQuery selector
  return this.each(function each() {
    // reference to single element in jQuery selector
    var $this = $(this);

    // for each auto-incrementer
    calls.forEach(function (call) {
      // append the generated content
      $this.append(call());
    });
  });
};

// you supply the following functions to the plugin

// return content
function content(value, increment) {
  var first = value;
  var second = value + increment;

  return '<div>P ' + first + '-' + second + '</div>';
}

// return incremented arguments
function increment(value, increment) {
  value += increment + 1;
  
  return arguments;
}

// tell plugin to generate content
$("div").rangify(content, increment, [[5, 10], [2, 2]]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

#1 range: <div></div>
<br />
#2 range: <div></div>
<br />
#3 range: <div></div>

要说明为什么这是通用的,请考虑以下示例:

// jQuery plugin named rangify
$.fn.rangify = function rangify(getter, increment, tuples) {
  // decorator to transform getter into auto-incrementing getter
  function decorator(tuple) {
    // scoped variable `tuple`
    // re-used by decorated function
    return function decorated() {
      // get content from getter
      var content = getter.apply(undefined, tuple);

      // increment the arguments for the getter
      tuple = increment.apply(undefined, tuple);
      
      // return the content
      return content;
    }
  }

  // when jQuery plugin is called
  // this initializes scoped auto-incrementers
  // with arguments supplied from array of tuples
  var calls = tuples.map(decorator);
  
  // iterate through context of jQuery selector
  return this.each(function each() {
    // reference to single element in jQuery selector
    var $this = $(this);

    // for each auto-incrementer
    calls.forEach(function (call) {
      // append the generated content
      $this.append(call());
    });
  });
};

// you supply the following functions to the plugin

// return content
function content(className, chapter, section) {
  return '<div class="' + className + '">Chapter ' + chapter + ' - Section ' + section + '</div>';
}

// return incremented arguments
function increment(className, chapter, section) {
  if (section === 'C') {
    section = 'A';
    chapter++;
  } else {
    var nextCode = section.charCodeAt(0) + 1;
    section = String.fromCharCode(nextCode);
  }
  
  return arguments;
}

// tell plugin to generate content
$("div").rangify(content, increment, [['red', 1, 'A'], ['green', 4, 'A']]);
div:not([class]) {
  display: inline-block;
  border: 1px solid black;
  padding: 5px;
  margin-bottom: 5px;
}

.red {
  color: red;
}

.green {
  color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

【讨论】:

  • @ChrisHappy 我添加了一个更通用的解决方案。你可以选择你想使用哪一个
【解决方案2】:

由于问题含糊不清,不确定这是否是您所追求的,但是这会将参数注入到装饰函数中,这将增加装饰函数的每次调用。

计数器保存在 incrementRangeDecorator 函数的闭包中,因此它不会暴露在全局范围内。

// function decorator that will inject two argements into the 
// decorated function that will be incremented each call
const incrementRangeDecorator = function(start, increment, fn) {
  return function(...args) {
    const ret = fn(start, start += increment, ...args)
    start = start + 1
    return ret
  }
}

// function to decorate
function rangeF(start, current, extraArg) {
  console.log('called rangeF()', `${start}-${current}`, extraArg)
}

// decorate rangeF with the incrementRangeDecorator
const incrementBy2 = incrementRangeDecorator(2, 2, rangeF)
const incrementBy5 = incrementRangeDecorator(5, 10, rangeF)


incrementBy2('you')
incrementBy2('can')
incrementBy2('pass')

incrementBy5('extra')
incrementBy5('arguments')
incrementBy5()

【讨论】:

  • 看起来很有希望,但 const incrementBy2 = incrementRangeDecorator(2, rangeF) 之后并没有给它加 1...
  • @ChrisHappy 我想这就是你的意思。
  • @ChrisHappy 您还应该注意, (5, 10) 的增量实际上是 11。其他查看代码的人可能会感到困惑
  • 对,你只需要从中获取减1的数量...更新问题。
【解决方案3】:

使用

$(function() {

});

将等待执行,直到 DOM 准备好。 (这相当于 .ready() 函数,甚至建议使用它来代替 .ready()...)

里面的变量不会是“全局”的,它们将属于那个函数。

剩下的就自己解释了。

$(function() {
    var a = 5; var b = 10; var c = 2; var d = 2;
    $("div").each(function() {	
        function rangeF(firstValue, increment) {			
            var first = firstValue + "-"; //Set the first value and put a hypen after it
            firstValue += increment; //Increment it by the increment
            var second = firstValue; //Set the second value
            firstValue++; //Increment by one to avoid duplicates
            return first + second; //return both values (e.g. 1-2 or x-y)
        }
		
        range = rangeF(a, b);
        range2 = rangeF(c, d);
		
        a = a+b+1;
        c = c+d+1;
		
        $(this)
        .append('<div>' + range + '</div>')
        .append('<div>' + range2 + '</div>');
    });
});
div {
    border:#999 1px solid;
    padding:1em;
    margin:1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="A">
</div>
<div id="B">
</div>
<div id="C">
</div>

希望对您有所帮助。

【讨论】:

  • 您能更清楚地解释一下您要做什么吗?这个函数会在页面加载的时候执行一次,对吧?如果我知道您要实现的目标,也许我可以调整代码。 :-)
  • 好的,但我的解决方案不正是您想要的吗?变量不会全局保存。它们仅在计算到最后时保存。
  • 最终目标是什么?你想要一个函数 rangeF 来计算某个元素的增量吗?并且您也希望能够为其他元素调用该函数?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-25
  • 2022-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多