Интеллектуальный кеш в R Markdown [дубликат]

Что вы должны знать о this

this (иначе говоря, «контекст») - это специальное ключевое слово внутри каждой функции, и его значение зависит только от , как была вызвана функция, а не как / когда / где она была определена. На него не влияют лексические области, такие как другие переменные (кроме функций стрелок, см. Ниже). Вот несколько примеров:

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

Чтобы узнать больше о this, просмотрите документацию MDN .


Как сделать обратитесь к правильному this

Не используйте this

Фактически вы не хотите иметь доступ к this в частности, но объект, на который он ссылается на . Вот почему простое решение - просто создать новую переменную, которая также относится к этому объекту. Переменная может иметь любое имя, но общие - self и that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

Поскольку self является нормальной переменной, она подчиняется лексическим правилам области и доступна внутри обратного вызова. Это также имеет то преимущество, что вы можете получить доступ к значению this самого обратного вызова.

Явно установить this обратного вызова - часть 1

Возможно, у вас есть не контролируйте значение this, потому что его значение устанавливается автоматически, но на самом деле это не так.

Каждая функция имеет метод .bind [docs] , который возвращает новую функцию с this, привязанную к значению. Функция имеет то же поведение, что и тот, который вы назвали .bind, только то, что this было установлено вами. Независимо от того, как и когда эта функция вызывается, this всегда будет ссылаться на переданное значение.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

В этом случае мы привязываем обратный вызов this к значению MyConstructor 's this.

Примечание. При связывании контекста для jQuery вместо этого используйте jQuery.proxy [docs] . Причина этого заключается в том, что вам не нужно сохранять ссылку на функцию при отмене обратного вызова события. jQuery обрабатывает это внутренне.

ECMAScript 6: Используйте функции стрелок

В ECMAScript 6 представлены функции стрелок , которые можно рассматривать как лямбда-функции. У них нет собственной привязки this. Вместо этого this просматривается в области видимости как обычная переменная. Это означает, что вам не нужно называть .bind. Это не единственное особое поведение, которое у них есть. Дополнительную информацию см. В документации MDN.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

Установите this обратного вызова - часть 2

Некоторые функции / методы, которые принимают обратные вызовы, также принимают значение, к которому должен обращаться обратный вызов this. Это в основном то же самое, что и привязывать его самостоятельно, но функция / метод делает это за вас. Array#map [docs] - такой метод. Его подпись такова:

array.map(callback[, thisArg])

Первый аргумент - это обратный вызов, а второй аргумент - значение this. Вот надуманный пример:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Примечание. Можно ли передать значение для this, как правило, упоминается в документации этой функции / метода. Например, метод $.ajax jQuery [docs] описывает параметр, называемый context:

Этот объект станет контекстом всех обратных вызовов, связанных с Ajax.

blockquote>

Общая проблема: использование объектных методов в качестве обработчиков обратных вызовов / событий

Еще одно распространенное проявление этой проблемы - когда объектный метод используется как обработчик обратного вызова / события , Функции являются первоклассными гражданами в JavaScript, а термин «метод» - просто разговорный термин для функции, которая является значением свойства объекта. Но эта функция не имеет конкретной ссылки на ее «содержащий» объект.

Рассмотрим следующий пример:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

Функция this.method назначается как обработчик события click , но если щелкнуть document.body, зарегистрированное значение будет undefined, потому что внутри обработчика события this ссылается на document.body, а не на экземпляр Foo. Как уже упоминалось в начале, то, что относится к [49], зависит от того, как называется функция, а не от того, как она определена. Если код выглядит следующим образом, может быть более очевидно, что функция не имеет неявной ссылки на объект:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

Решение такое же, как указано выше: если доступно, используйте .bind явно привязать this к определенному значению

document.body.onclick = this.method.bind(this);

или явно вызвать функцию как «метод» объекта, используя анонимную функцию в качестве обработчика обратного вызова / события и назначить object (this) к другой переменной:

var self = this;
document.body.onclick = function() {
    self.method();
};

или использовать функцию стрелки:

document.body.onclick = () => this.method();
6
задан Josh Crozier 2 January 2016 в 04:39
поделиться

1 ответ

Да, вы можете сделать var частью опций chunk, например

<<cached, cache=TRUE, cache.whatever=var>>=
@

cache.whatever не является официальным именем опции chunk, но вы можете использовать произвольные параметры в knitr , и они повлияют на недействительность кеша. В этом случае, когда обновляется var, кеш будет обновлен.

Если вы хотите var воздействовать на все кешированные фрагменты, вы можете установить его как глобальную опцию, но не забудьте установить его как неоценимое выражение:

opts_chunk$set(cache.whatever = quote(var))

Вы можете использовать произвольные выражения R внутри quote(), поэтому, если у вас больше переменных, вы можете поместить их в список, например

opts_chunk$set(cache.whatever = quote(list(var1, var2)))
6
ответ дан Yihui Xie 20 August 2018 в 21:59
поделиться
  • 1
    Спасибо, что ответили, Yihui! То, что вы предложили, работает, когда применяется к каждому фрагменту отдельно, но похоже, что я не могу установить cache.whatever=var в качестве параметра глобального фрагмента. Использование opts_chunk$set(cache.whatever=var) не влияет. Есть ли решение для этой проблемы? – CL. 24 August 2013 в 10:50
  • 2
    @ user2706569 Я отредактировал ответ выше. – Yihui Xie 24 August 2013 в 21:05
  • 3
    Это работает, еще раз спасибо! Возможно, вы должны упомянуть об этом в yihui.name/knitr/demo/cache ? Кстати, мне кажется, что установка opts_chunk$set(cache.whatever = quote(foo)) вызывает ошибку, если foo не задан заранее. Последний вопрос: ни cache.whatever=c(quote(foo), quote(bar)), ни cache.whatever=list(quote(foo), quote(bar)), похоже, не работают. Есть ли другой способ использовать более одной переменной для каждого параметра? – CL. 25 August 2013 в 10:45
  • 4
    @ user2706569 Пожалуйста, не стесняйтесь помочь мне обновить документацию. Для вашего последнего вопроса см. Отредактированный ответ выше. – Yihui Xie 25 August 2013 в 19:29
  • 5
    Я не уверен, могу ли я описать проблему и ее решение достаточно точно, но я буду стараться внести свой вклад в документацию, когда смогу это сделать. Спасибо, что внесли поправки в свой ответ! – CL. 25 August 2013 в 21:17
Другие вопросы по тегам:

Похожие вопросы: