827

Objective

Start with the page Installation of Objective.js

The Objective class is at the root of all the classes of Objective.js.

An instance of Objective can delegate the execution of different methods to a another instance, transfer the execution of a method to another instance which can automatically dispatch it, transfer the execution of a method to another instance which can directly respond to it or dispatch it automatically, notify to transfer the execution of a method to listeners which can directly respond to it or automatically dispatch it.

An instance of Objective can clone itself.

NOTE: The classes Undo and Validator are independent and can be used without Objective.js in any project in JavaScript .

  1. function Objective() {
  2. }

Creates an instance of the class Objective.

  1. Objective.prototype.clone = function() {
  2.     return Object.assign(Object.create(this), this);
  3. };

clone returns a new instance identical to this. IMPORTANT: clone copies the values of all the properties of this. If a value is a reference to an object, the clone will share the reference.

See the article Object.assign() on the website MDN Web Docs.

  1. Objective.prototype.delegate = function(f = null, ...args) {
  2.     let d = this._delegate;
  3.  
  4.     if (f === null)
  5.         return d;
  6.  
  7.     if (d === undefined)
  8.         return undefined;
  9.  
  10.     if (! (f in d && typeof d[f] === 'function'))
  11.         return undefined;
  12.  
  13.     return d[f](...args);
  14. };

Returns the result of the execution of the function f with the arguments args following f by the delegate of this. If this doesn't have a delegate or if the delegate of this doesn't have the function f, delegate returns undefined. If f is null, delegate returns the delegate of this.

  1. Objective.prototype.setDelegate = function(d) {
  2.     if (! (d === null || (typeof d === 'object')))
  3.         throw new TypeError();
  4.  
  5.     this._delegate = d;
  6.  
  7.     return this;
  8. };

setDelegate initializes the property delegate of this to d.

  1. Objective.prototype.hasListener = function(l) {
  2.     return this._listeners !== undefined && this._listeners.indexOf(l) != -1;
  3. };

hasListener returns true if the instance l is in the list of listeners of this, otherwise false.

  1. Objective.prototype.addListener = function(l) {
  2.     if (this._listeners === undefined)
  3.         this._listeners = [l];
  4.     else if (this._listeners.indexOf(l) == -1)
  5.         this._listeners.push(l);
  6.  
  7.     return this;
  8. };

addListener adds the instance l to the list of listeners of this.

  1. Objective.prototype.removeListener = function(l) {
  2.     if (this._listeners !== undefined) {
  3.         let i = this._listeners.indexOf(l);
  4.  
  5.         if (i != -1)
  6.             this._listeners.splice(i, 1);
  7.     }
  8.  
  9.     return this;
  10. };

removeListener removes the instance l from the list of listeners of this.

  1. Objective.prototype.notify = function(f, ...args) {
  2.     if (this._listeners !== undefined) {
  3.         for (let l of this._listeners)
  4.             l.forwardTo(f, ...args);
  5.     }
  6.  
  7.     return this;
  8. };

notify transfers the execution of the method f with the arguments args to the listeners of this.

  1. Objective.prototype.forwardTo = function(f, ...args) {
  2.     if (typeof this[f] === 'function')
  3.         this[f](...args);
  4.     else
  5.         this.forward(f, ...args);
  6. };

forwardTo runs the method f of this with the arguments args. If f isn't a method of this, forwardTo automatically transfers its execution with forward.

  1. Objective.prototype.forward = function(f, ...args) {
  2. };

forward of Objective ignores the execution of f and does nothing. A subclass can code an implementation of forward which transfers the execution of the method f with the arguments args to another instance, with forwardTo to preserve the transmission between a series of instances. See the section Test.

