简体   繁体   中英

Is using of “Durable Object” a good practice in JavaScript?

According to the definition in Douglas Crockford's book, "JavaScript: The Good Parts", a durable object is an object in the functional style which all its methods make no use of this or that . Please look into the following examples:

This is an example of durable object:

const MyObj = function()
{
  const myObj = BaseObject();

  const inp = create( "input" );
  inp.type = "checkbox";
  const txt = doc.createTextNode("");
  myObj.control = create( "label" );
  myObj.control.appendChild( inp );
  myObj.control.appendChild( txt );

  myObj.setState = state => inp.checked = state;

  myObj.getState = () => inp.checked;

  myObj.setCaption = cap =>
  {
    txt.textContent = cap;
  }
  return myObj;
}

This is an example of non-durable object:

const MyObj = function()
{
  const myObj = BaseObject();

  myObj.inp = create( "input" );
  myObj.inp.type = "checkbox";
  myObj.txt = doc.createTextNode("");
  myObj.control = create( "label" );
  myObj.control.appendChild( myObj.inp );
  myObj.control.appendChild( myObj.txt );

  myObj.setState = function(state)
  { 
      this.inp.checked = state; **// Look at here**
  }

  myObj.getState = function() 
  {
      return this.inp.checked;
  }

  myObj.setCaption = cap =>
  {
    this.txt.textContent = cap;
    this.callABaseObjectMethode(); **// Look at here**
  }
  return myObj;
}

I want to know whether it is a good practice to have durable object (this-free) or not. Important factors are performance, security, scalability, flexibility of our JavaScript code.

Both of Your examples not good example.

Both of them allocate memory for methods every time.

Your myObj in the beginning has BaseObject 's methods, fields. But after You say: allocate memory for setState method and attach to instance

So here comes prototypes :

MyObj.prototype.setState = state => this._state = state;

MyObj.prototype.getState = () => Object.assign({}, this._state);

Prototypes are static objects that being allocated once and associated to instances of classes.


Now let's make component from Your code (just for fun):

 class Component { constructor(initialState) { this._state = initialState ? initialState : {}; this._masterNode = document.createElement(this.constructor.name); this._eventListeners = {}; } createElement(tagName, attributes = {}, onStateChange) { const element = document.createElement(tagName); Object.assign(element, attributes); if (onStateChange) { this.on('stateChanged', (newState) => { onStateChange(newState, element); }); } return element; } createInput(name, type, onStateChange) { return this.createElement('input', {name, type}, onStateChange); } createLabel(labelFor, onStateChange) { return this.createElement('label', {for: labelFor}, onStateChange); } createTextNode(text, onStateChange) { const textNode = document.createTextNode(text); if (onStateChange) { this.on('stateChanged', (newState) => { onStateChange(newState, textNode); }); } return textNode; } appendChild(element) { this._masterNode.appendChild(element); } setState(state) { Object.assign(this._state, state); this.emit('stateChanged', this._state); } getState() { return Object.assign({}, this._state); } on(eventName, listener) { if (!this._eventListeners[eventName]) this._eventListeners[eventName] = []; this._eventListeners[eventName].push(listener); } emit(eventName, payload) { if (!this._eventListeners[eventName]) return; console.log(eventName, payload); this._eventListeners[eventName].forEach(method => { method(payload); }); } appendTo(container) { container.appendChild(this._masterNode); } } const form = new Component(); // create label const label = form.createLabel('termsAndConditions'); // create checkbox with state listener const checkbox = form.createInput('something', 'checkbox', (newState, element) => { if (newState.agreedWithTC === true) { element.checked = true; return; } element.checked = false; }); // operating with state on click by checkbox checkbox.onclick = () => { if (checkbox.checked) { form.setState({agreedWithTC: true}); return; } form.setState({agreedWithTC: false}); }; // append checkbox to label label.appendChild(checkbox); const textNode = form.createTextNode('Agree with T&C', (newState, element) => { textNode.textContent = textNode.textContent.replace('(agreed)', '').replace('(not agreed)', ''); if (newState.agreedWithTC === true) { textNode.textContent += ' (agreed)'; return; } textNode.textContent += ' (not agreed)'; }); // create text node and append it to label label.appendChild(textNode); // append label to form form.appendChild(label); // append overall component instance to container form.appendTo(document.getElementById('container')); setInterval(() => { form.setState({agreedWithTC: !form.getState().agreedWithTC}); }, 1000); 
 <div id="container"></div> 

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