从同一对象的不同实例中触发另一个实例的函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从同一对象的不同实例中触发另一个实例的函数相关的知识,希望对你有一定的参考价值。

我是javascript的初学者,我正在努力弄清楚如何使用一个实例的函数来触发另一个实例中的函数,反之亦然,这两个版本都是同一个类。让我解释一下我的意思。

我的项目是用Javascript构建一个番茄钟。番茄钟是一个你在指定时间内工作的过程(例如25分钟),然后短暂休息(5分钟),然后重复。时钟应该无限期地或者在用户停止之前一直向后运行。

我需要完成一个时钟来触发另一个时钟的开始,反之亦然。

我为每个计时器使用完全独立的,略有不同的功能构建了一个工作程序(冗余很多)。我试图通过创建一类Timers并从中构建每一个来简化我的代码。那就是我被困住的地方。

我的Timer类中有一个函数,当计时器到达零时,需要调用另一个计时器的倒计时开始(Codepen上的第126行)。我怎样才能做到这一点?

感谢您提供的任何帮助。

这是我在Codepen上的项目:https://codepen.io/lieberscott/pen/baRpgx?editors=1010

我的Javascript代码如下:

let session; // session Timer object instance
let btimer; // break Timer object instance

let s_off; // boolean for whether session timer is off or on
let s_timer; // reference to session timer html element
let s_stop; // reference to session stop HTML button
let s_increase; // reference to session increase HTML button
let s_decrease; // reference to session decrease HTML button

// same variables as above for break timer
let b_off;
let b_timer;
let b_stop;
let b_increase;
let b_decrease;


$(document).ready(function() {
  s_off = true;
  s_timer = $("#timer");
  s_stop = $("#stop");
  s_increase = $("#increase");
  s_decrease = $("#decrease");
  b_off = true;
  b_timer = $("#breaktimer");
  b_stop = $("#breakstop");
  b_increase = $("#breakincrease");
  b_decrease = $("#breakdecrease");

  session = new Timer(1, 60, s_off, s_timer, s_stop, s_increase, s_decrease);
  btimer = new Timer(5, 60, b_off, b_timer, b_stop, b_increase, b_decrease);

  // increase session minutes
  $(s_increase).on("click", function() {
    if (session.off) {
      session.min++;
      session.sec = 00;
      s_timer.html(session.min + ":" + session.sec);
    }
  });

  // decrease session minutes
  $(s_decrease).on("click", function() {
    if (session.off) {
      if (session.min > 1) {
        session.min--;
      }
      session.sec = 00;
      s_timer.html(session.min + ":" + session.sec);
    }
  });

  // increase break minutes
  $(b_increase).on("click", function() {
    if (btimer.off) {
      btimer.min++;
      btimer.sec = 00;
      b_timer.html(btimer.min + ":" + btimer.sec);
    }
  });

  // decrease break minutes
  $(b_decrease).on("click", function() {
    if (btimer.off) {
      if (btimer.min > 1) {
        btimer.min--;
      }
      btimer.sec = 00;
      b_timer.html(btimer.min + ":" + btimer.sec);
    }
  });

  // begin session timer by clicking on the timer itself
  $(s_timer).on("click", function() {
    session.time();
  });

  // stop session timer
  $(s_stop).on("click", function() {
    session.off = true;
    session.stopClock(session.intervalFunction);
  });

  // stop break timer
  $(b_stop).on("click", function() {
    btimer.off = true;
    btimer.stopClock(btimer.intervalFunction);
  });

});


class Timer {
  constructor(min, sec, off, disp, stopButton, increaseButton, decreaseButton) {
    this.min = min; // minutes
    this.minsSet = min; // minutes again, this will be used to reset the timer
    this.sec = sec;
    this.off = off; // boolean saying whether timer is off or not
    this.disp = disp; // HTML display
    this.stopButton = stopButton;
    this.increaseButton = increaseButton;
    this.decreaseButton = decreaseButton;
    this.func;
  }

  time() { // function fired when the timer is clicked
    if (this.off) {
      this.off = false;
      this.func = this.intervalFunc();
    }
  }

  intervalFunc() { // set the interval of the timer
    setInterval(function() {this.countdown();}, 1000); // ERROR HERE
  }

  countdown() { // interval to complete for duration of timer
    // check if clock reaches zero
    if (this.sec == 0) {
      this.min--;
      this.sec = 60;
      if (this.min < 0) {
        this.min = this.minsSet;
        this.sec = 0;
        this.off = true;
        this.time(); // this needs to trigger, not this.time(), but the OTHER object's time() function
        this.stopClock(this.func); // clearInterval() function below
      }
    }

    // if clock is not at 0:00, display new time
    this.sec--;
    let m = this.min.toString();
    let s;
    if (this.sec < 10) {
      s = "0" + this.sec.toString()
    }
    else {
      s = this.sec.toString();
    }
    this.disp.html(m + ":" + s);
  }

  stopClock() {
    clearInterval(this.func);
  }
}
答案

1)我尝试了你的代码并修复了一些bug,你的setInterval问题是因为“this”指向那里的window对象。

2)为了调用另一个对象time()方法,首先你需要知道你正在使用哪个对象,所以我在类中添加了一个类型变量,然后在倒计时函数中添加了一个检查。这笔中有变化:

https://codepen.io/yaduvanshi/pen/dJRdeR?editors=0010

intervalFunc() { // set the interval of the timer
   var that =this;
   setInterval(function() {that.countdown();}, 1000); // ERROR HERE
}
另一答案

我认为您正在寻找的解决方案是Javascript为您提供的.bind()或.call()(Function.prototype.bind())。例如,.bind()函数将特定对象实例作为参数。你可以在这里阅读https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

以上是关于从同一对象的不同实例中触发另一个实例的函数的主要内容,如果未能解决你的问题,请参考以下文章

为啥我能够从在同一对象的另一个实例上调用的方法访问一个实例的私有实例变量? [复制]

如何一个接一个地打开同一片段但具有不同数据的多个实例?

使用反射从同一类型的另一个实例复制所有对象值

将类对象实例作为参数从 main() 传递给另一个类对象实例

c++ 对象正在创建同一个数组的两个实例,但在不同的范围内?

是否可以创建同一对象的不同实例并通过将参数传递给 Koin 中的 get() 函数来访问它们?