在JavaScript中使用“耐用对象”是一种好习惯吗?

时间:2018-08-26 17:22:24

标签: javascript

根据道格拉斯·克罗克福德(Douglas Crockford)的书“ JavaScript:好的零件”的定义,耐用的对象是一种功能风格的对象,其所有方法均不使用 this < / em>或 that 。请查看以下示例:

这是耐用对象的示例:

        var request = HttpWebRequest.CreateHttp(url);
        request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1";
        request.Method = "HEAD";
        using (var response = await request.GetResponseAsync())
        {
            var length = response.ContentLength;
        }

这是非耐用对象的示例:

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

我想知道是否有耐用的物品(无此物品)是一种好习惯。重要因素包括我们的JavaScript代码的性能,安全性,可伸缩性和灵活性。

1 个答案:

答案 0 :(得分:0)

您的例子都不是好例子。

它们两者每次都为方法分配内存。

您的myObj开头有BaseObject的方法,字段。但是在您说: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>