简体   繁体   中英

Javascript: Prototype provides interface to call object's method infinitely

I am looking for a JavaScript implementation for the following requirements:

  1. A prototype implements a next and a run method. If next is invoked, an iteration function once is called once. If run is invoked, once is called infinitely often (abortion via user request must also be possible, but is currently not reflected in the source code).
  2. once takes a done argument which it will invoke once it is done.
  3. The iteration function once is defined in the prototype , but can and will be overridden by the child Child .
  4. Infinite iterations as in run must be possible, hence the stack must be lost (as it happens when the function is called by setTimeout.

My current problem with this source code: once of Parent is invoked, not of Child .

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>JS test</title>
    <script type="text/javascript">
      function write(msg) {
        var t = document.createTextNode(msg);
        var li = document.createElement("li");
        li.appendChild(t);
        document.querySelector("ul").appendChild(li);
      }

      var Parent = function () {
        var running = 0;

        var run = function () {
          running = Infinity;
          invokeNextIter();
        };

        var next = function () {
          running = 1;
          invokeNextIter();
        };

        var invokeNextIter = function () {
          if (running > 0) {
            running -= 1;
            setTimeout(function () { once(invokeNextIter); }, 1);
          }
        };

        var once = function (done) {
          var time = Math.random() * 3 + 1;
          write(time + " sec");
          setTimeout(done, time * 1000);
        };

        return {
          run: run,
          once: once
        };
      };

      var Child = function () {
        var once = function (done) {
          write("2 sec as always");
          setTimeout(done, 2000);
        };

        var p = new Parent();
        return Object.create(p, { once : once });
      };

      function main() {
        var c = new Child();
        c.run();
      }
    </script>
  </head>
  <body onload="main()">
    <ul>
    </ul>
  </body>
</html>

Was not able to get this running with Function.prototype.bind or associated techniques. Any help appreciated gratefully 😎

Ok, in your case, the only function which is different between Parent and Child is your once() function.

So you have to start from your Parent class, build the core, then you will add instance method to Parent and child , to override the once() function.

We will use the prototypal inheritance . The rule is that you can prototype any object that is initialized with the new keyword, and that includes native javascript objects.

  function write(msg) {
     var t = document.createTextNode(msg);
     var li = document.createElement("li");
     li.appendChild(t);
     document.querySelector("ul").appendChild(li);
   }

   var Parent = function(){
     //Retrieve context
     var self = this;

     var running = 0
     //Create a `run` function which will refer to the current context
     self.run = function(){
       running = Infinity;
       invokeNextIter();
     }

     //Declare our private function
     var next = function () {
        running = 1;
        invokeNextIter();
      };

     var invokeNextIter = function () {
        if (running > 0) {
          running -= 1;
          setTimeout(function () {
            //Call once method which is in the prototype of the current context
            self.once(invokeNextIter);
          }, 1);
        }
      };
   }

   //Add a "once" instance method to Parent
   Parent.prototype.once = function(done){
     var time = Math.random() * 3 + 1;
     write(time + " sec");
     setTimeout(function(){
       done();
     }, time * 1000);
   }


   //Create our Child 'class'
   var Child = function(){

   }

   //Declare Child as a subclass of the first
   Child.prototype = new Parent();

   //Add a "once" instance method to Child and override the "once" parent method
   Child.prototype.once = function(done){
     write("1.5 sec as always");
     setTimeout(function(){
       done();
     }, 1500);
   }


   function main(){
     // Create instances and see the overridden behavior
     var c = new Child();
     var p = new Parent();
     //c.run() will call child once() method
     c.run();
     //p.run() will call parent once() method
     p.run();
   }

Here, you can see the self.run() and self.once() . Self variable will refer to the current instance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM