javascript - example - ¿Por qué TypeScript genera un IIFE para una clase?
que es typescript (2)
Esta pregunta ya tiene una respuesta aquí:
Mirando este código TypeScript:
class Greeter {
greet() {}
}
Genera un IIFE (Expresión de Función Invocada Inmediatamente) alrededor de la función de constructor y todas las declaraciones de función de prototipo como:
var Greeter = (function () {
function Greeter() {
}
Greeter.prototype.greet = function () { };
return Greeter;
}());
¿Cuál es la ventaja aquí? Cada vez que leo sobre IIFE, veo mucho uso en la definición de módulos. Por lo que puedo ver, Typescript no genera nada dentro del IIFE que pueda contaminar el espacio de nombres global.
En mi opinión, no hay ninguna ventaja sobre esta declaración de clase:
var Greeter = function () {}
Greeter.prototype.greet = function () { };
¿Cuál es el motivo?
Eso es interesante. Creo que el compilador mecanografiado compila ClassDeclaration
deducido de ClassExpression
s, asignando la expresión a una variable en el alcance, para que no tengan que manejar esos casos de forma independiente. Esto simplifica el compilador de TypeScript y hace que el código generado sea algo modular (diría más legible, pero eso es solo cuestión de gustos).
class Bar { };
foo(class Baz { });
var Baa = class Bab { };
Compila en:
var Bar = (function () {
function Bar() {
}
return Bar;
}());
;
foo((function () {
function Baz() {
}
return Baz;
}()));
var Baa = (function () {
function Bab() {
}
return Bab;
}());
Ver, la ClassDeclaration
se compila como una ClassExpression
asignada a una variable local.
Para evitar la contaminación del espacio de nombres global.
Es un patrón de clausura donde las funciones internas tienen acceso a las propiedades de sus padres. Por IIFE, se devuelve la REFERENCIA a las funciones internas.
A continuación hay dos escenarios, donde el patrón IIFE es bastante útil y la razón por la cual el compilador TypeScript genera el patrón IIFE:
- Implementación de herencia: donde pasa la
BaseClass
como argumento para IIFE. Si IIFEE no hubiera estado allí,BaseClass
sería una variable global, contaminando así el espacio de nombres global.
TypeScript :
class Greeter extends BaseController {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
JS :
var Greeter = (function(_super) {
__extends(Greeter, _super);
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function() {
return "Hello, " + this.greeting;
};
return Greeter;
}(BaseController));
- Implementación de patrón de módulo: donde la aplicación tiene solo una variable global como ''aplicación'' y todas las demás funciones se envuelven en objetos como
app.cart
,app.catalog
, etc. Solo la variable se expone a través de los módulos y todas las demás características se agregan a los módulos. , que solo es posible con IIFE.
TypeScript :
module App.Controller {
export class Greeter extends BaseController {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
}
JS :
var App;
(function (App) {
var Controller;
(function (Controller) {
var Greeter = (function (_super) {
__extends(Greeter, _super);
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
}(BaseController));
Controller.Greeter = Greeter;
})(Controller = App.Controller || (App.Controller = {}));
})(App || (App = {}));
Copie / Pegue este código js en la consola de los navegadores y solo la variable de la aplicación se creará globalmente. La funcionalidad de reposo estará bajo la aplicación.
Gracias, mkdudeja