ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript API 設計原則の詳細な紹介

JavaScript API 設計原則の詳細な紹介

黄舟
黄舟オリジナル
2017-03-08 15:02:071312ブラウズ

少し前に、ネイティブ モジュール API (iOS および Android モジュールは JavaScript インターフェイスにカプセル化されています) を整理して最適化したので、古い記事ですが、JavaScript API の設計に関するいくつかの記事を勉強しました。それらをここに記録してください。

優れた API 設計: 自己記述的でありながら抽象化の目標を達成します。

適切に設計された API を使用すると、開発者はマニュアルやドキュメントを頻繁に保管する必要がなく、テクニカル サポート コミュニティに頻繁にアクセスする必要もありません。

スムーズなインターフェイス

メソッドチェーン: スムーズで読みやすく、理解しやすい

//常见的 API 调用方式:改变一些颜色,添加事件监听
var elem = document.getElementById("foobar");
elem.style.background = "red";
elem.style.color = "green";
elem.addEventListener('click', function(event) {
  alert("hello world!");
}, true);

//(设想的)方法链 API
DOMHelper.getElementById('foobar')
  .setStyle("background", "red")
  .setStyle("color", "green")
  .addEvent("click", function(event) {
    alert("hello world");
  });

Set 操作と get 操作を 1 つに組み合わせることができ、メソッドが増えるほど、ドキュメントを書くのが難しくなる可能性があります

var $elem = jQuery("#foobar");

//setter
$elem.setCss("background", "green");
//getter
$elem.getCss("color") === "red";

//getter, setter 合二为一
$elem.css("background", "green");
$elem.css("color") === "red";

一貫性

関連するインターフェイスが一貫したスタイルを維持している場合、API の完全なセットが使い慣れた快適な感覚を伝えれば、開発者の新しいツールへの適応が大幅に容易になります。

物事に名前を付ける: 短く、自己記述的で、最も重要なのは一貫性です

「コンピューター サイエンスにおける難しい問題は 2 つだけです。それは、キャッシュの無効化と物事の名前付けです。」
「コンピューター サイエンスにおいて、頭の痛い問題は世界に 2 つだけです。」 : キャッシュの無効化と名前付けの問題」
— Phil Karlton

好きな言葉遣いを選んで、それを使い続けてください。スタイルを選択し、それを維持します。

パラメータを処理するとき

、提供したメソッドが人々によってどのように使用されるかを考慮する必要があります。繰り返し呼び出されるでしょうか?なぜ繰り返し呼び出されるのですか?開発者が重複呼び出しを減らすために API はどのように役立ちますか?
マップ マッピング パラメーター、コールバック、またはシリアル化された属性名を受け取ることで、API がクリーンになるだけでなく、より快適かつ効率的に使用できるようになります。

jQuery の css() メソッドは DOM 要素のスタイルを設定できます: css() 方法可以给 DOM 元素设置样式:

jQuery("#some-selector")
  .css("background", "red")
  .css("color", "white")
  .css("font-weight", "bold")
  .css("padding", 10);

这个方法可以接受一个 JSON 对象:

jQuery("#some-selector").css({
  "background" : "red",
  "color" : "white",
  "font-weight" : "bold",
  "padding" : 10
});

//通过传一个 map 映射绑定事件
jQuery("#some-selector").on({
  "click" : myClickHandler,
  "keyup" : myKeyupHandler,
  "change" : myChangeHandler
});

//为多个事件绑定同一个处理函数
jQuery("#some-selector").on("click keyup change", myEventHandler);

处理类型

定义方法的时候,需要决定它可以接收什么样的参数。我们不清楚人们如何使用我们的代码,但可以更有远见,考虑支持哪些参数类型。

//原来的代码
DateInterval.prototype.days = function(start, end) {
  return Math.floor((end - start) / 86400000);
};

//修改后的代码
DateInterval.prototype.days = function(start, end) {
  if (!(start instanceof Date)) {
    start = new Date(start);
  }
  if (!(end instanceof Date)) {
    end = new Date(end);
  }

  return Math.floor((end.getTime() - start.getTime()) / 86400000);
};

加了短短的6行代码,我们的方法强大到可以接收 Date 对象,数字的时间戳,甚至像 Sat Sep 08 2012 15:34:35 GMT+0200 (CEST) 这样的字符串

