Quel objet la fonction javascript est liée à (quel est son "ceci")?

je sais qu'à l'intérieur de la fonction, c'est this.

var func = function {
    return this.f === arguments.callee; 
    // => true, if bound to some object
    // => false, if is bound to null, because this.f === undefined
}

var f = func; // not bound to anything;

var obj = {};
obj1.f = func; // bound to obj1 if called as obj1.f(), but not bound if called as func()

var bound = f.bind(obj2) // bound to obj2 if called as obj2.f() or as bound()

Édition:

Vous ne pouvez pas appeler obj2.f()f ne devient pas une propriété de obj2

modifier la fin.

La question est: comment faire pour trouver l'objet, que la fonction est liée, en dehors de cette fonction?

je veux réaliser ceci:

function g(f) {
  if (typeof(f) !== 'function') throw 'error: f should be function';

  if (f.boundto() === obj)
    // this code will run if g(obj1.f) was called
    doSomething(f);

  // ....

  if (f.boundto() === obj2)
    // this code will run if g(obj2.f) or g(bound) was called
    doSomethingElse(f);
}

et l'application partielle sans changer l'objet que la fonction est liée à:

function partial(f) {
   return f.bind(f.boundto(), arguments.slice(1));
}

Consensus:

Vous ne pouvez pas le faire. À emporter: utiliser bind et this avec le plus grand soin :)

16
demandé sur esp 2013-01-13 23:28:16

4 réponses

Application Partielle

Vous pouvez faire une application partielle:

// This lets us call the slice method as a function
// on an array-like object.
var slice = Function.prototype.call.bind(Array.prototype.slice);

function partial(f/*, ...args */) {

    if (typeof f != 'function')
        throw new TypeError('Function expected');

    var args = slice(arguments, 1);

    return function(/* ...moreArgs */) {
        return f.apply(this, args.concat(slice(arguments)));
    };

}

à quel objet cette fonction est-elle liée?

de plus, il y a une solution assez simple à la première partie de votre question. Pas sûr si c'est une option pour vous, mais vous pouvez assez facilement singe-patch choses dans JS. Singe de correction bind est tout à fait possible.

var _bind = Function.prototype.apply.bind(Function.prototype.bind);
Object.defineProperty(Function.prototype, 'bind', {
    value: function(obj) {
        var boundFunction = _bind(this, arguments);
        boundFunction.boundObject = obj;
        return boundFunction;
    }
});

Lancez juste cela avant que d'Autres scripts ne soient lancés, et n'importe script qui utilise bind, il ajoutera automatiquement un boundObject propriété de la fonction:

function f() { }
var o = { };
var g = f.bind(o);
g.boundObject === o; // true

(Note: je suppose que vous êtes dans un environnement ES5 ci-dessus en raison du fait que vous utilisez bind.)

10
répondu Nathan Wall 2013-01-13 23:24:18

une fonction en javascript n'est techniquement liée à rien. Il peut être déclaré comme une propriété d'un objet, comme dans:

var obj = {
    fn: function() {}
}
obj.fn();

Mais, si vous obtenez la fonction dans une variable par lui-même, il n'est lié à aucun objet particulier.

Par exemple, si vous avez fait ceci:

var obj = {
    fn: function() {}
}
var func = obj.fn;
func();

puis, quand vous appelez func() qui exécute l' fn() la fonction, il n'aura pas d'association avec obj quand il est appelé. L'association d'une objet avec une fonction se fait par l'appelant de la fonction. Ce n'est pas une propriété de la fonction.

si on utilise fn.bind(obj), qui crée une nouvelle fonction qui à l'interne exécute un appel à obj.fn(). Il n'ajoute pas par magie de nouvelles capacités au javascript. En fait, vous pouvez voir un polyfill pour .bind() pour voir comment ça fonctionne ici sur MDN.


si vous attendez this toujours être un objet particulier n'importe comment une fonction est appelée, ce n'est pas comme ça que fonctionne javascript. A moins qu'une fonction ne soit en fait un shim qui force une association avec un objet hard-wird quand on l'appelle (qu'est-ce que .bind()), puis une fonction n'a pas un câblé association. L'association se fait par l'appelant basé sur la façon dont il appelle la fonction. Ceci est différent de celui de certaines autres langues. Par exemple, en C++, vous ne pouvez pas appeler une fonction sans avoir le bon objet pour s'y associer au moment de l'appel. Langue ne résoudra tout simplement pas l'appel de fonction et vous obtenez une erreur de compilation.

si vous branchez sur des types en javascript, alors vous n'utilisez probablement pas les capacités orientées objet du langage correctement ou à votre meilleur avantage.

4
répondu jfriend00 2018-02-06 04:50:19

au Lieu de lier la fonction func aux objets, pourquoi ne pas essayer de traiter func comme un objet, qui peut contenir obj1 et obj2 que ses propriétés?

Par exemple:

var func = function {
    this.object; // Could be obj1 or obj2
    return this.f === arguments.callee;
    // => true, if this.object is not null
}

var f = func;

f.object = obj1; // or func.object = obj2;

Vous pouvez aussi écrire une fonction qui gère savoir si ou non l'objet obj1 ou obj2:

function g(f) {
  if (typeof(f) !== 'function') throw 'error: f should be function';

  if (f.object === obj)
    // this code will run if g(f) was called
    doSomething(f);
  if (f.object === obj2)
    // this code will run if g(f) or g(bound) was called
    doSomethingElse(f);
}

La raison en est que vous voulez traiter obj1 et obj2 comme une propriété de la fonction f. Cependant, lorsque vous liez, vous ajoutez la fonction comme propriété de l'un ou l'autre obj1 ou obj2. Il est possible de lier la fonction à plusieurs objets, de sorte qu'il n'est pas logique de chercher le seul objet auquel vous avez lié la fonction; parce que vous ajoutez la fonction comme un sous-ensemble de l'objet.

Dans ce cas, puisque vous voulez traiter l'objet comme un sous-ensemble de la fonction, il pourrait être judicieux d'ajouter une propriété dans la fonction qui permet de tenir obj1 ou obj2.

3
répondu Stegrex 2013-01-13 20:57:52

Si vous faites la liaison, vous pouvez ajouter un champ à la fonction d'enregistrement de la ce pour des tests ultérieurs.

var that = "hello";
var xyz = function () { console.log(this); }.bind(that);
xyz.that = that;

// xyz is callable as in xyz(), plus you can test xyz.that without calling
2
répondu Erik Eidt 2013-01-13 20:21:59