Test
  1. function Calculator(helper = null) {
  2.     this._accu = 0.0;
  3.  
  4.     if (helper)
  5.         this.setDelegate(helper);
  6. }
  7.  
  8. Calculator.prototype = Object.create(Objective.prototype);
  9.  
  10. Object.defineProperty(Calculator.prototype, 'constructor', { value: Calculator, enumerable: false, writable: true });
  11.  
  12. Object.defineProperty(Calculator.prototype, 'value', {
  13.     get:    function() {
  14.         return this._accu;
  15.     },
  16.     set:    function(n) {
  17.         if (typeof n !== 'number')
  18.             throw new TypeError();
  19.  
  20.         this._accu = n;
  21.     }
  22. });
  23.  
  24. Calculator.prototype.clear = function() {
  25.     this._accu = 0.0;
  26.  
  27.     return this;
  28. };
  29.  
  30. Calculator.prototype.add = function(val) {
  31.     this._accu += val;
  32.  
  33.     return this;
  34. };
  35.  
  36. Calculator.prototype.sub = function(val) {
  37.     this._accu -= val;
  38.  
  39.     return this;
  40. };
  41.  
  42. Calculator.prototype.mul = function(val) {
  43.     this._accu *= val;
  44.  
  45.     return this;
  46. };
  47.  
  48. Calculator.prototype.div = function(val) {
  49.     this._accu /= val;
  50.  
  51.     return this;
  52. };
  53.  
  54. Calculator.prototype.sqrt = function() {
  55.     this._accu = Math.sqrt(this._accu);
  56.  
  57.     return this;
  58. };
  59.  
  60. Calculator.prototype.clr = function() {
  61.     this.delegate('clr');
  62.  
  63.     return this;
  64. };
  65.  
  66. Calculator.prototype.sto = function() {
  67.     this.delegate('sto', this._accu);
  68.  
  69.     return this;
  70. };
  71.  
  72. Calculator.prototype.rcl = function() {
  73.     this._accu = this.delegate('rcl');
  74.  
  75.     return this;
  76. };
  77.  
  78. function CalculatorMemory() {
  79.     this._mem = 0.0;
  80. }
  81.  
  82. CalculatorMemory.prototype = Object.create(Objective.prototype);
  83.  
  84. Object.defineProperty(CalculatorMemory.prototype, 'constructor', { value: CalculatorMemory, enumerable: false, writable: true });
  85.  
  86. CalculatorMemory.prototype.clr = function() {
  87.     this._mem = 0.0;
  88.  
  89.     return this;
  90. };
  91.  
  92. CalculatorMemory.prototype.sto = function(val) {
  93.     this._mem = val;
  94.  
  95.     return this;
  96. };
  97.  
  98. CalculatorMemory.prototype.rcl = function() {
  99.     return this._mem;
  100. };
  1. <?php head('javascript', '/objectivejs/Objective.js'); ?>
  2. <?php head('javascript', '/objectivejs/tests/Calculator.js'); ?>

Adds the tags <script src="/objectivejs/Objective.js"> and <script src="/objectivejs/tests/Calculator.js"></script> to the <head> section of the HTML document.

The test program creates a calculator with one memory, calculates the gold number and displays it, memorizes the result, clears the calculator, recalls the golden number in memory and displays it.

  1. const mem = new CalculatorMemory();
  2. const calc = new Calculator(mem);

Creates an instance of Calculator with one instance of CalculatorMemory as a parameter.

  1. calc.value = 5;
  2. calc.sqrt();
  3. calc.add(1);
  4. calc.div(2);

Computes (1 + sqrt(5)) / 2.

  1. console.log(calc.value);    // 1.618

Displays the result.

  1. calc.sto();
  2. calc.clear();

Memorizes the result. Resets the calculator to 0.

  1. console.log(calc.value);    // 0

Displays 0.

  1. calc.rcl();

Recalls the number in memory.

  1. console.log(calc.value);    // 1.618

Displays the result.

  1. calc2 = calc.clone();
  2. console.log(calc2.value);   // 1.618
  3. calc2.clear();
  4. console.log(calc.value);    // 1.618
  5. calc2.clr();
  6. calc.rcl();
  7. console.log(calc.value);    // 0

