Подтвердить что ты не робот

Как изменить контекст функции в javascript

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

Техника проиллюстрирована с использованием этого примера (из http://ejohn.org/apps/learn/#25)

var object = {}; 
function fn(){ 
  return this; 
} 
assert( fn() == this, "The context is the global object." ); 
assert( fn.call(object) == object, "The context is changed to a specific object." );
4b9b3361

Ответ 1

jQuery использует его для хорошего эффекта:

$('a').each(function() {
    // "this" is an a element - very useful
});

Фактический код jQuery выглядит следующим образом:

for ( name in object ) {
    if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
        break;
    }
}

Если он просто сделал callback( name, object[ name ] ), то this не будет установлен на текущий объект в вашем итераторе, и вам придется использовать этот параметр. В основном это упрощает процесс.

Ответ 2

Пожалуйста, посмотрите на этот пример:

<script>
var el = document.getElementById('button');
el.onclick = function(){
    this.value = "Press Me Again"; //this --> now refers to the the element button not on the window
}

//Another Example:
var Person = function(name,location){
  this.name = name;
  this.location = location;  
  alert(this.location); 
}   
var p2 = new Person("Samantha","California"); //this refers to the instance of the function Person(Person now acts as a class)
var p1 = Person(); // this refers to the window(Person simply acts as a simple function)
</script>
<button id="button1">Press Me</button>

Новое ключевое слово изменяет контекст.

Ответ 3

Это очень полезно при выполнении обратных вызовов из запросов AJAX:

function Person(_id, _name) {
    this.id = _id;
    this.name = _name;
};

Person.prototype.sayHi = function(greeting) {
    alert(greeting + " from " + this.name);
};

Person.prototype.loadFromAJAX = function(callback) {
    // in this example, it jQuery, but could be anything
    var t = this;
    $.get("myurl.php", function(data) {
        callback.call(t, data.greeting);
    });
};

Собственно, это довольно дрянной пример.

В jQuery есть много применений. Например, функция jQuery(). Get():

get: function( num ) {
    return num === undefined ?
        // Return a 'clean' array
        Array.prototype.slice.call( this ) :
        // Return just the object
        this[ num ];
}

Он использует функции прототипа Array, но в контексте объекта jQuery.

Ответ 4

Пример реального мира, с которым я столкнулся:

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

Но эта функция может быть методом объекта, и вы хотите, чтобы ключевое слово "this", используемое внутри него, ссылалось на объект владельца... поэтому вам нужно изменить контекст, чтобы "this" не ссылался на элемент DOM, но будет ссылаться на объект владельца.

Вы можете легко изменить контекст функции в jquery, используя функцию proxy(). См. Этот вопрос: jquery "his" проблема привязки к обработчику событий (эквивалент bindAsEventListener в прототипе) и первый ответ

Ответ 5

Функция связывания может быть тем, что вы ищете, функция bind возвращает новую функцию в контексте, в котором вы проходили, сценарий реального мира может быть, когда вы используете делегатов jquery для придания некоторого поведения элементу dom, и вы хотите, чтобы обратный вызов выполнялся в другом контексте. потому что контекст по умолчанию в delgate jquery является объектом dom, связанным с обработчиком, что означает, что вы не можете получить доступ к любому свойству, кроме свойств, принадлежащих dom-объекту

Ответ 6

Мне всегда нужно иметь другой контекст при использовании setTimeout, а jQuery имеет удобную функцию $. proxy, которая делает хитрость:

function iAmCalledAfterTimeout()
{
     alert(this.myProperty); //it will alert "hello world"
}    

setTimeout($.proxy(iAmCalledAfterTimeout, {myProperty:"hello world"}), 1000);