“injector.js”中的“getService”是如何从angular中的调用方访问本地变量的

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

本文关键字:调用 方访问 变量 访问 angular 中的 js injector getService      更新时间:2023-09-26

考虑官方角度存储库中的以下代码

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函数中调用的,因此它可以访问其父属性。在您的案例中,您有不知道彼此变量的兄弟函数。

有关作用域链和闭包的更多信息:https://stackoverflow.com/a/1484230/5954939