У функции reader.onload есть триггер события? [Дубликат]

Моим лучшим решением для R Markdown было создание куска кода только для загрузки библиотек и исключения всего в куске.

{r results='asis', echo=FALSE, include=FALSE,}
knitr::opts_chunk$set(echo = TRUE, warning=FALSE)
#formating tables
library(xtable)

#data wrangling
library(dplyr)

#text processing
library(stringi)
987
задан T.J. Crowder 11 July 2017 в 18:32
поделиться

9 ответов

Что вы должны знать о 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.


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

Еще одно распространенное проявление этой проблемы - когда объектный метод используется как обработчик обратного вызова / события , Функции являются первоклассными гражданами в 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();
1222
ответ дан NomadeNumerique 16 August 2018 в 00:16
поделиться
  • 1
    Феликс, я уже читал этот ответ, но не ответил. Я очень обеспокоен тем, что люди используют self и that для ссылки на this. Я так чувствую, потому что this - перегруженная переменная, используемая в разных контекстах; тогда как self обычно соответствует локальному экземпляру, а that обычно относится к другому объекту. Я знаю, что вы не установили это правило, поскольку я видел, что он появился в ряде других мест, но именно поэтому я начал использовать _this, но не уверен, как это себя чувствуют другие, - это была обычная практика. – vol7ron 12 September 2014 в 16:39
  • 2
    @FelixKling было бы безопасно предположить, что использование этих внутренних функций прототипа всегда будет иметь ожидаемое поведение независимо от того, как они (как правило) вызываются? При использовании обратных вызовов внутри функций прототипа существует ли альтернатива bind (), self или that? – andig 28 December 2015 в 16:57
  • 3
    @FelixKling Иногда полезно полагаться на Function.prototype.call () и Function.prototype.apply (). В частности, с apply () у меня много пробега. Я менее склонен использовать bind (), возможно, только из привычки, хотя я знаю (но не уверен), что могут быть небольшие накладные преимущества при использовании привязки по другим параметрам. – Nolo 15 November 2016 в 07:02
  • 4
    Отличный ответ, но подумайте над добавлением дополнительного необязательного решения, которое просто не должно использовать классы, новые или вообще ничего. – Aluan Haddad 12 February 2017 в 13:53
  • 5
    re arrow functions "Вместо этого это рассматривается в области видимости как обычная переменная. & quot; полностью сделал этот клик для меня, спасибо! () => this.clicked();) – alphanumeric0101 25 May 2018 в 20:36

Мы не можем привязать это к setTimeout(), поскольку он всегда выполняется с глобальным объектом (Window), если вы хотите получить доступ к контексту this в функции обратного вызова, а затем с помощью bind() к функции обратного вызова, которую мы можем достичь как:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);
11
ответ дан Aliaksandr Sushkevich 16 August 2018 в 00:16
поделиться
  • 1
    Как это отличается от любого из существующих ответов? – Felix Kling 17 November 2017 в 16:17

Проблема с «контекстом»

Термин «контекст» иногда используется для ссылки на объект, на который ссылается this . Его использование неуместно, потому что оно не подходит ни семантически, ни технически с помощью ECMAScript в этом .

«Контекст» означает обстоятельства, окружающие что-то, что добавляет смысл , или некоторая предшествующая и следующая информация, которая дает дополнительный смысл. Термин «контекст» используется в ECMAScript для ссылки на контекст выполнения , который является всеми параметрами, областью действия и этой в рамках некоторого исполняемого кода.

Это показано в разделе 10.4.2 ECMA-262 :

Установите значение ThisBinding на то же значение, что и ThisBinding для контекста выполнения вызова

, в котором четко указано, что этот является частью контекста выполнения.

Контекст выполнения предоставляет информацию, которая добавляет смысл в код, который выполняется , Он содержит гораздо больше информации о том, что только thisBinding .

Таким образом, значение этого не является «контекстом», это всего лишь одна часть выполнения контекст. Это, по сути, локальная переменная, которая может быть задана вызовом любого объекта и в строгом режиме для любого значения вообще.

20
ответ дан arcy 16 August 2018 в 00:16
поделиться

Это все в «волшебном» синтаксисе вызова метода:

object.property();

Когда вы получаете свойство из объекта и вызываете его за один раз, объект будет контекстом для метода , Если вы вызываете тот же метод, но в отдельных шагах, контекст представляет собой глобальную область (окно):

var f = object.property;
f();

Когда вы получаете ссылку на метод, он больше не привязан к объекту, это просто ссылка на простую функцию. То же самое происходит, когда вы получаете ссылку на использование в качестве обратного вызова:

