0

I'm actually developing a simple application and I have this class, in which I need console.log the result of a function passed in parameters.

Context

I m trying to make a simple DI container based on Ng2 one (simpler, to really understand it way of work) based on the API.

So, I have an Injector class, a Binding class and a ResolvedBinding class. Injector accepts Binding in parameters to create ResolvedBinding objects

Here the injector class :

import {ResolvedBinding} from "./ResolvedBinding";
import {Binding} from "./Binding";


export class Injector {


    private _binds:Array<ResolvedBinding>;


    constructor(bindings:ResolvedBinding[]) {
        this._binds = bindings;
    }

    public static ResolveAndCreate(binds:Array<Binding>):Injector {
        return new Injector(Injector.resolve(binds));
    }

    get(token:any) {
        for (var i in this._binds) {
            if (this._binds[i].key === token) {
                return this._binds[i].factory();
                /*if(new this._binds[i].factory instanceof Object)

                 else
                 return this._binds[i].factory();*/
            }
        }

        return null;
    }

    static resolve(binds:Array<Binding>):Array<ResolvedBinding> {
        var resolvedBindings = new Array<ResolvedBinding>();

        for (var i  in binds) {
            var factory;

            if (binds[i].object.toClass) {
                factory = binds[i].object.toClass;
            } else {
                if (binds[i].object.toFactory) {
                    factory = binds[i].object.toFactory;
                }
                else {
                    if (binds[i].object.toValue) {
                        factory = ()=> {
                            return binds[i].object.toValue;
                        }
                    }
                    else {
                        /* what else ? */
                    }
                }
            }

            resolvedBindings.push(new ResolvedBinding(binds[i].token, factory));
        }


        return resolvedBindings;
    }
}

Here's the binding class :

export class Binding {

    private _token:any;
    private _object:any;

    constructor(token, object) {
        this._token = token;
        this._object = object;
    }

    public get token():any {
        return this._token;
    }

    public get object():any {
        return this._object;
    }
}

And the ResolvedBinding class :

export class ResolvedBinding {

    private _key:any;
    private _factory:any;

    constructor(key:any, factory:any) {
        this._key = key;
        this._factory = factory;
        console.log(this._factory()); // gives the good result;
    }

    public get key():any {
        return this._key;
    }

    public set key(value:any) {
        this._key = value;
    }

    public get factory():any {
        console.log(this._factory()); // gives undefined;
        return this._factory;
    }

}

Here's how I call the injector from my main class :

import { Injector } from './Ioc/Injector';
import { Binding } from './Ioc/Binding';
import { Car } from './Ioc/Car';

var injector = Injector.ResolveAndCreate([
    new Binding(Car, {toClass: Car}),
    new Binding(String, {toValue: "Hello you !"}),
    new Binding(Number, {
        toFactory: () => {
            return 1 + 2;
        }
    })
]);

var carC = injector.get(Car);
var myString = injector.get(String);
var myNumber = injector.get(Number);


console.log(carC); // undefined
console.log(myString); // undefined
console.log(myNumber); // 3

Problem

The problem seems to be when I instantiate ResolvedBinding class and push it to the array. In fact, the _factory property has a value in the constructor, but when I try to log it into the getter, it gives me an undefined, and so I get an undefined when trying to get a Car instance.

Fenton
  • 241,084
  • 71
  • 387
  • 401
mfrachet
  • 8,772
  • 17
  • 55
  • 110

1 Answers1

1

The for loop incorrectly captures a loop variable here:

    if (binds[i].object.toValue) {
        factory = ()=> {
            return binds[i].object.toValue; // <-- bad!
        }
    }

See JavaScript closure inside loops – simple practical example

Community
  • 1
  • 1
Ryan Cavanaugh
  • 209,514
  • 56
  • 272
  • 235