Creates a clone of the calculator and displays its value. Sets the value of the clone to 0 and checks that the value of the calculator hasn't changed. Sets the memory of the clone to 0. Recalls the value in memory of the calculator and displays its value. Since the calculator and its clone share the same instance of CalculatorHelper, it is set to 0.

Display the page generated by the file testObjective.phtml and check the trace in the console of the browser:

1.618033988749895
0
1.618033988749895
1.618033988749895
1.618033988749895
0

Check that the calculator and its clone share the same delegate:

calc2._delegate === calc._delegate
true

Add a clone method to the Calculator class which clones the delegate of a calculator:

Calculator.prototype.clone = function() {
    const clone = Objective.prototype.clone.call(this);

    const delegate = this.delegate();

    if (delegate)
        clone.setDelegate(delegate.clone());

    return clone;
}

Redisplay the page generated by the file testObjective.phtml and check in the trace in the console of the browser that the memory of the calculator isn't changed when the memory of the clone is cleared:

1.618033988749895
0
1.618033988749895
1.618033988749895
1.618033988749895
1.618033988749895

The calculator and its clone don't share the same delegate:

calc2._delegate === calc._delegate
false
  1. <?php head('javascript', '/objectivejs/Objective.js'); ?>

Adds the tag <script src="/objectivejs/Objective.js"></script> to the <head> section of the HTML document.

  1. function Ping() {
  2. }
  3.  
  4. Ping.prototype = Object.create(Objective.prototype);
  5.  
  6. Object.defineProperty(Ping.prototype, 'constructor', { value: Ping, enumerable: false, writable: true });
  7.  
  8. Ping.prototype.echo = function(msg) {
  9.     console.log(`[PING] ${msg}`);
  10. }

The method echo of the class Ping displays [PING] followed by the message msg on the console.

  1. function Pong() {
  2. }
  3.  
  4. Pong.prototype = Object.create(Objective.prototype);
  5.  
  6. Object.defineProperty(Pong.prototype, 'constructor', { value: Pong, enumerable: false, writable: true });
  7.  
  8. Pong.prototype.echo = function(msg) {
  9.     console.log(`[PONG] ${msg}`);
  10. }

The method echo of the class Pong displays [PONG] followed by the message msg on the console.

  1. function PingPong(pong) {
  2.     this._pong = pong;
  3. }
  4.  
  5. PingPong.prototype = Object.create(Objective.prototype);
  6.  
  7. Object.defineProperty(PingPong.prototype, 'constructor', { value: PingPong, enumerable: false, writable: true });
  8.  
  9. PingPong.prototype.forward = function(f, ...args) {
  10.     this._pong.forwardTo(f, ...args);
  11. }

The method forward of the class PingPong transfers the execution of all the methods to a Pong instance.

  1. function Router(ping, pong) {
  2.     this._ping = ping;
  3.     this._pong = pong;
  4.  
  5.     this._channel = this._ping;
  6. }
  7.  
  8. Router.prototype = Object.create(Objective.prototype);
  9.  
  10. Object.defineProperty(Router.prototype, 'constructor', { value: Router, enumerable: false, writable: true });
  11.  
  12. Router.prototype.switch = function() {
  13.     this._channel = this._channel === this._ping ? this._pong : this._ping;
  14.  
  15.     this.notify('routerSwitched', this);
  16.  
  17.     return this;
  18. }
  19.  
  20. Router.prototype.forward = function(f, ...args) {
  21.     this._channel.forwardTo(f, ...args);
  22. }

The method forward of the class Router transfers the execution of all the methods to a Ping or a Pong instance. The method switch toggles the transfer of the methods between the Ping or the Pong. switch notifies the message routerSwiched to all listeners.

  1. function Listener(logger) {
  2.     this._logger = logger;
  3. }
  4.  
  5. Listener.prototype = Object.create(Objective.prototype);
  6.  
  7. Object.defineProperty(Listener.prototype, 'constructor', { value: Listener, enumerable: false, writable: true });
  8.  
  9. Listener.prototype.forward = function(f, ...args) {
  10.     if (this._logger);
  11.         this._logger.forwardTo(f, ...args);
  12. }

