From 501bbf1f8445d8fefaac8f15e61629808a27bff8 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 31 Dec 2015 17:06:29 -0800 Subject: [PATCH] make `this` respect a target if one is used Otherwise when invoked "globally", `this` is set to the function instance --- README.md | 11 +++++++++-- index.js | 7 ++++++- test.js | 12 ++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bfb14e0..1524de8 100644 --- a/README.md +++ b/README.md @@ -99,16 +99,23 @@ var fn = createFunction('name', 0, FunctionSubclass, args); ### invoke → Symbol You use the `invoke` Symbol to define the function to execute when a created -function instance is invoked. Note that `this` in the invoke function is bound to -the created function instance. +function instance is invoked. + +Note that `this` in the invoke function is bound to the created function instance +when invoked without a receiver (i.e. "globally"). Otherwise, `this` respects the +left-hand receiver, or target when used with `.call()`/`.apply()`. ``` js var invoke = require('function-class/invoke'); fn[invoke] = function () { console.log('fn has been invoked!'); + return this; }; fn(); // fn has been invoked! + +assert.equal(fn(), fn); +assert.equal(fn.call(global), global); ``` diff --git a/index.js b/index.js index 5327c9b..361af04 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,12 @@ function createFunctionInstance (name, length, constructor, args) { // create function instance fn = functionNameArity(name, length, function () { - return fn[invoke].apply(fn, arguments); + "use strict"; + var invokeFn = fn[invoke]; + if (typeof invokeFn !== 'function') + throw new Error('you must define the `[function-class/invoke]` function on this instance'); + var thisArg = typeof this === 'undefined' ? fn : this; + return invokeFn.apply(thisArg, arguments); }); if (constructor) { diff --git a/test.js b/test.js index b921380..507d2b0 100644 --- a/test.js +++ b/test.js @@ -86,3 +86,15 @@ assert.ok(oneOffCalled); var snowman = createFunction('⌛', 30); assert.equal(snowman.name, '⌛'); assert.equal(snowman.length, 30); + + +// `this` arg +var thisArg = createFunction(); +thisArg[invoke] = function () { + return this; +}; +assert.equal(thisArg(), thisArg); +assert.equal(thisArg()()(), thisArg()); +assert.equal(thisArg.call(global), global); +assert.equal(thisArg.call(1).valueOf(), 1); +assert.equal(thisArg.call(true).valueOf(), true);