style change attribute javascript hidden-features

javascript - change - title css



Características ocultas de JavaScript? (30)

¿Qué "características ocultas" de JavaScript crees que todos los programadores deberían saber?

Después de haber visto la excelente calidad de las respuestas a las siguientes preguntas, pensé que era hora de pedir JavaScript.

A pesar de que JavaScript es posiblemente el idioma más importante del lado del cliente en este momento (solo pregunte a Google), es sorprendente lo poco que la mayoría de los desarrolladores web aprecian lo poderoso que es.


" Métodos de extensión en JavaScript " a través de la propiedad prototipo.

Array.prototype.contains = function(value) { for (var i = 0; i < this.length; i++) { if (this[i] == value) return true; } return false; }

Esto agregará un método contains a todos los objetos Array . Puedes llamar a este método usando esta sintaxis.

var stringArray = ["foo", "bar", "foobar"]; stringArray.contains("foobar");


Aquí hay algunas cosas interesantes:

  • La comparación de NaN con cualquier cosa (incluso NaN ) siempre es falsa, que incluye == , < y > .
  • NaN significa No un número, pero si solicita el tipo, en realidad devuelve un número.
  • Array.sort puede tomar una función de comparación y se llama mediante un controlador de tipo quicksort (depende de la implementación).
  • La expresión regular "constantes" puede mantener el estado, como la última cosa que coincidieron.
  • Algunas versiones de JavaScript le permiten acceder a miembros de $0 , $1 , $2 en una expresión regular.
  • null es diferente a cualquier otra cosa. No es un objeto, un booleano, un número, una cadena, ni undefined . Es un poco como un "alternativo" undefined . (Nota: tipo de typeof null == "object" )
  • En el contexto más externo, this produce el objeto [Global] que de otra manera sería innombrable.
  • Declarar una variable con var , en lugar de simplemente confiar en la declaración automática de la variable, le da al tiempo de ejecución una posibilidad real de optimizar el acceso a esa variable
  • El constructo with destruirá tales optimizaciones.
  • Los nombres de variables pueden contener caracteres Unicode.
  • Las expresiones regulares de JavaScript no son realmente regulares. Se basan en las expresiones regulares de Perl y es posible construir expresiones con lookaheads que requieren mucho, mucho tiempo para evaluar.
  • Los bloques se pueden etiquetar y utilizar como objetivos de break . Los bucles se pueden etiquetar y utilizar como el objetivo de continue .
  • Las matrices no son escasas. La configuración del elemento 1000 de una matriz, por lo demás vacía, debe llenarlo con undefined . (depende de la implementación)
  • if (new Boolean(false)) {...} ejecutará el bloque {...}
  • Los motores de expresiones regulares de Javascript son específicos de la implementación: por ejemplo, es posible escribir expresiones regulares "no portátiles".

[Actualizado un poco en respuesta a buenos comentarios; por favor vea los comentarios]


Las funciones son ciudadanos de primera clase en JavaScript:

var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); }; var sum = function(x,y,z) { return x+y+z; }; alert( passFunAndApply(sum,3,4,5) ); // 12

Se pueden usar técnicas de programación funcional para escribir javascript elegante .

En particular, las funciones se pueden pasar como parámetros, por ejemplo, Array.filter() acepta una devolución de llamada:

[1, 2, -1].filter(function(element, index, array) { return element > 0 }); // -> [1,2]

También puede declarar una función "privada" que solo existe dentro del alcance de una función específica:

function PrintName() { var privateFunction = function() { return "Steve"; }; return privateFunction(); }


Las funciones son objetos y por lo tanto pueden tener propiedades.

