Какая функция JavaScript javascript объекта (какова ее "this")? - программирование
Подтвердить что ты не робот

Какая функция JavaScript javascript объекта (какова ее "this")?

Я знаю, что внутри функции это 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()

Отредактировано:

Фактически вы не вызываете obj2.f(), поскольку f не становится свойством obj2

конец редактирования.

Возникает вопрос: как найти объект, связанный с функцией, вне этой функции?

Я хочу добиться этого:

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);
}

и частичное приложение без изменения объекта, к которому привязана функция:

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

Консенсус:

Вы не можете этого сделать. Takeaway: используйте bind и this с большой осторожностью:)

4b9b3361

Ответ 1

Частичное приложение

Вы можете выполнить частичное приложение:

// 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)));
    };

}

Какой объект привязан к этой функции?

Кроме того, есть довольно прямолинейное решение первой части вашего вопроса. Не уверен, что это вариант для вас, но вы можете довольно легко обезглавить вещи в JS. Обезболивание bind вполне возможно.

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;
    }
});

Просто запустите это, прежде чем запускать любые другие скрипты, и любой script, который использует bind, он автоматически добавит свойство boundObject к функции:

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

(Примечание. Я предполагаю, что вы находитесь в среде ES5 выше из-за того, что используете bind.)

Ответ 2

Функция в javascript технически не связана ни с чем. Он может быть объявлен как свойство объекта, как в:

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

Но если вы сами введете функцию в свою собственную переменную, она не привязана к какому-либо конкретному объекту.

Например, если вы это сделали:

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

Затем, когда вы вызываете func(), который, в свою очередь, выполняет функцию fn(), он вообще не будет связываться с obj при его вызове. Связывание объекта с функцией выполняется вызывающей функцией. Это не свойство функции.

Если нужно использовать fn.bind(obj), это создает новую функцию, которая только внутренне выполняет вызов obj.fn(). Он не волшебным образом добавляет новые возможности в javascript. Фактически вы можете увидеть polyfill для .bind(), чтобы увидеть, как он работает здесь, в MDN.


Если вы ожидаете, что this всегда будет конкретным объектом независимо от того, как вызывается функция, это не то, как работает javascript. Если функция на самом деле не является прокладкой, которая заставляет ассоциацию с жестким wird объектом при вызове (что делает .bind()), то функция не имеет жесткой связи. Связь выполняется вызывающим абонентом в зависимости от того, как она вызывает функцию. Это отличается от некоторых других языков. Например, в С++ вы не можете вызывать функцию, не имея подходящего объекта для связи с ней во время вызова. Язык просто не разрешит вызов функции, и вы получите ошибку компиляции.

Если вы разветвляетесь по типам в javascript, то вы, вероятно, не используете объектно-ориентированные возможности языка правильно или в ваших лучших интересах.

Ответ 3

Вместо привязки функции func к объектам, почему бы не попробовать обрабатывать func как объект, который может содержать obj1 и obj2 как свои свойства?

Например:

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;

Вы также можете написать функцию, которая обрабатывает объект obj1 или 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);
}

Причина в том, что вы хотите рассматривать obj1 и obj2 как свойство функции f. Однако при связывании вы добавляете функцию как свойство obj1 или obj2. Возможно привязать функцию к нескольким объектам, поэтому не имеет смысла искать один объект, к которому вы привязали функцию; потому что вы добавляете функцию как подмножество объекта.

В этом случае, поскольку вы хотите рассматривать объект как подмножество функции, может иметь смысл добавить свойство в функцию, которая может содержать obj1 или obj2.

Ответ 4

Если вы выполняете привязку, вы можете добавить поле в функцию, чтобы записать это для последующего тестирования.

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