Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 8b6b428

Browse files
mprobstlgalfaso
authored andcommitted
feat($injector): support instantiating classes.
ES6's `class Foo {}` constructors cannot be instantiated using `fn.apply`. This change extracts injection argument collection and then uses new (Function.bind.apply(ctor, args)) to instantiate the service instance. Closes: #12598 Closes: #12597
1 parent 8f0b482 commit 8b6b428

File tree

2 files changed

+37
-21
lines changed

2 files changed

+37
-21
lines changed

src/auto/injector.js

+27-21
Original file line numberDiff line numberDiff line change
@@ -804,48 +804,54 @@ function createInjector(modulesToLoad, strictDi) {
804804
}
805805
}
806806

807-
function invoke(fn, self, locals, serviceName) {
808-
if (typeof locals === 'string') {
809-
serviceName = locals;
810-
locals = null;
811-
}
812807

808+
function injectionArgs(fn, locals, serviceName) {
813809
var args = [],
814-
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
815-
length, i,
816-
key;
810+
$inject = createInjector.$$annotate(fn, strictDi, serviceName);
817811

818-
for (i = 0, length = $inject.length; i < length; i++) {
819-
key = $inject[i];
812+
for (var i = 0, length = $inject.length; i < length; i++) {
813+
var key = $inject[i];
820814
if (typeof key !== 'string') {
821815
throw $injectorMinErr('itkn',
822816
'Incorrect injection token! Expected service name as string, got {0}', key);
823817
}
824-
args.push(
825-
locals && locals.hasOwnProperty(key)
826-
? locals[key]
827-
: getService(key, serviceName)
828-
);
818+
args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
819+
getService(key, serviceName));
829820
}
821+
return args;
822+
}
823+
824+
825+
function invoke(fn, self, locals, serviceName) {
826+
if (typeof locals === 'string') {
827+
serviceName = locals;
828+
locals = null;
829+
}
830+
831+
var args = injectionArgs(fn, locals, serviceName);
830832
if (isArray(fn)) {
831-
fn = fn[length];
833+
fn = fn[fn.length - 1];
832834
}
833835

834836
// http://jsperf.com/angularjs-invoke-apply-vs-switch
835837
// #5388
836838
return fn.apply(self, args);
837839
}
838840

841+
839842
function instantiate(Type, locals, serviceName) {
840843
// Check if Type is annotated and use just the given function at n-1 as parameter
841844
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
842-
// Object creation: http://jsperf.com/create-constructor/2
843-
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
844-
var returnedValue = invoke(Type, instance, locals, serviceName);
845-
846-
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
845+
var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
846+
var args = injectionArgs(Type, locals, serviceName);
847+
// Empty object at position 0 is ignored for invocation with `new`, but required.
848+
args.unshift({});
849+
/*jshint -W058 */ // Applying a constructor without immediate parentheses is the point here.
850+
return new (Function.prototype.bind.apply(ctor, args));
851+
/*jshint +W058 */
847852
}
848853

854+
849855
return {
850856
invoke: invoke,
851857
instantiate: instantiate,

test/auto/injectorSpec.js

+10
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,16 @@ describe('injector', function() {
270270
it('should take args before first arrow', function() {
271271
expect(annotate(eval('a => b => b'))).toEqual(['a']);
272272
});
273+
274+
it('should be possible to instantiate ES6 classes', function() {
275+
// Only Chrome (not even the FF we use) supports ES6 classes.
276+
if (!/chrome/i.test(navigator.userAgent)) return;
277+
providers('a', function() { return 'a-value'; });
278+
var clazz = eval('(class { constructor(a) { this.a = a; } aVal() { return this.a; } })');
279+
var instance = injector.instantiate(clazz);
280+
expect(instance).toEqual({a: 'a-value'});
281+
expect(instance.aVal()).toEqual('a-value');
282+
});
273283
/*jshint +W061 */
274284
});
275285
}

0 commit comments

Comments
 (0)