template navigationend for example oop angularjs

navigationend - angularjs con oop herencia en acción



ng-template angular 5 (3)

Creo que sus suposiciones son bastante buenas y jugué con algunos enfoques como ese, pero todos resultaron más prolijos de lo que esperaba.

Tuve un problema donde desarrollé un cuadro de diálogo complejo como pestaña en nuestra interfaz de administración, pero quería un diálogo casi idéntico en una ventana emergente en la sección de usuario, pero los datos se llenarían de una fuente diferente y habría unos pocos. botones adicionales. Básicamente es un gran candidato para la herencia clásica. Para el lado de UI utilicé una plantilla que se incluyó en dos lugares con diferentes controladores. Pero para evitar la duplicación de la compleja lógica de UI en los controladores, quería usar la herencia.

El método de herencia de alcance se basa en cierta medida en la estructura de la aplicación y no era apropiado porque las dos interfaces de usuario se encontraban en aplicaciones efectivamente diferentes. El enfoque de poner el código reutilizado en los servicios terminaría siendo detallado, ya que habría necesitado que cada método del controlador llamara a un método equivalente en el servicio. Así que utilicé el siguiente enfoque simple para la herencia de JavaScript:

/** * Effective base class for Thing Controllers. * This should be considered abstract since it does not define * $scope.readData() or $scope.saveData() which may be called from its * other functions. */ function BaseThingController($scope, $http){ $scope.data = []; // local data store; $scope.validateForm(){...} $scope.edit(){...} $scope.cancel(){...} $scope.reset(){...} $scope.otherMethod1(){...} $scope.otherMethod2(){...} $scope.otherMethod3(){...} } /** * AdminThingController effectively extends BaseThingController */ function AdminThingController($scope, $http){ // Calling BaseThingController as a function defines all the needed // functions and properties in our scope. BaseThingController($scope, $http) $scope.readData(){ // $scope.data = data from admin data source } $scope.saveData(newData){ // save to special admin service } // initialize local data $scope.readData() } /** * UserThingController effectively extends BaseThingController */ function UserThingController($scope, $http){ // Calling BaseThingController as a function defines all the needed // functions and properties in our scope. BaseThingController($scope, $http) $scope.readData(){ // $scope.data = data from user data source } $scope.saveData(newData){ // save to user service } /** * Overriding base class behaviour here */ $scope.otherMethod1(){...} // initialize local data $scope.readData() }

Así que no he usado la herencia de prototipos ya que $ scope está disponible. Pero obtuve todo el comportamiento del controlador base y solo agregué o anulé lo que quería. Mis vistas podrían configurarse con cualquiera de los controladores y funcionarían sin modificaciones.

Abstracto

Estoy trabajando en una aplicación que utiliza angular como marco de trabajo del cliente, actualmente angular rocks y estoy muy contento de usarlo, aunque ahora me parece que uso mucho para copiar y pegar el código que me gustaría organizar en la jerarquía de clases . Por ejemplo, los diálogos comparten un conjunto de funcionalidades comunes, necesitan abrirse, cerrarse, el código que proporciona funcionalidad de typeahead también es el primer candidato para heredar de un padre BaseTypeaheadClass, aunque una cosa que no encontré en angular es una forma estándar de organizar estas jerarquías. Ambos controladores, servicios y proveedores usan funciones normales de JavaScript debajo de las cuales se pueden extender por medio de un prototype , por lo que mi pregunta es:

Pregunta

¿Cuál es la forma angular de organizar mis funciones de clase? ¿Hay algún mecanismo estándar que permita derivar una clase de otra clase?

PD

Mis conjeturas sobre el problema:

  • Defina la implementación de las clases base como servicios, como resultado, se inyectarán fácilmente en cualquier controlador u otros servicios donde se necesite esa clase específica
  • Defina el servicio OOP y proporcione métodos tales como define , derive , etc. que se usarán para crear clases base / derivadas

Editar

Ha pasado algún tiempo desde el momento en que inicialmente estaba haciendo mi pregunta. Desde entonces, he presentado un enfoque que estoy utilizando con éxito en varios proyectos, que me gusta mucho y quiero compartir con todos.

Actualmente angular no proporciona ninguna construcción para organizar las jerarquías de clase y es una pena, ya que una aplicación más o menos grande no puede ser suficiente solo para las construcciones Model / View / Controller / ..., tiene que organizar su código en objetos OOP.

Estoy trabajando en el campo del desarrollo web desde hace bastante tiempo y no he visto ni siquiera un proyecto empresarial que aprovechara masivamente el OOP con JavaScript. Lo que vi fue una gran y bien organizada lógica del lado del servidor / de la base de datos + cerca de infinitos espaguetis de javascript engrasados ​​con el zoo de marcos y bibliotecas en el lado del cliente.

Ningún MVVM, frameworks MVP como knockout.js, backbone, otros ... son capaces de reemplazar el OOP como tal. Si no está utilizando principios básicos de programación orientada, como Clases, Objetos, Herencias, Abstracción, Polimorfismo, está en un gran problema, lo que terminará es un espaghetti javascript mega largo.

En cuanto a Angular, creo que es un framework muy diferente de knockout.js / backbone.js / cualquier otro MVV-cualquier framework pero según mi práctica tampoco es una bala de plata capaz de reemplazar OOP. Cuando trato de no usar el OOP con Angular, termino con una lógica duplicada ubicada principalmente en los controladores. Y desafortunadamente no hay (no he encontrado) una forma limpia y angular de vencer ese problema.

Pero he resuelto con éxito (creo) ese problema.

Utilicé lib compacto y de dependencia cero que solo implementa John Resig''s Simple JavaScript Inheritance ( https://github.com/tracker1/core-js/blob/master/js-extensions/040-Class.js ). Con la ayuda de esa biblioteca pude crear / heredar / crear métodos abstractos / anularlos, en otras palabras, hacer todo lo que he acostumbrado en el lado del servidor.

Aquí hay un ejemplo de uso:

Application.factory(''SomeChildObject'', [''$http'', ''SomeParentClass'', function ($http, SomeParentClass) { var SomeChildClass = SomeParentClass.extend({ init: function() { // Constructor this._super.init(123, 231); // call base constructor }, someFunction: function() { // Notice that your OOP now knows everything that can be injected into angular service, which is pretty cool :) $http({method: ''GET'', url: ''/someUrl''}).then(function(){ this._super.someFunction(); // call base function implementation }); } }); // return new SomeChildClass(); // We are not returning instance here! return SomeChildClass; // Service is a function definition not an instance of an object }]); // So now we can both use this service in angular and have the ability to extend it using the `extend` method call, like so: Application.controller(''MegaController'', [''$scope'', ''SomeChildClass'', function ($scope, SomeChildClass) { $scope.someObject = new SomeChildClass(); }]);

OOP + Angular juega muy bien, los objetos creados en contexto angular pueden aprovechar la inyección de dependencia a través de servicios automáticamente, por lo que no es necesario inyectar instancias en los constructores de OOP, lo que hace que su jerarquía de OOP sea muy delgada y libre de elementos irrelevantes eso necesita ser (y es) manejado por angular.js

Así que juega con este enfoque y da tu opinión aquí con los resultados que obtuviste o los problemas que encontraste,

Otra edición

Recientemente me he enfrentado a algunos problemas con la implementación original de Class.js, de la siguiente manera:

1) Si va a pasar una referencia a sus métodos de instancia como devoluciones de llamada a otros métodos, estos métodos podrían funcionar de la manera que usted espera que no funcionen. Perderán referencia a this . En tal caso, esperará ver su objeto actual dentro de this pero será una Window nivel superior u otro objeto de contexto dependiendo de cómo la devolución de llamada llame a su método. Sucede debido a la arquitectura de JavaScript. Para combatir este problema, se proporciona una función especial ClassMember que indica a la Class que vincule su método al contexto del objeto cuando se está creando (ver Usage continuación para obtener más información).

2) Obviamente, la implementación original de Class.js no sabe nada sobre el tipo angular de las declaraciones de métodos de controlador, es decir,

Class.extend(''YourClassDisplayName'', { ctor: function () { // Some useful constructor logic }, controller: [''$scope'', ''$attrs'', function ($scope, $attrs) { // Do something with $scope and $attrs }] });

La implementación actual comprende la sintaxis anterior

3) Al usar el método anterior sin un manejo adecuado, se rompería el proceso $$annotate angular $$annotate '', por lo que al hacer referencia al ejemplo anterior sería imposible inyectar $scope y $attrs en el método ClassMember , o reemplazar el método que está usando this.base(...) llamadas. Entonces esto también está arreglado.

Gotchas:

1) Al usar this.base(...) dentro del controlador de operación asincrónico (algo así como $http.get(..., function() { self.base(...); }) ) tenga en cuenta que this.base(...) call tiene una vida útil limitada y tan pronto como el método retorne this.base(...) deja de existir. Por lo tanto, debe guardar explícitamente la referencia al método base si planea llamar a los métodos básicos de manera asíncrona. es decir:

... var self = this; var base = this.base; ... $http.get(..., function () { base.call(self, ...); // or base.apply(self, ...), or base() if you don''t care about `this` })

Resolví todos los problemas anteriores (excepto uno que no se pudo resolver debido a la arquitectura de JavaScript) y me gustaría compartirlos con todos, espero que se beneficien de ello:

/* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. * * Inspired by base2 and Prototype * Angular adaptations by Denis Yaremov http://github.com/lu4 * Usage: --------------------------------- var X = Class.extend(''X'', { ctor: function () { this.name = "I''m X"; }, myOrdinaryMethod: function (x, y, z) { console.log([this.name, x, y, z]); }, myClassMemberMethod: ClassMember(function (x, y, z) { console.log([this.name, x, y, z]); }) }); var Y = Class.extend(''Y'', { ctor: function () { this.name = "I''m Y"; }, myOrdinaryMethod: function (x, y, z) { console.log([this.name, x, y, z]); }, myClassMemberMethod: ClassMember(function (x, y, z) { console.log([this.name, x, y, z]); }) }); var x = new X(); var y = new Y(); x.myClassMemberMethod(''a'', ''b'', ''c''); // ["I''m X", "a", "b", "c"] y.myClassMemberMethod(''u'', ''v'', ''m''); // ["I''m Y", "u", "v", "m"] x.myOrdinaryMethod(''a'', ''b'', ''c''); // ["I''m X", "a", "b", "c"] y.myOrdinaryMethod(''u'', ''v'', ''m''); // ["I''m Y", "u", "v", "m"] y.theirOrdinaryMethod = x.myOrdinaryMethod; y.theirClassMemberMethod = x.myClassMemberMethod; y.theirOrdinaryMethod(''a'', ''b'', ''c''); // ["I''m Y", "a", "b", "c"] y.theirClassMemberMethod(''u'', ''v'', ''m''); // ["I''m X", "u", "v", "m"] */ angular.module(''app'').factory(''ClassMember'', function () { return function ClassMember(fn) { if (this instanceof ClassMember) { this.fn = fn; } else { return new ClassMember(fn); } }; }); angular.module(''app'').factory(''Class'', function (ClassMember) { var runtime = { initializing: false }, fnTest = /xyz/.test(function() { xyz; }) ? //bbase/b/ : /.*/, FN_ARGS = /^function/s*[^/(]*/(/s*([^/)]*)/)/m, STRIP_COMMENTS = /((////.*$)|(///*[/s/S]*?/*//))/mg; var toString = Object.prototype.toString; // The base Class implementation (does nothing) function Class() { }; Class.members = { }; // Create a new Class that inherits from this class Class.extend = function extend(displayName, properties) { var array; var targetMembers = {}; var sourceMembers = this.members; for (var memberName in sourceMembers) { if (sourceMembers.hasOwnProperty(memberName)) { targetMembers[memberName] = sourceMembers[memberName]; } } var base = this.prototype; // Instantiate a base class (but only create the instance, // don''t run the ctor constructor) runtime.initializing = true; var prototype = new this(); runtime.initializing = false; // Copy the properties over onto the new prototype for (var name in properties) { if (properties.hasOwnProperty(name)) { // Check if we''re overwriting an existing function var property = properties[name]; // Support angular''s controller/service/factory declaration notation if (toString.call(property) === ''[object Array]'') { array = property; var item = array[array.length - 1]; if (toString.call(item) === ''[object Function]'' || item instanceof ClassMember) { property = array[array.length - 1]; } else { array = null; } } else { array = null; } var isClassMember = property instanceof ClassMember; if (isClassMember) { property = property.fn; } if (typeof property === "function") { if (typeof base[name] === "function" && fnTest.test(property)) { property = (function (propertyName, fn) { var args = fn.toString().replace(STRIP_COMMENTS, '''').match(FN_ARGS)[1]; return (new Function(''propertyName'', ''fn'', ''base'', ''return function ('' + args + '') {/n/ var prevBase = this.base;/n/ var hasBase = "base" in this;/n/ /n/ // Add a new .base() method that is the same method/n/ // but on the super-class/n/ /n/ this.base = base[propertyName];/n/ /n/ // The method only need to be bound temporarily, so we/n/ // remove it when we/'re done executing/n/ var ret = fn.call(this'' + (!!args ? ('', '' + args) : args) + '');/n/ /n/ if (hasBase) {/n/ this.base = prevBase;/n/ } else {/n/ delete this["base"];/n/ }/n/ return ret;/n/ }''))(propertyName, fn, base); })(name, property); } if (isClassMember) { targetMembers[name] = property; } else if (name in targetMembers) { delete targetMembers[name]; } if (array) { array[array.length - 1] = property; property = array; } prototype[name] = property; } else { prototype[name] = property; } } } var membersArray = []; for (var i in targetMembers) { if (targetMembers.hasOwnProperty(i)) { membersArray.push({ name: i, fn: targetMembers[i] }); } } // All construction is actually done in the ctor method var ChildClass = (new Function("runtime", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {/n/ if (!runtime.initializing && this.ctor)/n/ {/n/ var length = members.length;/n/ for (var i = 0; i < length; i++)/n/ {/n/ var item = members[i];/n/ this[item.name] = (function (me, fn) {/n/ var args = fn.toString().replace(STRIP_COMMENTS, '''').match(FN_ARGS)[1];/n/ return args ? (new Function(''me'', ''fn'', ''return function ('' + args + '') { return fn.call(me, '' + args + ''); }''))(me, fn) : function () { return fn.call(me); };/n/ })(this, item.fn);/n/ /n/ }/n/ this.ctor.apply(this, arguments);/n/ }/n/ }"))(runtime, membersArray, FN_ARGS, STRIP_COMMENTS); ChildClass.members = targetMembers; // Populate our constructed prototype object ChildClass.prototype = prototype; // Enforce the constructor to be what we expect ChildClass.prototype.constructor = ChildClass; // And make this class extendable ChildClass.extend = extend; return ChildClass; }; return Class; });

Otra edición

Finalmente me encontré con otro problema relacionado con la implementación original de John Resig en relación con angular, y el problema está relacionado con el proceso de anotación de angular (utilizado para la inyección de dependencia) que utiliza Function.prototype.toString () y algunos Regex''es para el propósito de extraer los nombres de las dependencias. Y el problema con la implementación original es que no espera esto y por lo tanto no puede declarar métodos que acepten dependencias, así que modifiqué un poco la implementación para tratar el problema descrito anteriormente y aquí está:

/* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. * * Inspired by base2 and Prototype * Angular adaptations by Denis Yaremov http://github.com/lu4 * Usage: --------------------------------- var X = Class.extend(''X'', { ctor: function () { this.name = "I''m X"; }, myOrdinaryMethod: function (x, y, z) { console.log([this.name, x, y, z]); }, myClassMemberMethod: ClassMember(function (x, y, z) { console.log([this.name, x, y, z]); }) }); var Y = Class.extend(''Y'', { ctor: function () { this.name = "I''m Y"; }, myOrdinaryMethod: function (x, y, z) { console.log([this.name, x, y, z]); }, myClassMemberMethod: ClassMember(function (x, y, z) { console.log([this.name, x, y, z]); }) }); var x = new X(); var y = new Y(); x.myClassMemberMethod(''a'', ''b'', ''c''); // ["I''m X", "a", "b", "c"] y.myClassMemberMethod(''u'', ''v'', ''m''); // ["I''m Y", "u", "v", "m"] x.myOrdinaryMethod(''a'', ''b'', ''c''); // ["I''m X", "a", "b", "c"] y.myOrdinaryMethod(''u'', ''v'', ''m''); // ["I''m Y", "u", "v", "m"] y.theirOrdinaryMethod = x.myOrdinaryMethod; y.theirClassMemberMethod = x.myClassMemberMethod; y.theirOrdinaryMethod(''a'', ''b'', ''c''); // ["I''m Y", "a", "b", "c"] y.theirClassMemberMethod(''u'', ''v'', ''m''); // ["I''m X", "u", "v", "m"] */ angular.module(''homer'').factory(''Class'', function () { function ClassMember(fn) { if (this instanceof ClassMember) { this.fn = fn; return this; } else { return new ClassMember(fn); } } function ClassEvent() { if (this instanceof ClassEvent) { return this; } else { return new ClassEvent(); } } var runtime = { initializing: false }, fnTest = /xyz/.test(function () { xyz; }) ? //bbase/b/ : /.*/, fnArgs = /^function/s*[^/(]*/(/s*([^/)]*)/)/m, stripComments = /((////.*$)|(///*[/s/S]*?/*//))/mg; var toString = Object.prototype.toString; // The base Class implementation (does nothing) function Class() { }; Class.events = {}; Class.members = {}; // Create a new Class that inherits from this class Class.extend = function Extend(displayName, properties) { var array; var targetEvents = {}; var sourceEvents = this.events; var targetMembers = {}; var sourceMembers = this.members; for (var eventName in sourceEvents) { if (sourceEvents.hasOwnProperty(eventName)) { targetEvents[eventName] = sourceEvents[eventName]; } } for (var memberName in sourceMembers) { if (sourceMembers.hasOwnProperty(memberName)) { targetMembers[memberName] = sourceMembers[memberName]; } } var base = this.prototype; // Instantiate a base class (but only create the instance, // don''t run the ctor constructor) runtime.initializing = true; var prototype = new this(); runtime.initializing = false; // Copy the properties over onto the new prototype for (var name in properties) { if (properties.hasOwnProperty(name)) { // Check if we''re overwriting an existing function var property = properties[name]; // Support angular''s controller/service/factory declaration notation if (toString.call(property) === ''[object Array]'') { array = property; var item = array[array.length - 1]; if (toString.call(item) === ''[object Function]'' || item instanceof ClassMember) { property = array[array.length - 1]; } else { array = null; } } else { array = null; } var isClassMember = property instanceof ClassMember; if (isClassMember) { property = property.fn; } var isClassEvent = property instanceof ClassEvent; if (isClassEvent) { property = (function() { function Subscriber(fn) { Subscriber.listeners.push(fn.bind(this)); }; Subscriber.listeners = []; Subscriber.fire = function() { var listeners = Subscriber.listeners; for (var i = 0; i < listeners.length; i++) { var result = listeners[i].apply(this, arguments); if (result !== undefined) return result; } return void 0; } return Subscriber; })(); } if (typeof property === "function") { if (typeof base[name] === "function" && fnTest.test(property)) { property = (function (propertyName, fn) { var args = fn.toString().replace(stripComments, '''').match(fnArgs)[1]; return (new Function(''propertyName'', ''fn'', ''base'', ''return function ('' + args + '') {/n/ var prevBase = this.base;/n/ var hasBase = "base" in this;/n/ /n/ // Add a new .base() method that is the same method/n/ // but on the super-class/n/ /n/ this.base = base[propertyName];/n/ /n/ // The method only need to be bound temporarily, so we/n/ // remove it when we/'re done executing/n/ var ret = fn.call(this'' + (!!args ? ('', '' + args) : args) + '');/n/ /n/ if (hasBase) {/n/ this.base = prevBase;/n/ } else {/n/ delete this["base"];/n/ }/n/ return ret;/n/ }''))(propertyName, fn, base); })(name, property); } if (isClassEvent) { targetEvents[name] = property; } else { delete targetEvents[name]; } if (isClassMember) { targetMembers[name] = property; } else if (name in targetMembers) { delete targetMembers[name]; } if (array) { array[array.length - 1] = property; property = array; } prototype[name] = property; } else { prototype[name] = property; } } } var eventsArray = []; for (var targetEventName in targetEvents) { if (targetEvents.hasOwnProperty(targetEventName)) { eventsArray.push({ name: targetEventName, fn: targetEvents[targetEventName] }); } } var membersArray = []; for (var targetMemberName in targetMembers) { if (targetMembers.hasOwnProperty(targetMemberName)) { membersArray.push({ name: targetMemberName, fn: targetMembers[targetMemberName] }); } } // All construction is actually done in the ctor method var ChildClass = (new Function("runtime", "events", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {/n/ if (!runtime.initializing && this.ctor)/n/ {/n/ var length = members.length;/n/ var bind = function (me, $$fn$$) {/n/ var args = $$fn$$.toString().replace(STRIP_COMMENTS, '''').match(FN_ARGS)[1];/n/ var result = args ? (new Function(''me'', ''$$fn$$'', ''return function ('' + args + '') { return $$fn$$.apply(me, arguments); }''))(me, $$fn$$) : function () { return $$fn$$.apply(me, arguments); };/n/ return result;/n/ };/n/ for (var i = 0; i < length; i++)/n/ {/n/ var item = members[i];/n/ var fn = item.fn;/n/ var name = item.name;/n/ var property = this[name] = bind(this, fn);/n/ if (fn.fire) {/n/ property.fire = bind(this, fn.fire);/n/ }/n/ if (fn.listeners) {/n/ property.listeners = fn.listeners;/n/ }/n/ }/n/ /n/ var length = events.length;/n/ for (var i = 0; i < length; i++)/n/ {/n/ var item = events[i];/n/ var fn = item.fn;/n/ var name = item.name;/n/ var property = this[name] = bind(this, fn);/n/ if (fn.fire) {/n/ property.fire = bind(this, fn.fire);/n/ }/n/ if (fn.listeners) {/n/ property.listeners = fn.listeners;/n/ }/n/ }/n/ this.ctor.apply(this, arguments);/n/ }/n/ }"))(runtime, eventsArray, membersArray, fnArgs, stripComments); ChildClass.members = targetMembers; // Populate our constructed prototype object ChildClass.prototype = prototype; // Enforce the constructor to be what we expect ChildClass.prototype.constructor = ChildClass; // And make this class extendable ChildClass.extend = Extend; ChildClass.event = ClassEvent; ChildClass.member = ClassMember; return ChildClass; }; Class.member = ClassMember; Class.event = ClassEvent; return Class; });


Déjame darte mi opinión sobre la situación Angular / herencia.

No haces herencia de clase / prototipo en Angular.js. Puede ser difícil de probar, y eso es un problema. Para aquellos que están buscando ''herencia'' en Angular, recomiendo esto:

Tu clase base es el controlador . El controlador es un modelo abstracto de todos modos, por lo que es perfecto para ese propósito. Use una función $ scope.init () en su controlador, ¡pero no lo llame desde allí!

Si quiere ''ampliar'' la funcionalidad de su controlador, use directivas . En su función directive link (), llame al controlador $ scope.init (). (al compilar, primero, los controladores de ejecución angular y las funciones de enlace de directivas después). Si el alcance tuviera $scope.name=''base'' , en el enlace de la directiva podrá redefinir $scope.name=child y luego ejecutar $ scope.init ().

¡Pero espera! Pero esto solo permite una herencia de un solo nivel. - Sí, eso es verdad. Pero si busca herencia multinivel, debe usar Servicios .

La herencia multinivel no es otra cosa, sino que comparte el mismo código en una estructura de clase jerárquica. Para este propósito, use Servicios y agregue estos servicios con el inyector de dependencia a sus directivas. Muy fácil. Esto debería ser fácil de lograr, fácil de entender, y las pruebas se ejecutan sin problemas.

Las directivas son herramientas muy potentes, porque puede combinar dinámicamente parciales con controladores.


Tus conjeturas suenan perfectamente aplicables.

Puede reutilizar la funcionalidad definida en los controladores principales simplemente llamando a los métodos adjuntos al alcance principal:

HTML

<div ng-controller="ParentCtrl"> <!-- Something here ... --> <div ng-controller="ChildCtrl"> <!-- Something here ... --> </div> <!-- Something here ... --> </div>

JavaScript

function ParentCtrl($scope) { $scope.parentMethod = function () { //method body }; } function ChildCtrl($scope) { $scope.childMethod = function () { //functionality $scope.parentMethod(); //functionality }; }

Si desea utilizar el enfoque de JavaScript con herencia de prototipo, puede usar:

var myApp = angular.module(''myApp'',[]); function Parent($scope) { $scope.name = ''Superhero''; $scope.clickParent = function() { $scope.name = ''Clicked from base controller''; } } function Child($scope, $injector) { debugger; $injector.invoke(Parent, this, {$scope: $scope}); $scope.name = ''Superhero Child''; $scope.clickChild = function(){ $scope.clickParent(); } } Child.prototype = Object.create(Parent.prototype);

http://jsfiddle.net/mhevery/u6s88/12/

Para servicios, por ejemplo, puede usar:

(function () { function ParentService(arg1) { this.arg1 = arg1; } function ChildService(arg1, arg2) { ParentService.call(this, arg1); this.arg2 = arg2; } ChildService.prototype = new ParentService(); app.service(''ChildService'', ChildService); }());

También consulte this discusión y la publicación del blog sobre herencia en AngularJS que publiqué .