2011-12-23 2 views
5

Я определил две функции для массива:Как вызвать внешнее «это» во внутренней функции?

Array.prototype.remove = function(obj) { 
    var i = this.length; 
    while (i--) { 
     if (this[i] === obj) { 
      this.removeAt(i); 
     } 
    } 
}; 
Array.prototype.removeAll = function(array2) { 
    array2.forEach(function(item) { 
     this.remove(item); // remove not found!! 
    }); 
} 

Но в функции removeAll, он сообщает function remove is not found. Я исправляю это следующим образом:

Array.prototype.removeAll = function(array2) { 
    var outer = this; 
    array2.forEach(function(item) { 
     outer.remove(item); 
    }); 
} 

Но это уродливо. Есть ли способ лучше?

+0

Я не думаю, что это ужасно уродливо, и это работает. «Это» в вашем foreach изменяется как элемент на итерации, поэтому я не вижу слишком много возможностей для этого. – Paddy

ответ

6

Передача this с помощью переменной переменной, так же как идиоматический подход. В этом нет ничего уродливого. (Чаще всего называть переменную that или self))

1

Function.bind и аналогичный.

array2.forEach((function(item) { 
    this.remove(item); 
}).bind(this)); 

Это технически не такой же, как и предыдущий «внутренний этот» теперь слежка/потерянным (и функция упаковщик новый создается), но она хорошо работает в некоторых контекстах.

По большей части, я предпочитаю стандартный var self = this ...

Happy кодирования.

+0

Насколько я знаю, 'Function.bind' является ECMAScript 5, который поддерживается только последним браузером (не поддерживается в IE8, FF3.6, FF3.6, Safari 4, Safari 5, Safari 5.1 и Opera 10.50 - 11.50) –

+0

@StefanGehrig Вы правы, поэтому «и подобные» :-) Легко реализовать такую ​​функцию, и такая документация MDC дает такой пример. Такую же функциональность можно найти в ряде фреймворков. –

+0

Просто хотел отметить эту важную деталь ... ;-) –

2

Передача следующего одного аргумента forEach который будет контекстом this в функции обратного вызова, в вашем случае this относится к объекту окна.

Array.prototype.removeAll = function(array2) { 

    array2.forEach(function(item) { 
     this.remove(item); 
    },this); 
} 
+0

Очень мило, я этого не знал. –

+3

помните, что это не поддерживается в ie8 и более ранних версиях. –

2

Альтернатива использования привязки (если вам необходимо поддерживать старые браузеры и не хотите, чтобы расширить Function.prototype), чтобы просто обернуть обратный вызов в функции immidate и кормить this в качестве аргумента, как это:

Array.prototype.removeAll = function(array2) { 
    array2.forEach(function(outer){ 
    return function(item) { 
     outer.remove(item); 
    };}(this)); 
} 

или вы можете написать простую карри функцию полезности и использовать как этот

function curry() { 
    var fn = Array.prototype.shift.call(arguments), 
     args = Array.prototype.slice.call(arguments); 
    return function curryed() { 
    return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); 
    }; 
}; 



Array.prototype.removeAll = function(array2) { 
    array2.forEach(curry(function(item) { 
     outer.remove(item); 
    },this)); 
} 

Если вы не возражаете расширение Function.prototype вы можете использовать bind, как уже описано другими, вы можете найти отличное расширение совместимости на MDN здесь: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Смежные вопросы