39

リクエスト ハンドラからいくつかのデータベース関数を呼び出しています。これらの関数はすべて、エラーを処理するための個別の「エラー コールバック」を行います。例:

function referralComplete(req, res) {
    /*getting id etc.*/
    db.startDatabaseConnection(function() {
        db.flagReferralAsDone(id, function(success) {
            db.endDatabaseConnection();
            /*doing stuff on success*/
        }, onError);
    }, onError);

    function onError(err, description) {
        logger.error(description + ": " + err);
        user.pageNotFound(req, res);
    }
}

これに似たいくつかのリクエストハンドラーがあり、すべて異なるデータベース関数を呼び出しています。現時点では、エラーを処理する必要があるため、それぞれのスコープに重複しonError()ていますが、重複せずに同じことを達成する方法があると思います。reqres

だから問題は、どうにかしてバインドreqresて、各リクエストハンドラーonError()に複製する必要がないようにすることは可能でしょうか?onError()

4

1 に答える 1

85

結び方は簡単!

db.startDatabaseConnection(function(){
  // whatever
}, onError.bind(this, var1, var2));

リンクはちょっと長いですが、この素晴らしいリンクをクリックすることで、バインドについて詳しく知ることができます

ここに本当の基本的なデモがあります

// a function
var something = function (a, b, c) {
  console.log(a, b, c);
};

// a binding of something with 3 defined args
var b = something.bind(null, 1, 2, 3);

// call b
b();
//=> 1 2 3

舞台裏で、これは基本的に何が起こっているかです

// ES6
const myBind = (f, context, ...x) =>
  (...y) => f.call(context, ...x, ...y);

// ES5
var myBind = function(fn, context) {
  var x = Array.prototype.slice.call(arguments, 2);
  return function() {
    var y = Array.prototype.slice.call(arguments, 0); 
    return fn.apply(context, x.concat(y));
  };
};

var b = myBind(console.log, console, 1, 2, 3);

b();
// => 1 2 3

b(4,5,6)
// => 1 2 3 4 5 6 

環境?

Context を使用すると、関数の を動的に変更できますthisfunctionキーワードで定義された関数のコンテキストのみをバインドできることに注意してください。アロー関数には、this操作できないレキシカルがあります。これは完全を期すために示されていますが、この種のプログラムは使用しないことをお勧めします。通常は、動的関数コンテキストに依存するのではなく、別の関数パラメーターを使用することをお勧めしますthis。このようなコンテキスト切り替えをサポートするのは、JavaScript でオブジェクト指向スタイルを有効にするためです。このスタイルを使用していない限り、コンテキストに注意を払う理由はないと思います。

const getCanvas = (id) =>
  document.getElementById(id).getContext('2d')

const draw = function (canvas, x = 0, y = 0)
{ canvas.beginPath()
  canvas.strokeStyle = this.color             // `this` refers to context!
  canvas.rect(x, y, this.width, this.height)  // `this` refers to context!
  canvas.stroke()
}

// create two contexts
const contextA =
  { color: 'blue', width: 10, height: 10 }
  
const contextB =
  { color: 'green', width: 10, height: 20 }

// bind the draw function to each context and the canvas
const drawA =
  draw.bind(contextA, getCanvas('main'))
  
const drawB =
  draw.bind(contextB, getCanvas('main'))

// call the bound drawing functions normally
// draw three blue squares
drawA(0, 0)
drawA(20, 0)
drawA(40, 0)

// and one green rect
drawB(80, 0)
<canvas id="main"></canvas>

部分適用

binding に似ているのは部分適用です

コンピューター サイエンスでは、部分適用 (または部分関数適用) とは、多数の引数を関数に固定し、より小さなアリティの別の関数を生成するプロセスを指します。

ここでは、partialこれを実現するのに役立つ非常に単純なヘルパー プロシージャを作成できます。

const identity = x =>
  x

const partial = (f = identity, ...x) =>
  (...y) => f (...x, ...y)

const foo = (...all) =>
  console.log ('array of', all)

partial (foo, 1, 2, 3) (4, 5, 6)
// 'array of', [ 1, 2, 3, 4, 5, 6 ]


カリー

カリー化はバインディングまたは部分適用に関連していますが、同じではありません

数学とコンピューター サイエンスでは、カリー化とは、複数の引数 (または引数のタプル) を取る関数の評価を、それぞれが 1 つの引数を持つ一連の関数の評価に変換する手法です。

const identity = x =>
  x

const curry = (f = identity, arity = f.length) => x =>
{
  const next = (xs = []) =>
    xs.length >= arity
      ? f (...xs)
      : x => next ([ ...xs, x ])
  return next ([ x ])
}

const foo = (a, b, c) =>
  console.log ('a', a, 'b', b, 'c', c)

curry (foo) (1) (2) (3)
// 'a' 1 'b' 2 'c' 3

curry (foo) ('choo') ('bye') ()
// 'a' 'choo' 'b' 'bye' 'c' undefined

于 2013-07-17T22:17:32.153 に答える