fn = function(x) { // ... } fn.foo = 1; fn.next = function(y) { // }


Para eliminar correctamente una propiedad de un objeto, debe eliminar la propiedad en lugar de establecerla como indefinida :

var obj = { prop1: 42, prop2: 43 }; obj.prop2 = undefined; for (var key in obj) { ...

La propiedad prop2 seguirá siendo parte de la iteración. Si quieres deshacerte completamente de prop2 , deberías hacer lo siguiente:

delete obj.prop2;

La propiedad prop2 ya no aparecerá cuando esté iterando a través de las propiedades.


Podría citar la mayor parte del excelente libro de Douglas Crockford, JavaScript: The Good Parts .

Pero solo tomaré uno para ti, siempre usa === y !== lugar de == y !=

alert('''' == ''0''); //false alert(0 == ''''); // true alert(0 ==''0''); // true

== no es transitiva. Si usa === daría falso para todas estas declaraciones como se esperaba.


Puede usar el operador in para verificar si existe una clave en un objeto:

var x = 1; var y = 3; var list = {0:0, 1:0, 2:0}; x in list; //true y in list; //false 1 in list; //true y in {3:0, 4:0, 5:0}; //true

Si encuentra que los objetos literales son demasiado feos, puede combinarlos con la función sin parámetros punta:

function list() { var x = {}; for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0; return x } 5 in list(1,2,3,4,5) //true


Sé que llego tarde a la fiesta, pero no puedo creer que la utilidad del operador + no haya sido mencionada más allá de "convertir cualquier cosa en un número". Tal vez eso es lo bien oculto que es una característica?

// Quick hex to dec conversion: +"0xFF"; // -> 255 // Get a timestamp for now, the equivalent of `new Date().getTime()`: +new Date(); // Safer parsing than parseFloat()/parseInt() parseInt("1,000"); // -> 1, not 1000 +"1,000"; // -> NaN, much better for testing user input parseInt("010"); // -> 8, because of the octal literal prefix +"010"; // -> 10, `Number()` doesn''t parse octal literals // A use case for this would be rare, but still useful in cases // for shortening something like if (someVar === null) someVar = 0; +null; // -> 0; // Boolean to integer +true; // -> 1; +false; // -> 0; // Other useful tidbits: +"1e10"; // -> 10000000000 +"1e-4"; // -> 0.0001 +"-12"; // -> -12

Por supuesto, puedes hacer todo esto usando Number() lugar, ¡pero el operador + es mucho más bonito!

También puede definir un valor de retorno numérico para un objeto anulando el método valueOf() del prototipo. Cualquier conversión de número realizada en ese objeto no dará como resultado NaN , pero el valor de retorno del método valueOf() :

var rnd = { "valueOf": function () { return Math.floor(Math.random()*1000); } }; +rnd; // -> 442; +rnd; // -> 727; +rnd; // -> 718;


Si está buscando en Google una referencia de JavaScript decente sobre un tema determinado, incluya la palabra clave "mdc" en su consulta y sus primeros resultados serán del Centro de desarrolladores de Mozilla. No llevo ninguna referencia o libro fuera de línea conmigo. Siempre uso el truco de la palabra clave "mdc" para llegar directamente a lo que estoy buscando. Por ejemplo:

Google: javascript array sort mdc
(en la mayoría de los casos puede omitir "javascript")

Actualización: Mozilla Developer Center ha sido renombrado a Mozilla Developer Network . El truco de la palabra clave "mdc" todavía funciona, pero pronto tendremos que comenzar a usar "mdn" .


Tal vez un poco obvio para algunos ...

Instale Firebug y use console.log ("hello"). Mucho mejor que usar alertas aleatorias (); recuerdo que hice muchas cosas hace unos años.


También mencionado en "Javascript: The Good Parts" de Crockford:

parseInt() es peligroso. Si le pasa una cadena sin informarle de la base adecuada, puede devolver números inesperados. Por ejemplo, parseInt(''010'') devuelve 8, no 10. Pasar una base a parseInt hace que funcione correctamente:

parseInt(''010'') // returns 8! (in FF3) parseInt(''010'', 10); // returns 10 because we''ve informed it which base to work with.


Tendría que decir funciones autoejecutables.

(function() { alert("hi there");})();

Debido a que Javascript no tiene un ámbito de bloqueo , puede usar una función autoejecutable si desea definir variables locales:

(function() { var myvar = 2; alert(myvar); })();

Aquí, myvar no interfiere ni contamina el alcance global, y desaparece cuando la función termina.



with .

Rara vez se usa, y francamente, rara vez es útil ... Pero, en circunstancias limitadas, tiene sus usos.

Por ejemplo: los literales de objetos son muy útiles para configurar rápidamente las propiedades de un nuevo objeto. ¿Pero qué sucede si necesita cambiar la mitad de las propiedades de un objeto existente?

var user = { fname: ''Rocket'', mname: ''Aloysus'', lname: ''Squirrel'', city: ''Fresno'', state: ''California'' }; // ... with (user) { mname = ''J''; city = ''Frostbite Falls''; state = ''Minnesota''; }

Alan Storm señala que esto puede ser algo peligroso: si el objeto utilizado como contexto no tiene una de las propiedades asignadas, se resolverá en el ámbito externo, posiblemente creando o sobrescribiendo una variable global. Esto es especialmente peligroso si está acostumbrado a escribir código para trabajar con objetos donde las propiedades con valores predeterminados o vacíos se dejan sin definir:

var user = { fname: "John", // mname definition skipped - no middle name lname: "Doe" }; with (user) { mname = "Q"; // creates / modifies global variable "mname" }

Por lo tanto, es probablemente una buena idea evitar el uso de la instrucción with para dicha asignación.

Ver también: ¿Existen usos legítimos para la declaración "with" de JavaScript?


Saber cuantos parámetros espera una función.

function add_nums(num1, num2, num3 ){ return num1 + num2 + num3; } add_nums.length // 3 is the number of parameters expected.

Saber cuantos parámetros recibe la función.

function add_many_nums(){ return arguments.length; } add_many_nums(2,1,122,12,21,89); //returns 6


Asignando valores por defecto a las variables

Puede utilizar el operador lógico o || en una expresión de asignación para proporcionar un valor predeterminado:

var a = b || c;

La variable a obtendrá el valor de c solo si b es falsy (si es null , false , undefined , 0 , empty string o NaN ), de lo contrario a obtendrá el valor de b .

Esto suele ser útil en las funciones, cuando se desea asignar un valor predeterminado a un argumento en caso de que no se proporcione:

function example(arg1) { arg1 || (arg1 = ''default value''); }

Ejemplo IE fallback en los controladores de eventos:

function onClick(e) { e || (e = window.event); }

Las siguientes funciones de idioma han estado con nosotros durante mucho tiempo, todas las implementaciones de JavaScript las admiten, pero no formaron parte de la especificación hasta ECMAScript 5th Edition :

La declaración del debugger

Descrito en: § 12.15 La declaración del depurador

Esta declaración le permite colocar puntos de interrupción programáticamente en su código con solo:

// ... debugger; // ...

Si un depurador está presente o activo, causará que se interrumpa de inmediato, justo en esa línea.

De lo contrario, si el depurador no está presente o está activo, esta declaración no tiene ningún efecto observable.

Literales multilínea de cuerda

Descrito en: § 7.8.4 Literales de cadenas

var str = "This is a / really, really / long line!";

Debe tener cuidado porque el carácter al lado de / debe ser un terminador de línea, si tiene un espacio después de / por ejemplo, el código se verá exactamente igual, pero generará un SyntaxError .


La herencia prototípica (popularizada por Douglas Crockford) revoluciona completamente la forma en que piensas sobre un montón de cosas en Javascript.

Object.beget = (function(Function){ return function(Object){ Function.prototype = Object; return new Function; } })(function(){});

¡Es un asesino! Lástima que casi nadie lo usa.

Le permite "generar" nuevas instancias de cualquier objeto, extenderlas, mientras mantiene un enlace de herencia prototípica (en vivo) a sus otras propiedades. Ejemplo:

var A = { foo : ''greetings'' }; var B = Object.beget(A); alert(B.foo); // ''greetings'' // changes and additionns to A are reflected in B A.foo = ''hello''; alert(B.foo); // ''hello'' A.bar = ''world''; alert(B.bar); // ''world'' // ...but not the other way around B.foo = ''wazzap''; alert(A.foo); // ''hello'' B.bar = ''universe''; alert(A.bar); // ''world''


Métodos privados

Un objeto puede tener métodos privados.

function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; // A private method only visible from within this constructor function calcFullName() { return firstName + " " + lastName; } // A public method available to everyone this.sayHello = function () { alert(calcFullName()); } } //Usage: var person1 = new Person("Bob", "Loblaw"); person1.sayHello(); // This fails since the method is not visible from this scope alert(person1.calcFullName());


Puede acceder a las propiedades del objeto con [] lugar de .

Esto le permite buscar una propiedad que coincida con una variable.

obj = {a:"test"}; var propname = "a"; var b = obj[propname]; // "test"

También puede usar esto para obtener / establecer propiedades de objetos cuyo nombre no es un identificador legal.

obj["class"] = "test"; // class is a reserved word; obj.class would be illegal. obj["two words"] = "test2"; // using dot operator not possible with the space.

Algunas personas no lo saben y terminan usando eval () de esta manera, lo cual es una muy mala idea :

var propname = "a"; var a = eval("obj." + propname);

Esto es más difícil de leer, más difícil de encontrar errores (no se puede usar jslint), más lento de ejecutar y puede conducir a ataques de XSS.


Algunos lo llamarían una cuestión de gusto, pero:

aWizz = wizz || "default"; // same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }

El operador trinario se puede encadenar para actuar como el de Scheme (cond ...):

(cond (predicate (action ...)) (predicate2 (action2 ...)) (#t default ))

Se puede escribir como...

predicate ? action( ... ) : predicate2 ? action2( ... ) : default;

Esto es muy "funcional", ya que ramifica su código sin efectos secundarios. Así que en lugar de:

if (predicate) { foo = "one"; } else if (predicate2) { foo = "two"; } else { foo = "default"; }

Puedes escribir:

foo = predicate ? "one" : predicate2 ? "two" : "default";

Funciona bien con la recursión, también :)


La parte superior de mi cabeza...

Funciones

Argumentos. Llamada se refiere a la función que aloja la variable "Argumentos", por lo que puede usarse para repetir funciones anónimas

var recurse = function() { if (condition) arguments.callee(); //calls recurse() again }

Eso es útil si quieres hacer algo como esto:

//do something to all array items within an array recursively myArray.forEach(function(item) { if (item instanceof Array) item.forEach(arguments.callee) else {/*...*/} })

Objetos

Algo interesante sobre los miembros de los objetos: pueden tener cualquier cadena como sus nombres:

//these are normal object members var obj = { a : function() {}, b : function() {} } //but we can do this too var rules = { ".layout .widget" : function(element) {}, "a[href]" : function(element) {} } /* this snippet searches the page for elements that match the CSS selectors and applies the respective function to them: */ for (var item in rules) { var elements = document.querySelectorAll(rules[item]); for (var e, i = 0; e = elements[i++];) rules[item](e); }

Instrumentos de cuerda

String.split puede tomar expresiones regulares como parámetros:

"hello world with spaces".split(//s+/g); //returns an array: ["hello", "world", "with", "spaces"]

String.replace puede tomar una expresión regular como un parámetro de búsqueda y una función como un parámetro de reemplazo:

var i = 1; "foo bar baz ".replace(//s+/g, function() {return i++}); //returns "foo1bar2baz3"


No es necesario definir ningún parámetro para una función. Puede usar los arguments la función como el objeto de tipo matriz.

function sum() { var retval = 0; for (var i = 0, len = arguments.length; i < len; ++i) { retval += arguments[i]; } return retval; } sum(1, 2, 3) // returns 6


Puedes usar objetos en lugar de interruptores la mayor parte del tiempo.

function getInnerText(o){ return o === null? null : { string: o, array: o.map(getInnerText).join(""), object:getInnerText(o["childNodes"]) }[typeis(o)]; }

Actualización: si le preocupa que los casos que evalúan por adelantado sean ineficientes (¿por qué le preocupa la eficiencia tan pronto en el diseño del programa?), Entonces puede hacer algo como esto:

function getInnerText(o){ return o === null? null : { string: function() { return o;}, array: function() { return o.map(getInnerText).join(""); }, object: function () { return getInnerText(o["childNodes"]; ) } }[typeis(o)](); }

Esto es más oneroso de escribir (o leer) que un interruptor o un objeto, pero conserva los beneficios de usar un objeto en lugar de un interruptor, que se detalla en la sección de comentarios a continuación. Este estilo también hace que sea más sencillo convertir esto en una "clase" adecuada una vez que crezca lo suficiente.

update2: con las extensiones de sintaxis propuestas para ES.next, esto se convierte en

let getInnerText = o -> ({ string: o -> o, array: o -> o.map(getInnerText).join(""), object: o -> getInnerText(o["childNodes"]) }[ typeis o ] || (->null) )(o);


Variables privadas con una interfaz pública

Utiliza un pequeño truco con una definición de función de auto-llamada. Todo dentro del objeto que se devuelve está disponible en la interfaz pública, mientras que todo lo demás es privado.

var test = function () { //private members var x = 1; var y = function () { return x * 2; }; //public interface return { setx : function (newx) { x = newx; }, gety : function () { return y(); } } }(); assert(undefined == test.x); assert(undefined == test.y); assert(2 == test.gety()); test.setx(5); assert(10 == test.gety());


¿Qué tal los cierres en JavaScript (similar a los métodos anónimos en C # v2.0 +)? Puede crear una función que crea una función o "expresión".

Ejemplo de cierres :

//Takes a function that filters numbers and calls the function on //it to build up a list of numbers that satisfy the function. function filter(filterFunction, numbers) { var filteredNumbers = []; for (var index = 0; index < numbers.length; index++) { if (filterFunction(numbers[index]) == true) { filteredNumbers.push(numbers[index]); } } return filteredNumbers; } //Creates a function (closure) that will remember the value "lowerBound" //that gets passed in and keep a copy of it. function buildGreaterThanFunction(lowerBound) { return function (numberToCheck) { return (numberToCheck > lowerBound) ? true : false; }; } var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6]; var greaterThan7 = buildGreaterThanFunction(7); var greaterThan15 = buildGreaterThanFunction(15); numbers = filter(greaterThan7, numbers); alert(''Greater Than 7: '' + numbers); numbers = filter(greaterThan15, numbers); alert(''Greater Than 15: '' + numbers);


Asegúrese de usar el método hasOwnProperty al iterar a través de las propiedades de un objeto:

for (p in anObject) { if (anObject.hasOwnProperty(p)) { //Do stuff with p here } }

Esto se hace para que solo acceda a las propiedades directas de un objeto y no utilice las propiedades que están en la cadena del prototipo.


Los números también son objetos. Así que puedes hacer cosas geniales como:

// convert to base 2 (5).toString(2) // returns "101" // provide built in iteration Number.prototype.times = function(funct){ if(typeof funct === ''function'') { for(var i = 0;i < Math.floor(this);i++) { funct(i); } } return this; } (5).times(function(i){ string += i+" "; }); // string now equals "0 1 2 3 4 " var x = 1000; x.times(function(i){ document.body.innerHTML += ''<p>paragraph #''+i+''</p>''; }); // adds 1000 parapraphs to the document


Puede capturar excepciones dependiendo de su tipo. Citado de MDC :

try { myroutine(); // may throw three exceptions } catch (e if e instanceof TypeError) { // statements to handle TypeError exceptions } catch (e if e instanceof RangeError) { // statements to handle RangeError exceptions } catch (e if e instanceof EvalError) { // statements to handle EvalError exceptions } catch (e) { // statements to handle any unspecified exceptions logMyErrors(e); // pass exception object to error handler }

NOTA: Las cláusulas de captura condicionales son una extensión de Netscape (y, por lo tanto, de Mozilla / Firefox) que no forman parte de la especificación ECMAScript y, por lo tanto, no se puede confiar en ellas, excepto en determinados navegadores.


Se pueden invocar métodos (o funciones) en objetos que no son del tipo para el que fueron diseñados para trabajar. Esto es genial para llamar métodos nativos (rápidos) en objetos personalizados.

var listNodes = document.getElementsByTagName(''a''); listNodes.sort(function(a, b){ ... });

Este código se bloquea porque listNodesno es unArray

Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);

Este código funciona porque listNodesdefine suficientes propiedades de tipo matriz (longitud, operador []) para ser utilizadas por sort().


También puede extender las clases (Heredar) y anular propiedades / métodos utilizando la cadena de prototipo spoon16 aludidos.

En el siguiente ejemplo creamos una clase Pet y definimos algunas propiedades. También anulamos el método .toString () heredado de Object.

Después de esto, creamos una clase Dog que extiende a Pet y anula el método .toString () nuevamente cambiando su comportamiento (polimorfismo). Además agregamos algunas otras propiedades a la clase secundaria.

Después de esto, verificamos la cadena de herencia para mostrar que Dog aún es del tipo Dog, del tipo Pet y del tipo Object.

// Defines a Pet class constructor function Pet(name) { this.getName = function() { return name; }; this.setName = function(newName) { name = newName; }; } // Adds the Pet.toString() function for all Pet objects Pet.prototype.toString = function() { return ''This pets name is: '' + this.getName(); }; // end of class Pet // Define Dog class constructor (Dog : Pet) function Dog(name, breed) { // think Dog : base(name) Pet.call(this, name); this.getBreed = function() { return breed; }; } // this makes Dog.prototype inherit from Pet.prototype Dog.prototype = new Pet(); // Currently Pet.prototype.constructor // points to Pet. We want our Dog instances'' // constructor to point to Dog. Dog.prototype.constructor = Dog; // Now we override Pet.prototype.toString Dog.prototype.toString = function() { return ''This dogs name is: '' + this.getName() + '', and its breed is: '' + this.getBreed(); }; // end of class Dog var parrotty = new Pet(''Parrotty the Parrot''); var dog = new Dog(''Buddy'', ''Great Dane''); // test the new toString() alert(parrotty); alert(dog); // Testing instanceof (similar to the `is` operator) alert(''Is dog instance of Dog? '' + (dog instanceof Dog)); //true alert(''Is dog instance of Pet? '' + (dog instanceof Pet)); //true alert(''Is dog instance of Object? '' + (dog instanceof Object)); //true

Ambas respuestas a esta pregunta fueron códigos modificados de un gran artículo de MSDN por Ray Djajadinata.