Expresiones regulares como funciones

Firefox incluye una extensión de JavaScript no estándar que hace que las expresiones regulares se puedan llamar como funciones. Esto sirve como una forma abreviada de llamar al exec de una expresión regular. método. Por ejemplo, en Firefox /regex/("string") es equivalente a /regex/.exec("string") . Las primeras propuestas de ECMAScript 4 indicaron que esta funcionalidad se agregaría a la especificación de ES4, pero la discusión posterior en la lista de correo de discusión de ES4 sugiere que podría descartarse.

Sin embargo, puede implementar algo similar agregando call y apply métodos para RegExp.prototype , que podría ayudar con la programación funcional y el código tipo pato que funciona tanto con funciones como con expresiones regulares. Así que vamos a agregarlos:

RegExp.prototype.call = function (context, str) {
	return this.exec(str);
};
RegExp.prototype.apply = function (context, args) {
	return this.exec(args[0]);
};

Tenga en cuenta que los dos métodos anteriores ignoran por completo el context argumento. Podrías pasar null o cualquier otra cosa como contexto, y obtendría el resultado normal de ejecutar exec en la expresión regular. Usando los métodos anteriores, puede trabajar genéricamente tanto con expresiones regulares como con funciones donde sea conveniente hacerlo. Algunos casos obvios en los que esto podría ser útil son los métodos de iteración de matrices de JavaScript 1.6. Las siguientes son implementaciones de filter , every , some y map que permiten su uso entre navegadores:

// Returns an array with the elements of an existng array for which the provided filtering function returns true
Array.prototype.filter = function (func, context) {
	var results = [];
	for (var i = 0; i < this.length; i++) {
		if (i in this && func.call(context, this[i], i, this))
			results.push(this[i]);
	}
	return results;
};
// Returns true if every element in the array satisfies the provided testing function
Array.prototype.every = function (func, context) {
	for (var i = 0; i < this.length; i++) {
		if (i in this && !func.call(context, this[i], i, this))
			return false;
	}
	return true;
};
// Returns true if at least one element in the array satisfies the provided testing function
Array.prototype.some = function (func, context) {
	for (var i = 0; i < this.length; i++) {
		if (i in this && func.call(context, this[i], i, this))
			return true;
	}
	return false;
};
// Returns an array with the results of calling the provided function on every element in the provided array
Array.prototype.map = function (func, context) {
	var results = [];
	for (var i = 0; i < this.length; i++) {
		if (i in this)
			results[i] = func.call(context, this[i], i, this);
	}
	return results;
};

Porque la matriz y null valores devueltos por exec tipo-convertir muy bien a true y false , el código anterior te permite usar algo como ["a","b","ab","ba"].filter(/^a/) para devolver todos los valores que comienzan con "a":["a","ab"] . El código ["1",1,0,"a",3.1,256].filter(/^[1-9]\d*$/) devolvería números enteros mayores que cero, independientemente del tipo:["1",1,256] . str.match(/a?b/g).filter(/^b/) devolvería todas las coincidencias de "b" no precedidas por "a". Este puede ser un patrón conveniente ya que JavaScript no admite la función de mirar atrás.

Todos los ejemplos anteriores ya funcionan con el Array.prototype.filter nativo de Firefox por el exec indirecto función de llamada en ese navegador, pero no funcionaría con la implementación de navegador cruzado de filter arriba sin agregar RegExp.prototype.call .

¿Te parece algo que te sería útil? ¿Puedes pensar en otros buenos ejemplos donde call y apply métodos serían útiles para las expresiones regulares?

Actualización: Esta publicación ha sido traducida al chino por PlanABC.net.