The method forward of the class Listener transfers the execution of all the methods to a Logger instance.

  1. function Logger() {
  2. }
  3.  
  4. Logger.prototype = Object.create(Objective.prototype);
  5.  
  6. Object.defineProperty(Logger.prototype, 'constructor', { value: Logger, enumerable: false, writable: true });
  7.  
  8. Logger.prototype.routerSwitched = function(sender) {
  9.     console.log('ROUTER SWITCHED');
  10. }

An instance of Logger responds to a routerSwiched message by displaying ROUTER SWITCHED on the console.

  1. const ping = new Ping();
  2. const pong = new Pong();
  3.  
  4. const router1 = new Router(ping, pong);

Creates an instance of Router with an instance of Ping and an instance of Pong.

  1. router1.forward('echo', 'HELLO');   // [PING] HELLO
  2. router1.switch();
  3. router1.forward('echo', 'HELLO');   // [PONG] HELLO

Transfers the method echo to router1 which transfers it to ping which displays [PING] HELLO. Toggles router1 on pong. Transfers the method echo to router1 which transfers it to pong which displays [PONG] HELLO.

  1. const pingpong = new PingPong(pong);
  2.  
  3. const router2 = new Router(ping, pingpong);

Creates an instance of PingPong with an instance of Pong. Creates an instance of Router with an instance of Ping and an instance of PingPong.

  1. router2.forward('echo', 'HELLO');   // [PING] HELLO
  2. router2.switch();
  3. router2.forward('echo', 'HELLO');   // [PONG] HELLO

Transfers the method echo to router2 which transfers it to ping which displays [PING] HELLO. Toggles router2 on pingpong. Transfers the method echo to router2 which transfers it to pingpong which transfers it to pong which displays [PONG] HELLO.

  1. const logger = new Logger();
  2. const listener = new Listener(logger);

Creates an instance of Listener with an instance of Logger.

  1. router2.addListener(listener);
  2. router2.switch();                   // ROUTER SWITCHED
  3. router2.forward('echo', 'HELLO');   // [PING] HELLO

Adds listener to the list of listeners of router2. Toggles router2 on ping which notifies the message routerSwitched to listener which automatically transfers it to logger which displays ROUTER SWITCHED. Transfers the method echo to router2 which transfers it to ping which displays [PING] HELLO.

  1. const router3 = new Router(ping, router2);

Creates an instance of Router with an instance of Ping and an instance of Router.

  1. router3.addListener(listener);
  2. router3.switch();                   // ROUTER SWITCHED
  3. router3.forward('echo', 'HELLO');   // [PING] HELLO
  4. router2.switch();                   // ROUTER SWITCHED
  5. router3.forward('echo', 'HELLO');   // [PONG] HELLO

Adds listener to the list of listeners of router3. Toggles router3 on router2 which notifies the message routerSwitched to listener which automatically transfers it to logger which displays ROUTER SWITCHED. Transfers the method echo to router3 which transfers it to router2 which transfers it to ping which displays [PING] HELLO.

Toggles router2 on pingpong which notifies the message routerSwitched to listener which automatically transfers it to logger which displays ROUTER SWITCHED. Transfers the method echo to router3 which transfers it to router2 which transfers it to pingpong which transfers it to pong which displays [PONG] HELLO.

Display the page generated by the file testObjectiveForward.phtml and check the trace in the console of the browser:

[PING] HELLO
[PONG] HELLO
[PING] HELLO
[PONG] HELLO
ROUTER SWITCHED
[PING] HELLO
ROUTER SWITCHED
[PING] HELLO
ROUTER SWITCHED
[PONG] HELLO
SEE ALSO

Installation, Once, Responder

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].