`injector.js` 中的 `getService` 如何从其调用者 angular 中访问局部变量?

How did `getService` in `injector.js` access local variable from its caller in angular?

考虑官方中的如下代码angular repository

function createInjector(modulesToLoad, strictDi) {
  strictDi = (strictDi === true);
  var testingScope = 'this is a test';
  var INSTANTIATING = {},
      providerSuffix = 'Provider',
      path = [],
      loadedModules = new HashMap([], true),
      providerCache = {
        $provide: {
            provider: supportObject(provider),
            factory: supportObject(factory),
            service: supportObject(service),
            value: supportObject(value),
            constant: supportObject(constant),
            decorator: decorator
          }
      },
      providerInjector = (providerCache.$injector =
          createInternalInjector(providerCache, function(serviceName, caller) {
            if (angular.isString(caller)) {
              path.push(caller);
            }
            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
          })),
      instanceCache = {},
      protoInstanceInjector =
          createInternalInjector(instanceCache, function(serviceName, caller) {
            var provider = providerInjector.get(serviceName + providerSuffix, caller);
            return instanceInjector.invoke(
                provider.$get, provider, undefined, serviceName);
          }),
      instanceInjector = protoInstanceInjector;

  providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
  var runBlocks = loadModules(modulesToLoad);
  instanceInjector = protoInstanceInjector.get('$injector');
  instanceInjector.strictDi = strictDi;
  forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });

  return instanceInjector;

  function createInternalInjector(cache, factory) {

    function getService(serviceName, caller) {
      console.log(testingScope);
      if (cache.hasOwnProperty(serviceName)) {
        if (cache[serviceName] === INSTANTIATING) {
          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
                    serviceName + ' <- ' + path.join(' <- '));
        }
        return cache[serviceName];
      } else {
        try {
          path.unshift(serviceName);
          cache[serviceName] = INSTANTIATING;
          return cache[serviceName] = factory(serviceName, caller);
        } catch (err) {
          if (cache[serviceName] === INSTANTIATING) {
            delete cache[serviceName];
          }
          throw err;
        } finally {
          path.shift();
        }
      }
    }
    return {
      get: getService,
    };
  }

我们看到 createInternalInjector 能够访问其调用者范围 createInjector 中的局部变量(如 path),而无需传递给参数。

事实上,如果我将 testingScope 添加到 createInjector 并尝试在 createInternalInjector 中访问,我能够做到。

这很奇怪,因为我尝试像下面这样复制这种行为。

testOuter();

function testOuter() {
  var outer = 'outer'

  testInner().test();

}

function testInner() {
  function testing() {
    console.log(outer);
  }
  return {
      test: testing
  }
}

但是却出现了错误。

ReferenceError: outer is not defined

谁能告诉我为什么会这样?

这里的问题是作用域链接。 createInternalInjector 函数在 createInjector 函数中调用,因此它可以访问其父属性。在您的情况下,您具有彼此不知道的同级函数变量。

关于作用域链和闭包的更多信息: