Как я могу ссылаться на объект внутри одной из его функций-членов? - PullRequest
1 голос
/ 20 февраля 2009

У меня есть следующее:

var o = {f: function(fn) {
    fn.call(o);
}};
var ob = {f: function() {
    o.f(function() {
        this.x = 2; //HERE: how can this reference ob?
        //ob.x = 2;
    });
}};
ob.f();
ob.x; // undefined

o.f(fn) звонки fn, где this связан с o.

ЗДЕСЬ, я хочу использовать this для доступа к об. Однако, когда вызывается ob.f, this связывается с o. JQuery работает так, я думаю. Например:

$(...).blah(function() {
    this // this is bound to $(...) jquery object.
    ...
};

То, что я сейчас делаю, это:

var Ob = function() {
    var self = this;
    self.f = function() {
        o.f(function() { self.x = 2; };
    };
};
var ob = new Ob();
ob.f();
ob.x; // 2

Но мне не нравится выше по стилистическим соображениям:

  1. Использование оператора new звучит как слишком классический ООП.
  2. Определение <strong>class</strong> Ob с использованием function не является интуитивно понятным (по крайней мере, в начале).

Вот почему я пытаюсь определить ob с помощью литерала объекта. Но я не могу найти способ ссылаться на объект ob в функции который использует вызов метода, который устанавливает this для другого объекта, чем ob.

Я могу сделать что-то вроде следующего:

var ob = {f: function() {
    o.f(function() {
        self.x = 2;
    });
}};
var self = ob;
ob.f();
ob.x;

Но я не знаю, как учесть выше. Я попробовал:

function obj(o) {
    return function() {
        var self = o;
        return o;
    }();
}
var ob = obj({f: function() {
    o.f(function() {
        self.x = 2;
    });
}});
ob.f();
ob.x;// ReferenceError: self is not defined

Итак, есть ли способ ссылаться на объект в функции внутри объекта? надежно (this может привязываться к чему-либо в зависимости от контекста)?

Ответы [ 3 ]

3 голосов
/ 20 февраля 2009

В JavaScript функции - это объекты, имеющие два метода для вызова функции:

call(scope, arg1, arg2, ...);
apply(scope, args);  // args is an array of arguments to call the function with

Первый аргумент, "scope", - это объект, который связан с "this" внутри функции. Итак, следующие примеры эквивалентны:

obj.method(1, 2, 3);
obj.method.call(obj, 1, 2, 3);
obj.method.apply(obj, [1, 2, 3]);

В первом примере вы вызываете функцию, переданную o.f (), используя 'o' в качестве области действия:

var o = {f: function(fn) {
    fn.call(o);
}};

Поэтому ваша функция передается в 'ob', ссылаясь на 'o' так:

var ob = {f: function() {
    o.f(function() {
        this.x = 2; //HERE: how can this reference ob?
        //ob.x = 2;
    });
}};

В строке «ЗДЕСЬ» на самом деле это «о».

Вы можете попробовать следующее:

var ob = {f: function() {
    var self = this;
    o.f(function() {
        self.x = 2; // self is ob now
    });
}};

Или вы можете изменить функцию 'o.f', чтобы получить параметр области действия:

var o = {f: function(fn, scope) {
    fn.call(scope || this); // Uses the given scope or this (= 'o') if no scope is provided
}};

Тогда вы можете передать «this» в «ob»:

var ob = {f: function() {
    o.f(function() {
        this.x = 2; // 'this' will be the 'outer' this
    }, this); // Here: this as scope
}};
1 голос
/ 20 февраля 2009

Следуя простому шаблону конструктора Дугласа Крокфорда, я бы сделал функцию-конструктор, которая использует литерал объекта вместо new. Как это:

var o = {f: function(fn) {
    fn.call(o);
}};

function obj() {
    var me = {};
    me.f = function () {
        o.f(function() {
            me.x = 2;
        });
    };
    return me;
}

var ob = obj();
ob.f();
ob.x; // 2
0 голосов
/ 20 февраля 2009

Вы можете сделать это без вспомогательных функций, просто используя литералы:

var o = {f: function(fn) {
    fn.call(o);
}};
var ob = {f: function() {
    var self = this; // this == ob
    o.f(function() {
        self.x = 2; // self == enclosing function's this == ob
    });
}};
ob.f();
assert(ob.x == 2);
...