Сохранение ссылки на “это” в опытных функциях JavaScript [дубликат]

Этот вопрос уже имеет ответ здесь:

Я просто вхожу в использование prototypal JavaScript, и я испытываю затруднения при выяснении, как сохранить a this ссылка на основной объект из прототипа функционирует, когда объем изменяется. Позвольте мне проиллюстрировать то, что я имею в виду (я использую jQuery здесь):

MyClass = function() {
  this.element = $('#element');
  this.myValue = 'something';

  // some more code
}

MyClass.prototype.myfunc = function() {
  // at this point, "this" refers to the instance of MyClass

  this.element.click(function() {
    // at this point, "this" refers to the DOM element
    // but what if I want to access the original "this.myValue"?
  });
}

new MyClass();

Я знаю, что могу сохранить ссылку на основной объект путем выполнения этого в начале myfunc:

var myThis = this;

и затем использование myThis.myValue получить доступ к свойству основного объекта. Но что происходит, когда у меня есть целый набор опытных функций на MyClass? Сделайте я должен сохранить ссылку на this в начале каждого? Кажется, что должен быть более чистый путь. И что относительно такой ситуации:

MyClass = function() {
  this.elements $('.elements');
  this.myValue = 'something';

  this.elements.each(this.doSomething);
}

MyClass.prototype.doSomething = function() {
  // operate on the element
}

new MyClass();

В этом случае я не могу создать ссылку на основной объект с var myThis = this; потому что даже исходное значение this в контексте doSomething a jQuery возразите и не a MyClass объект.

Было предложено мне использовать глобальную переменную для содержания ссылки на оригинал this, но это походит на действительно плохую идею мне. Я не хочу загрязнять глобальное пространство имен, и это кажется, что препятствовало бы тому, чтобы я инстанцировал двух различных MyClass объекты без них вмешивающийся друг в друга.

Какие-либо предложения? Существует ли очевидный способ, чтобы сделать то, что я после? Или мой весь шаблон разработки испорчен?

89
задан Rob W 27 December 2011 в 17:30
поделиться

4 ответа

Для сохранения контекста действительно полезен метод bind , теперь он является частью недавно выпущенного ECMAScript 5th Edition Спецификация, реализация этой функции проста (всего 8 строк):

// The .bind method from Prototype.js 
if (!Function.prototype.bind) { // check if native implementation available
  Function.prototype.bind = function(){ 
    var fn = this, args = Array.prototype.slice.call(arguments),
        object = args.shift(); 
    return function(){ 
      return fn.apply(object, 
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
  };
}

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

MyClass.prototype.myfunc = function() {

  this.element.click((function() {
    // ...
  }).bind(this));
};

Другой пример:

var obj = {
  test: 'obj test',
  fx: function() {
    alert(this.test + '\n' + Array.prototype.slice.call(arguments).join());
  }
};

var test = "Global test";
var fx1 = obj.fx;
var fx2 = obj.fx.bind(obj, 1, 2, 3);

fx1(1,2);
fx2(4, 5);

В этом втором примере мы можем наблюдать больше о поведении связывания .

По сути, он генерирует новую функцию, которая будет отвечать за вызов нашей функции, сохраняя контекст функции ( this значение), который определяется как первый аргумент bind .

Остальные аргументы просто передаются нашей функции.

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

Теперь fx2 - это новая функция, которую сгенерировал метод bind , он вызовет нашу функцию, сохраняя контекст и правильно передавая аргументы, она выдаст предупреждение «obj test 1 , 2, 3, 4, 5 ", поскольку мы вызвали его, добавив два дополнительных аргумента, он уже связал первые три.

64
ответ дан 24 November 2019 в 07:22
поделиться

Вы можете установить область видимости, используя call() и apply() function

4
ответ дан 24 November 2019 в 07:22
поделиться

Поскольку вы используете jQuery, стоит отметить, что эта уже поддерживается самой jQuery:

$("li").each(function(j,o){
  $("span", o).each(function(x,y){
    alert(o + " " + y);
  });
});

В данном примере o представляет li, в то время как y представляет ребенка span. А с помощью $.click() можно получить область видимости из объекта события :

$("li").click(function(e){
  $("span", this).each(function(i,o){
    alert(e.target + " " + o);
  });
});

Где e.target представляет li, а o представляет ребенка span.

1
ответ дан 24 November 2019 в 07:22
поделиться

Для вашего последнего примера MyClass вы можете сделать следующее:

var myThis=this;
this.elements.each(function() { myThis.doSomething.apply(myThis, arguments); });

В функции, которая передается в each , this относится к объекту jQuery, как вы уже знаете. Если внутри этой функции вы получаете функцию doSomething из myThis , а затем вызываете метод apply для этой функции с массивом аргументов (см. apply function ] и arguments переменная ), то this будет установлено в myThis в doSomething .

10
ответ дан 24 November 2019 в 07:22
поделиться
Другие вопросы по тегам:

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