goPersonal не является функцией javascript [duplicate]

У меня есть функция-конструктор, которая регистрирует обработчик событий:

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

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

// called as
var obj = new MyConstructor('foo', transport);

Однако я не могу получить доступ к свойству data созданного объекта внутри обратный вызов. Похоже, что this не ссылается на объект, который был создан, но на другой.

Я также попытался использовать метод объекта вместо анонимной функции:

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

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

, но он обнаруживает те же проблемы.

Как я могу получить доступ к правильному объекту?

928
задан 11 July 2017 в 21:32

6 ответов

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

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);
11
ответ дан 15 August 2018 в 15:57

Проблема с «context»

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

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

В показано это :

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

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

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

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

20
ответ дан 15 August 2018 в 15:57

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

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
ответ дан 15 August 2018 в 15:57

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

scope

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

   1) Global Scope

   2) Function Scope

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

--------------------------------------------------------------------------------
-                                                                              -
-   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, и четыре метода, называемые this , 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)

}

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

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

bind:

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

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

bind:

Метод first argument метода person используется как sayNameVersion3 внутри функция, которая вызывается с помощью call

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

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

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

p1.sayNameVersion3(niceCallback)

bind:

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

sayNameVersion4 использует this , чтобы манипулировать this, чтобы ссылаться на объект person

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

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

p1.sayNameVersion4(niceCallback)
16
ответ дан 15 August 2018 в 15:57

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

Вы можете использовать функцию bind(). Храните ссылку на контекст / внутри внутри другой переменной (см. Пример ниже). Используйте функции ES6 Arrow. Alter Code / 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);
  });
}
144
ответ дан 15 August 2018 в 15:57

Отличные ответы выше. Я просто хочу добавить, что внутри области вашей функции вы можете назначить значение этого параметра в переменную типа 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
ответ дан 15 August 2018 в 15:57

Другие вопросы по тегам:

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