如何更新依赖于函数中另一个变量的变量?

How to update a variable that depends on another variable in a function?

在下面的示例代码中,请注意变量 dependent 的值取决于变量 prereq。当调用函数 changePrereq 时,它会更改 prereq 的值。如果已记录,则会显示此更改,但不会反映在 dependent 的值中。相反,当 dependent 被放入一个跨度中时,它显示 Some text - undefined.

如何根据 prereq 的值更改 dependent

P.S。感谢大家的建议。对于我自己,我选择了 "ztcollazo" 的答案作为正确的决定。

"outis" - 感谢您的解释。我一定会关注您的建议,并会更详细地研究它们!

var display = document.getElementById('text'),
    prereq,
    message = "Some text - " + prereq;

function updateDisplay() {
    display.innerHTML = message;
    console.log(prereq);
}

function changePrereq() {
    prereq = "I am some text.";
    updateDisplay();
}
<p><span id="text"></span></p>
<button onclick="changePrereq()">Click</button>

将 changeMyText 变量移动到 changeTextFunc 函数中。 代码看起来像这样

    function changeMyText(m){
          var changeMyText = "Some text - " + someText1;
          if (m > 0) {
             myText.innerHTML = changeMyText;
          } else {
             console.log('m < 0');
          }
    }

问题是 changeMyText 不会在 someText 更新时更新。您需要在 changeTextFunc 函数内部定义 changeMyText,然后将 someText 作为参数传递。

示例:

var myText = document.getElementById('text');
var someText1;

var m1 = 1;

function changeTextFunc(someText, m) {
  var changeMyText = "Some text - " + someText;
  if (m > 0) {
    myText.innerHTML = changeMyText;
  } else {
    console.log('m < 0');
  }
}

function changeText() {
  someText1 = "I a'm some text.";
  changeTextFunc(someText1, m1);
}
<div>
  <button onclick="changeText()">Click</button>
  <p id="text"></p>
</div>

如果你想让一个变量基于另一个而改变,你必须在另一个改变之后设置它的值。有各种方法,具有各种实现。您可以将其分解为不同的方面进行更改:

  1. 内容:
    1. globals(注意:avoid global variables 在生产中,并在其他上下文中谨慎使用)
    2. 本地人
    3. 对象
      1. 普通方法
      2. getter/setter methods
  2. 其中:
    1. 内联,在站点引用一个变量
    2. 在为职责创建的单独函数中
  3. 当:
    1. 先决条件变量已更改
    2. 使用因变量

以上不同方面的一些选项不打算合并,或者不能合并。例如,1.3(对象)旨在与 2.2(单独的函数)一起使用,而 1.3.2(getters/setters)需要 2.2,因为对象 getters 和 setters 是函数( 2.2 基本上意味着“使用 getter 或 setter”,但不一定使用 getter/setter 语法)。你可能会想到其他方面,或者以上方面的其他可能性。

ztcollazo 显示了一个解决方案,该解决方案使用全局作为先决条件 (1.1),使用本地作为依赖项 (1.2),并在使用依赖项 (3.2) 时更新内联 (2.1)。如果 changeTextFunc 设置 changeMyText 中的行改为移动到 changeText (并且使用全局),你将有 1.1 + 2.1 + 3.1.

有关更多示例实现,请检查以下内容。它说明了上述四个不同的选项,并在评论中注明。

var display = document.getElementById('output'),
    dependent, prereq;

/* options 1.1, 2.2, 3.1: global, separate function, prereq change */
function setPrereq(value) {
    prereq = value;
    dependent = "global prereq setter: " + prereq;
}

function updateDisplayFromVariable() {
    display.innerText = dependent;
}

function changePrereq_updateWhenSet(value="setter") {
    setPrereq(value);
    updateDisplayFromVariable();
}

/* options 1.1, 2.2, 3.2: global, separate function, dependent used */
function getDependent(value) {
    return dependent = "global dependent getter: " + prereq;
}

function updateDisplayFromGetter() {
    display.innerText = getDependent();
}

function changePrereq_updateWhenUsed(value="inline, no setter") {
    prereq = value;
    updateDisplayFromGetter();
}

/* options 1.3.2, 2.2: (local) object getter/setter */
/* wrapped in self-called function to prevent polluting global namespace */
var dependency = (function () {
    let display = document.getElementById('output'),

        /* options 1.3.2, 2.2, 3.2: (local) object getter, dependent used */
        inGetter = {
            prereq: 'initial',
            /* note: `dependent` is entirely synthetic */
            get dependent() {
                return "object's dependent getter: " + this.prereq;
            },
        },

        /* options 1.3.2, 2.2, 3.1: (local) object setter, prereq changed */
        inSetter = {
            /* note: when using setter, can't use same name for the 
             * backing property; instead, must also define getter. */
            _prereq: 'initial',
            get prereq() {
                return this._prereq;
            },
            set prereq(value) {
                this._prereq = value;
                this.dependent = "object's prereq setter: " + value;
            },
        };

    function updateDisplay(from) {
        display.innerText = from.dependent;
    }
    
    /* expose 1.3.2, 2.2, 3.1 */
    function whenSet(value) {
        inSetter.prereq = value;
        updateDisplay(inSetter);
    }
    
    /* expose 1.3.2, 2.2, 3.2 */
    function whenUsed(value) {
        inGetter.prereq = value;
        updateDisplay(inGetter);
    }

    return {whenSet, whenUsed};
})();
<button onclick="changePrereq_updateWhenSet('thimbles')">Use global setter</button>
<button onclick="changePrereq_updateWhenUsed('care')">Use global getter</button>
<button onclick="dependency.whenSet('forks')">Use object setter</button>
<button onclick="dependency.whenUsed('hope')">Use object getter</button>
<p><span id="output"></span></p>

与任何设计一样,以上各有优点和缺点,但应该首选使用对象 setters/getters (1.3.2),因为它是最可靠的方法。使用独立函数(不是 getters/setters)和更新内联都更脆弱,因为程序员可能无法在某处使用它们,而是直接分配和引用变量。内联更新也更难维护,因为必须在执行更新的每一行上进行任何更改。全局变量有自己的问题,比如:

  • 模块中有限的代码重用(注意 updateDisplay(from) 如何适用于两种不同的情况,而 changePrereq_updateWhenSetchangePrereq_updateWhenUsed 各自需要不同的显示功能),并且
  • 不灵活(即,为新行为组合现有功能受到更多限制;换句话说,这限制了客户端代码的代码重用),
  • 当不同的模块使用相同的全局变量时命名冲突,导致它们相互冲突。

至于更新先决条件setter(1.3.2 + 2.2 + 3.1)中的依赖还是使用getter无后盾的依赖属性(在某些圈子里,这被称为“合成 属性”)取决于其他要求(基本上,是否允许依赖项被分配独立于先决条件的值)。例如,您可以对两个属性使用 getters 和 setters。