首页 > 解决方案 > 在 JavaScript 中使用“持久对象”是一种好习惯吗?

问题描述

根据 Douglas Crockford 的《JavaScript: The Good Parts》一书中的定义,持久对象是一个函数风格的对象,它的所有方法都没有使用thisthat。请查看以下示例:

这是持久对象的示例:

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;
}

这是非耐用对象的示例:

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;
}

我想知道拥有持久对象(this-free)是否是一种好习惯。重要的因素是 JavaScript 代码的性能、安全性、可扩展性和灵活性。

标签: javascript

解决方案


你的两个例子都不是很好的例子。

他们俩每次都为方法分配内存。

myObj一开始有BaseObject's 方法、字段。但在你说:allocate memory for setState method and attach to instance

所以来了prototypes

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

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

原型是静态对象,被分配一次并与类的实例相关联。


现在让我们从您的代码中制作组件(只是为了好玩):

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>


推荐阅读