Node Package: options

options

A very light-weight in-code option parsers for node.js.
一個非常輕量的在代碼內的NodeJS選項解析器。

大致的作用就是解析、重設、合併、拷貝、讀取、驗證選項,源代碼非常短,本文就做一個簡單的解讀。

這個包非常底層,沒有依賴其他的第三方包(葉子包),而且被廣泛地引用,在自行開發包的時候可以引用一下。

這個包是隻支持Node的,不適用於瀏覽器,因爲它主要操作配置文件,引用了NodeJS的 fs 包。


代碼註釋

老實說這個代碼寫得真不怎麼樣。

/*!
 * Copyright(c) 2011 Einar Otto Stangvik <[email protected]>
 * MIT Licensed
 */

var fs = require('fs');
/**
 * Options 是一個類,其構造函數的僅有一個參數:默認選項。
 * @params: defaults, 默認的參數選項
 * @note: defaults在代碼中會以閉包的形式保存(老實說這不是一個好方法)
 * @note: 沒有在Options中使用原型來生成方法
 * @note: 成員變量設定不清楚
 */
function Options(defaults) {
  var internalValues = {};
  var values = this.value = {}; // 老實說通讀了代碼我覺得這個變量就是雞肋
  // 將defaults深拷貝到internalValues中
  Object.keys(defaults).forEach(function(key) {
    internalValues[key] = defaults[key];
    // 定義對象的屬性
    Object.defineProperty(values, key, {
      get: function() { return internalValues[key]; }, // 偷樑換柱地重載了getter
      configurable: false, // 不可配置
      enumerable: true // 可枚舉
    });
  });
  /**
   * reset: 重置選項
   * @return: Options對象自身
   *  */ 
  this.reset = function() {
    // 將defaults深拷貝到internalValues中
    Object.keys(defaults).forEach(function(key) {
      internalValues[key] = defaults[key];
    });
    return this;
  };
  /**
   * Merge: 合併選項
   * @params: options, 需要合併的選項
   * @params: required, options 中要包含的鍵的數組
   * @throw: 當 required 中某值key使得 options[key] == undefined 時
   * @return: Options對象自身
   *  */
  this.merge = function(options, required) {
    // 初始化新的options
    options = options || {};
    // 若 required 是數組
    if (Object.prototype.toString.call(required) === '[object Array]') {
      // 遍歷 required, 檢查options與required之間是否missing。
      var missing = []; // 注意此處的變量提升
      for (var i = 0, l = required.length; i < l; ++i) {
        var key = required[i];
        if (!(key in options)) {
          missing.push(key);
        }
      }
      // missing 報錯 
      if (missing.length > 0) {
        if (missing.length > 1) {
          throw new Error('options ' +
            missing.slice(0, missing.length - 1).join(', ') + ' and ' +
            missing[missing.length - 1] + ' must be defined');
        }
        else throw new Error('option ' + missing[0] + ' must be defined');
      }
    }
    // 將options中的值深拷貝入internalValues
    Object.keys(options).forEach(function(key) {
      if (key in internalValues) {
        internalValues[key] = options[key];
      }
    });
    return this;
  };
  /**
   * copy: 拷貝選項
   * @params: keys, 需要拷貝的鍵的數組。
   * @return: 新的對象
   *  */ 
  this.copy = function(keys) {
    var obj = {};
    // 將defaults中所有在keys中的鍵找出來複製到obj中。
    // 吐槽: 照理說不是應該遍歷keys比較正常嗎
    Object.keys(defaults).forEach(function(key) {
      if (keys.indexOf(key) !== -1) {
        obj[key] = values[key];
      }
    });
    return obj;
  };
  /**
   * read: 從文件中以JSON格式讀取選項
   * @params: filename, 文件名
   * @params: cb, 回調函數
   * @note: 當cb未定義時使用同步讀取方式,否則使用異步。
   * @return: Options對象自身
   *  */ 
  this.read = function(filename, cb) {
    // 判斷cb的類型
    if (typeof cb == 'function') {
      // 異步讀取
      var self = this;
      fs.readFile(filename, function(error, data) {
        if (error) return cb(error); // 將error回傳給回調
        var conf = JSON.parse(data); // JSON格式解析
        self.merge(conf); // 將options合併
        cb(); // 吐槽: 作者的設計是就是不給回調任何關於data的信息
      });
    }
    else {
      // 同步讀取
      var conf = JSON.parse(fs.readFileSync(filename));
      this.merge(conf); // 吐槽: 你倒是嵌套地徹底一些啊
    }
    return this;
  };
  /**
   * isDefined: 謂詞:某個參數是否被定義
   * @params: key, 某個參數
   * @return: boolean值, 此參數是否被定義
   *  */ 
  this.isDefined = function(key) {
    return typeof values[key] != 'undefined';
  };
  /**
   * isDefinedAndNonNull: 謂詞:判斷某個參數是否被定義且非空
   * @params: key, 某個參數
   * @return: boolean值, 此參數是否被定義且非空
   *  */ 
  this.isDefinedAndNonNull = function(key) {
    return typeof values[key] != 'undefined' && values[key] !== null;
  };
  // 凍結對象
  Object.freeze(values); // 凍結默認值
  Object.freeze(this); // 凍結
}
// 導出Options類
module.exports = Options;

讀後感大概就是MDZZ。

發佈了61 篇原創文章 · 獲贊 18 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章