2010-02-16 7 views
104

Mi colega ha estado usando "nueva función()" con una minúscula "f" para definir nuevos objetos en JavaScript. Parece funcionar bien en todos los navegadores principales y también parece ser bastante eficaz para ocultar variables privadas. He aquí un ejemplo:`nueva función()` con minúscula "f" en JavaScript

var someObj = new function() { 
     var inner = 'some value'; 
     this.foo = 'blah'; 

     this.get_inner = function() { 
      return inner; 
     }; 

     this.set_inner = function (s) { 
      inner = s; 
     }; 
    }; 

Tan pronto como "este" se utiliza, se convierte en una propiedad pública de someObj. Así que algunosObj.foo, algunosObj.get_inner() y algunosObj.set_inner() están todos disponibles públicamente. Además, set_inner() y get_inner() son métodos privilegiados, por lo que tienen acceso a cierres "internos".

Sin embargo, no he visto ninguna referencia a esta técnica en ninguna parte. Incluso JSLint de Douglas Crockford se queja al respecto:

  • construcción raro. Eliminar 'nuevo'

Estamos utilizando esta técnica en la producción y parece estar funcionando bien, pero estoy un poco ansioso al respecto porque no está documentada en cualquier lugar. ¿Alguien sabe si esta es una técnica válida?

+5

Prefiero tu construcción sobre el IIFE ('Función invocada inmediatamente'). 1: no necesita un objeto explícito de 'instancia', eso es exactamente lo que 'esto' es en JavaScript. 2: No necesita devolver nada, lo que significa que no necesita recordarlo. Incluso el autor de la respuesta aceptada se olvidó de devolver el objeto de instancia inicialmente. Por lo general, las personas prefieren usar un IIFE si odian lo nuevo y esto, con buena razón: si tienes una función manejando un evento DOM, 'this' se referirá al elemento que activó el evento, no a tu objeto, pero podrías tener 'var instance = this' en su lugar. –

+1

¿Por qué es importante para la pregunta especificar "minúscula f"? – ClearCloud8

+7

Porque en Javascript también existe la función 'Function' (con F mayúscula), que es diferente: __Function__ es una función constructora que puede crear nuevos objetos de función, mientras que __function__ es una palabra clave. –

Respuesta

63

He visto esa técnica anteriormente, es válida, está utilizando una expresión de función como si fuera Constructor Function.

Pero en mi humilde opinión, se puede lograr el mismo con una expresión de la función de auto-invocando, yo realmente no veo el punto de utilizar el operador new de esa manera:

var someObj = (function() { 
    var instance = {}, 
     inner = 'some value'; 

    instance.foo = 'blah'; 

    instance.get_inner = function() { 
     return inner; 
    }; 

    instance.set_inner = function (s) { 
     inner = s; 
    }; 

    return instance; 
})(); 

El propósito del operador new es crear nuevas instancias de objeto, configurando la propiedad interna [[Prototype]], puede ver cómo se hace esto mediante la propiedad interna [Construct].

El código anterior producirá un resultado equivalente.

+1

La especificación ECMAScript 262 en la Sección 13 explica esto un poco más formalmente. Algo como 'function foo() {}' devuelve el resultado de crear un objeto 'Function' [presumiblemente con la nueva función()]. Es sintaxis azúcar. –

+3

Creo que te falta una 'instancia de devolución' al final. De lo contrario, 'someObj' simplemente será' undefined'.:-) –

+0

@Matthew: Sí, me perdí la declaración 'return', gracias. – CMS

15

Su código es similar a la construcción de menos raro

function Foo() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    ... 
}; 
var someObj = new Foo; 
+9

No es exactamente similar, hace exactamente lo mismo ... con la única excepción de que no podrán reutilizar Foo para crear otro objeto. – kikito

+3

La versión del OP podría reutilizarse a través de ** new someObj.constructor **. Aquí el constructor se agrega al espacio de nombres explícitamente; el estilo correcto depende del propósito previsto de la función. Además, este estilo, aunque ciertamente el estándar, permite que alguien llene el espacio de nombres global si olvida ** nuevo ** antes de ** Foo **. –

+0

@kikito, ¿a qué te refieres con que esto no permite reutilizar a Foo para crear otro objeto? var newObj = new Foo() debería estar creando una nueva instancia. –

12

Para aclarar algunos aspectos y hacer JSLint de Douglas Crockford no quejarse acerca de su código aquí son algunos ejemplos de creación de instancias:

1. o = new Object(); // normal call of a constructor 

2. o = new Object; // accepted call of a constructor 

3. var someObj = new (function() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    this.get_inner = function() { 
     return inner; 
    }; 

    this.set_inner = function (s) { 
     inner = s; 
    }; 
})(); // normal call of a constructor 

4. var someObj = new (function() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    this.get_inner = function() { 
     return inner; 
    }; 

    this.set_inner = function (s) { 
     inner = s; 
    }; 
}); // accepted call of a constructor 

En el ejemplo 3. expresión en (...) como valor es una función/constructor. Se ve así: new (function() {...})(). Si omite los corchetes finales como en el ejemplo 2, la expresión sigue siendo una llamada de constructor válida y se ve como el ejemplo 4.

Douglas Crockford's JSLint "piensa" que quería asignar la función a algún Obj, no a su instancia. Y, después de todo, es solo una advertencia, no un error.

Cuestiones relacionadas