2011-12-23 14 views
5

que define dos funciones para la matriz:¿Cómo invocar "esto" externo en la función interna?

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!! 
    }); 
} 

Pero en la función removeAll, informa function remove is not found. Lo arreglo de esta manera:

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

Pero es feo. ¿Hay una mejor manera?

+0

No creo que sea tremendamente feo, y funciona. El 'esto' en su foreach se cambia para que sea el elemento en la iteración, por lo que no veo demasiado para evitarlo. – Paddy

Respuesta

6

Pasando this a través de una variable diferente como lo hace es el enfoque idiomático. No hay nada feo en eso. (Sin embargo, es más común llamar a la variable that o self)

1

Hay Function.bind y similares.

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

No es técnicamente lo mismo, como el anterior, el "interior de este" ahora es la sombra/perdido (y se crea una nueva función de contenedor ), pero funciona muy bien en algunos contextos.

En su mayor parte, me quedo con la norma var self = this ...

codificación feliz.

+0

Por lo que sé, 'Function.bind' es ECMAScript 5, que solo es compatible con el último navegador (no es compatible con IE8, FF3.6, FF3.6, Safari 4, Safari 5, Safari 5.1 y Opera 10.50 - 11.50) –

+0

@StefanGehrig Tiene razón, de ahí el "y similar" :-) Es fácil implementar dicha función, y la documentación de MDC proporciona un ejemplo. Esta misma funcionalidad se puede encontrar en varios marcos. –

+0

Solo quería notar este importante detalle ... ;-) –

2

Pasando siguiente un argumento a forEach que será el contexto de this en la función de devolución de llamada, en su caso this se refiere al objeto ventana.

Array.prototype.removeAll = function(array2) { 

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

Muy bien, no lo sabía. –

+3

tenga en cuenta que esto no es compatible con ie8 y versiones anteriores. –

2

Una alternativa al uso de bind (si es necesario apoyar a los navegadores antiguos y no desea extender Function.prototype) es simplemente envolver su devolución de llamada en una función immidate y alimentar this como argumento así:

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

o puede escribir una función de utilidad de curry simple y utilizar como esto

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)); 
} 

Si no le importa extendiendo Function.prototype puede usar bind como ya se describió por otros puede encontrar una excelente extensión de compatibilidad en MDN aquí: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Cuestiones relacionadas