确定JavaScript函数是否为绑定函数

时间:2016-02-28 18:56:05

标签: javascript function

有没有办法确定JavaScript函数是否为bound function

示例:

var obj = {
  x:1  
};

function printX() {
    document.write(this.x);
}

function takesACallback(cb) {
  // how can one determine if this is a bounded function
  // not just a function?
  if (typeof cb === 'function') {
    cb();  
  }
}

takesACallback(printX.bind(obj)); // 1
takesACallback(printX);           // undefined

也许这是一个重点。我不是在问为什么第二个调用打印未定义。

7 个答案:

答案 0 :(得分:29)

绑定函数和箭头函数都没有prototype属性:

typeof (function() {}).prototype // 'object' as usual
typeof (function() {}).bind(null).prototype // 'undefined'!
typeof (() => {}).prototype // 'undefined'!

这不是100%安全,因为您仍然可以手动分配此属性(虽然这很奇怪)。
因此,检查可绑定性的简单方法如下:

// ES5
function isBindable(func) {
  return func.hasOwnProperty('prototype');
}

// ES6
const isBindable = func => func.hasOwnProperty('prototype');

用法:

isBindable(function () {}); // true
isBindable(() => {}); // false
isBindable(
  (function () {}).bind(null)
); // false

通过这种方式,您可以确保已传递的函数可以处理动态this

以上是上述失败的示例用法:

const arrowFunc = () => {};
arrowFunc.prototype = 42;

isBindable(arrowFunc); // true :(

有趣的是,虽然绑定函数没有prototype属性,但它们仍然可以用作构造函数(new):

var Animal = function(name) {
   this.name = name;
};

Animal.prototype.getName = function() {
  return this.name;
};

var squirrel = new Animal('squirrel');
console.log(squirrel.getName()); // prints "squirrel"

var MutatedAnimal = Animal.bind({}); // Radiation :)
console.log(MutatedAnimal.hasOwnProperty('prototype')); // prints "false"

var mutatedSquirrel = new MutatedAnimal('squirrel with two heads');
console.log(mutatedSquirrel.getName()); // prints "squirrel with two heads"

在这种情况下,使用原始函数prototypeAnimal) 请参阅JS Bin,代码和Dmitri Pavlutin提供的链接。

这当然不能使用箭头功能,因为它们不能用作构造函数。

不幸的是,我不知道是否有办法区分绑定函数(可用作构造函数)和箭头函数(不能用作构造函数)而try不能用{{1}并检查它是否抛出(new抛出"不是构造函数" 错误。)

答案 1 :(得分:12)

在支持ES6的环境中,您可以检查函数名称是否以"bound "开头(单词“bound”后跟空格)。

来自规范:

  

19.2.3.2 Function.prototype.bind ( thisArg , ...args)

     

[...]

     

15。执行SetFunctionName F targetName ,“绑定”)。

当然,如果手动更改了该功能的名称,可能会导致误报。

答案 2 :(得分:2)

可以覆盖现有的原型绑定,标记已绑定的函数。

一个简单的解决方案。但是,由于隐藏的类,这可能会导致V8中的某些优化(以及可能的其他运行时)。



(function (bind) {
  Object.defineProperties(Function.prototype, {
    'bind': {
      value: function (context) {
        var newf = bind.apply(this, arguments);
        newf.context = context;

        return newf;
      }
    },
    'isBound': {
      value: function () {
        return this.hasOwnProperty('context');
      }
    }
  });
}(Function.prototype.bind));




动议:



(function (bind) {
  Object.defineProperties(Function.prototype, {
    'bind': {
      value: function (context) {
        var newf = bind.apply(this, arguments);
        newf.context = context;

        return newf;
      }
    },
    'isBound': {
      value: function () {
        return this.hasOwnProperty('context');
      }
    }
  });
}(Function.prototype.bind));

var a = function () {
  console.log(this);
};
var b = {
  b: true
};
var c = a.bind(b);

console.log(a.isBound())
console.log(c.isBound())
console.log(c.context === b);
a();
c();




答案 3 :(得分:1)

根据以前的答案,我创建了一个函数来确定:

function isBoundFunction(func) {
    if(typeof func.prototype === 'object') return false
    try {
        new func()
    }
    catch(e) {
        return false
    }
    return true
}

该函数确定三种类型的函数:1。原始函数,其原型是对象,2。箭头函数,不能用作构造函数,3。绑定函数。

答案 4 :(得分:1)

我是新来的,没有足够的声誉发表评论,只是答案。对不起,但这不能回答OP,因为我不知道怎么做。我希望我做到了。

然而,依赖于遗失的prototype财产的非常常见的答案不会起作用。类方法,对象中的方法定义和async函数也不具有prototype属性,但它们不是自然绑定的。

另外,请记住,仍然可以通过闭包手动绑定一个函数,这将无视任何检测其绑定状态的尝试:

const bind=(fn,obj)=>{
    return (...args)=>{
        return fn.apply(obj,args)
    }
}

答案 5 :(得分:0)

有一个模块可以帮助您解决此问题:bind2

这是一个用例:

const bind2 = require('bind2');

function test() {
  return this.hello;
}
const context = { hello: 'world' };

console.log(bind2(test, context)); // true

完全公开:我编写了此模块。

答案 6 :(得分:-1)

您需要在原型上编写自己的bind函数。该函数将构建已绑定的索引。

然后,您可以使用另一个函数对存储该索引的对象执行查找。