this.saveNextLevelData(this.setAll);

Здесь вы привязываете контекст к функции:

this.saveNextLevelData(this.setAll.bind(this));

Если вы используете jQuery вы должны использовать метод $.proxy, а bind не поддерживается во всех браузерах:

this.saveNextLevelData($.proxy(this.setAll, this));
35
ответ дан Guffa 16 August 2018 в 00:16
поделиться

Во-первых, вам нужно иметь четкое представление о scope и поведении ключевого слова this в контексте scope.

this & amp; scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

вкратце, глобальная область относится к объекту window.Variables, объявленные в глобальной области, доступны из любого места. С другой стороны, область функций находится внутри функции .variable, объявленный внутри функции, не может быть доступен из внешнего мира в обычном режиме. this ключевое слово в глобальной области относится к объекту window. Внутренняя функция this также относится к объекту window.So this всегда будет ссылаться на окно до тех пор, пока мы найдем способ манипулировать this, чтобы указать контекст по собственному выбору.

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

Различные способы управления this внутри функций обратного вызова:

Здесь У меня есть функция-конструктор, называемая Person. Он имеет свойство, называемое name, и четыре метода, называемые sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4. Все четыре из них имеют одну конкретную задачу. Заберите обратный вызов и вызовите его. Обратный вызов имеет конкретную задачу, которая заключается в регистрации свойства имени экземпляра функции конструктора Person.

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

Теперь давайте создадим экземпляр из конструктора person и вызывать разные версии sayNameVersionX (X относится к 1,2,3,4) методу с niceCallback, чтобы увидеть, как много способов управления this внутри обратного вызова ссылаться на person.

var p1 = new Person('zami') // create an instance of Person constructor

bind:

Что нужно сделать, это создать новую функцию с ключевым словом this, установленным на предоставленное значение.

sayNameVersion1 и sayNameVersion2 используют bind для управления this функции обратного вызова.

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

сначала связывают this с обратным вызовом внутри самого метода. для второго обратного вызова передается связанный с ним объект.

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

вызов:

first argument в call используется как функция this внутри функции, которая вызывается с call, прикрепленной к ней.

sayNameVersion3 использует call для управления this ], чтобы ссылаться на созданный нами объект person, а не на объект окна.

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

и он называется следующим:

p1.sayNameVersion3(niceCallback)

apply:

Как и в call, первый аргумент apply относится к объекту, который будет обозначен ключевым словом this.

sayNameVersion4 использует apply для манипулирования this для обращения к объекту человека

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

, и он называется следующим. Просто передается обратный вызов,

p1.sayNameVersion4(niceCallback)
16
ответ дан mic4ael 16 August 2018 в 00:16
поделиться
  • 1
    любая конструктивная критика в отношении ответа будет оценена! – AL-zami 19 August 2017 в 08:55
  • 2
    Это ключевое слово в глобальной области не обязательно относится к объекту window . Это верно только в браузере. – Randall Flagg 23 May 2018 в 10:04
  • 3
    @RandallFlagg я написал этот ответ с точки зрения браузера. Получите бесплатный ответ на этот ответ, если необходимо :) – AL-zami 9 July 2018 в 00:14

Вот несколько способов доступа к родительскому контексту внутри дочернего контекста -

  1. Вы можете использовать функцию bind().
  2. Хранить ссылку на контекст / внутри внутри другой переменной (см. пример ниже).
  3. Использовать функции ES6 Arrow .
  4. Изменить код / function design / architecture - для этого вы должны иметь команду над шаблонами проектирования в javascript.

1. Используйте функцию bind()

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

Если вы используете underscore.js - http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2 Сохраните ссылку на контекст / внутри внутри другой переменной

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

3 Функция стрелки

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}
145
ответ дан Mohan Dere 16 August 2018 в 00:16
поделиться

Отличные ответы выше. Я хочу только добавить, что внутри области вашей функции вы можете присвоить значение этой переменной переменной let self = this;, а затем внутри обратного вызова просто обратиться к данным типа self.data.

Ваш код :

function MyConstructor(data, transport) {
    this.data = data;

    let self = this;   //ADD THIS LINE

    transport.on('data', function () {
        alert(self.data);   //USE IT LIKE THIS
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);
0
ответ дан oetoni 16 August 2018 в 00:16
поделиться
  • 1
    Об этом уже говорилось в других ответах ... – Felix Kling 15 August 2018 в 19:06
1
ответ дан Andrea Puddu 5 September 2018 в 23:52
поделиться
0
ответ дан skyboyer 29 October 2018 в 06:42
поделиться
Другие вопросы по тегам:

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