如果你需要确保传入的参数类型(字符串,数字,布尔),可以这样转换:

function castaway(some_string, some_integer, some_boolean) {
  some_string += "";
  some_integer += 0; // parseInt(some_integer, 10) 更安全些
  some_boolean = !!some_boolean;
}

处理 undefined

为了使你的 API 更健壮,需要鉴别是否真正的 undefined 值被传递进来,可以检查 arguments 对象:

function testUndefined(expecting, someArgument) {
  if (someArgument === undefined) {
    console.log("someArgument 是 undefined");
  }
  if (arguments.length > 1) {
    console.log("然而它实际是传进来的");
  }
}

testUndefined("foo");
// 结果: someArgument 是 undefined
testUndefined("foo", undefined);
// 结果:  someArgument 是 undefined , 然而它实际是传进来的

给参数命名

event.initMouseEvent(
  "click", true, true, window,
  123, 101, 202, 101, 202,
  true, false, false, false,
  1, null);

Event.initMouseEvent 这个方法简直丧心病狂,不看文档的话,谁能说出每个参数是什么意思?

给每个参数起个名字,赋个默认值,可好

event.initMouseEvent(
  type="click",
  canBubble=true,
  cancelable=true,
  view=window,
  detail=123,
  screenX=101,
  screenY=202,
  clientX=101,
  clientY=202,
  ctrlKey=true,
  altKey=false,
  shiftKey=false,
  metaKey=false,
  button=1,
  relatedTarget=null);

ES6, 或者 Harmony 就有 默认参数值 和 rest 参数 了。

参数接收 JSON 对象

与其接收一堆参数,不如接收一个 JSON 对象:

function nightmare(accepts, async, beforeSend, cache, complete, /* 等28个参数 */) {
  if (accepts === "text") {
    // 准备接收纯文本
  }
}

function dream(options) {
  options = options || {};
  if (options.accepts === "text") {
    // 准备接收纯文本
  }
}

调用起来也更简单了:

nightmare("text", true, undefined, false, undefined, /* 等28个参数 */);

dream({
  accepts: "text",
  async: true,
  cache: false
});

参数默认值

参数最好有默认值,通过 jQuery.extend() http://www.php.cn/) 和 Protoype 的 Object.extend ,可以覆盖预设的默认值。

var default_options = {
  accepts: "text",
  async: true,
  beforeSend: null,
  cache: false,
  complete: null,
  // …
};

function dream(options) {
  var o = jQuery.extend({}, default_options, options || {});
  console.log(o.accepts);
}

dream({ async: false });
// prints: "text"

扩展性

回调(callbacks)

通过回调, API 用户可以覆盖你的某一部分代码。把一些需要自定义的功能开放成可配置的回调函数,允许 API 用户轻松覆盖你的默认代码。

API 接口一旦接收回调,确保在文档中加以说明,并提供代码示例。

事件(events)

事件接口最好见名知意,可以自由选择事件名字,避免与原生事件 重名。

处理错误

不是所有的错误都对开发者调试代码有用:

// jQuery 允许这么写
$(document.body).on('click', {});

// 点击时报错
//   TypeError: ((p.event.special[l.origType] || {}).handle || l.handler).apply is not a function
//   in jQuery.min.js on Line 3

这样的错误调试起来很痛苦,不要浪费开发者的时间,直接告诉他们犯了什么错:

if (Object.prototype.toString.call(callback) !== '[object Function]') { // 看备注
  throw new TypeError("callback is not a function!");
}

备注:typeof callback === "function" 在老的浏览器上会有问题,object 会当成个 function

// 所有这些属性都返回 'true' 或 'false'
Modernizr.geolocation
Modernizr.localstorage
Modernizr.webworkers
Modernizr.canvas
Modernizr.borderradius
Modernizr.boxshadow
Modernizr.flexbox

このメソッドは JSON オブジェクトを受け入れることができます:
$("#grid") // Selects by ID
$("ul.nav > li") // All LIs for the UL with class "nav"
$("ul li:nth-child(2)") // Second item in each list

処理タイプ

メソッドを定義するとき、どのパラメータを受け入れることができるかを決定します。人々が私たちのコードをどのように使用するかはわかりませんが、より前向きになって、どのようなパラメータのタイプをサポートするかを検討することはできます。

rrreee

わずか 6 行のコードで、私たちのメソッドは、Date オブジェクト、数値タイムスタンプ、さらには Sat Sep 08 2012 15:34:35 GMT+ 0200 (CEST) などを受け入れるのに十分強力です。 ) このような文字列です

受信パラメータの型 (文字列、数値、ブール値) を確認する必要がある場合は、次のように変換できます:

rrreee

未定義の処理

順序API をより堅牢にするために、実際の unknown 値が渡されたかどうかを識別する必要がある場合は、arguments オブジェクトを確認できます。パラメータrrreee

Event.initMouseEvent このメソッドは単純にクレイジーです。ドキュメントを読まなければ、各パラメータが何を意味するのか誰にもわかりません。

各パラメータに名前を付け、デフォルト値を割り当てます。できれば

rrreee

ES6、またはHarmonyには「デフォルトパラメータ値」と「残りのパラメータ」があります。

パラメータは JSON オブジェクトを受け取ります

大量のパラメータを受け取る代わりに、JSON オブジェクトを受け取る方が良いです:

rrreee

また、呼び出しも簡単です:

rrreee

パラメータのデフォルト値 h2>パラメータにはデフォルト値が存在します。 jQuery.extend() http://www.php.cn/) および Protoype の Object.extend を介して、プリセットのデフォルト値をオーバーライドできます。

rrreee

拡張性

コールバック

コールバックを通じて、API ユーザーはコードの特定の部分を上書きできます。カスタマイズが必要な一部の関数を構成可能なコールバック関数に開くと、API ユーザーがデフォルトのコードを簡単にオーバーライドできるようになります。 🎜🎜 API インターフェースがコールバックを受け取ったら、必ずそれを文書化し、コード例を提供してください。 🎜

イベント

🎜 ネイティブ イベントとの名前の重複を避けるために、イベント インターフェイスの名前を知っておくことが最善です。 🎜🎜エラーの処理🎜🎜 すべてのエラーが開発者によるコードのデバッグに役立つわけではありません:🎜rrreee🎜そのようなエラーはデバッグが困難です。開発者の時間を無駄にせず、開発者にどのような間違いを犯したかを直接伝えてください:🎜rrreee🎜🎜 備考: typeof callback === "function" は古いブラウザでは問題を引き起こし、objectfunction として扱われます。 🎜🎜🎜予測可能性🎜🎜 優れた API は予測可能であり、開発者は例に基づいてその使用法を推測できます。 🎜🎜Modernizr の機能検出はその一例です: 🎜🎜a) HTML5、CSS の概念、API に完全に一致する属性名を使用します 🎜🎜b) 個々の検出は一貫して true または false の値を返します 🎜rrreee🎜 開発者に依存します 馴染みのある概念は、予測可能な目的にも役立ちます。 🎜🎜jQuery のセレクター構文は、CSS1 ~ CSS3 セレクターを DOM セレクター エンジンで直接使用できる例です。 🎜rrreee🎜比例調整🎜🎜 優れた API は、必ずしも小さい API である必要はありません。API のサイズは、その機能に見合ったものでなければなりません。 🎜🎜たとえば、有名な日付解析および書式設定ライブラリである Moment.js は、その API が簡潔かつ機能的であると言えます。 🎜🎜 Moment.js のような関数固有のライブラリの場合、API が焦点を絞って小さいことを確認することが非常に重要です。 🎜

API ドキュメントの作成

ソフトウェア開発で最も難しいタスクの 1 つは、ドキュメントを作成することです。実際、最大の不満は、使いやすいドキュメント ツールがないことです。

以下は自動ドキュメント生成ツールです:

  • YUIDoc (Node.js、npmが必要)

  • JsDoc Toolkit (Node.js、npmが必要)

  • Markdox (Node.js、npmが必要) )

  • dox(node.js、npmが必要)

  • docco(node.js、python、coffeescriptが必要)

  • jsduck(ruby、gemが必要)

  • jsdoc3(Javaが必要)

最も重要なことは、ドキュメントとコードが同時に更新されていることを確認することです。

参考文献:

  • 優れたAPI設計

  • より良いJavaScript APIの設計

  • 素晴らしいJavaScript API設計の秘密


以上がJavaScript API 設計原則の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。