2015-09-06 5 views
0

Рекомендуемый способ передачи функции различным методам AngularJS - это использовать синтаксис, который вызывается в документе AngularJS docs, обозначение массива.Передача функции в качестве параметра - нотация массива

Вы должны сделать это:

app.controller("MyCtrl", ['$scope', function($scope){ 
$scope.someData = "Array notation"; 
}]); 

вместо этого:

app.controller("MyCtrl", function($scope){ 
$scope.someData = "non-array notation"; 
}); 

из-за инъекции зависимостей путь AngularJS и Минимизация работ.

Я хотел бы знать, является ли первый способ передачи функции как параметра синтаксисом, упомянутым в стандарте JavaScript? В этом контексте в Интернете я не нашел ничего о «нотации массива».

+0

Это не упоминается в JS, потому что это просто соглашение, но легкое для подражания. В соответствующем коде достаточно проверить тип аргумента: если это просто функция, попытайтесь извлечь зависимость, проанализировав ее исходный код. – raina77ow

+0

Нет, вы можете передать кучу строк до того, как функция и угловые обработают их. – kappaallday

ответ

1

Это просто конвенция - но она продумана довольно хорошо, поэтому ее использовали по всему Угловому. См., Функция - модуль - может иметь только одну зависимость (как в вашем примере), или многие из них (начиная с двух, справа) или вообще не зависят. Поэтому нам нужно какое-то решение, которое отвечает на все случаи.

Наивный подход определяет все депо в качестве аргументов функции (ваш второй пример). Теперь можно извлечь (и ввести) их, проанализировав исходный код функции. Pro: абсолютный минимальный код для записи (в любом случае вам придется указывать все имена депо). Минусы: 1) на основе отражения (которое никогда не бывает быстрым), 2) ломается, когда скрипт минимизируется (и все имена параметров преобразуются).

Эти недостатки достаточно плохи, поэтому просто должен быть другой способ. Мы бы не захотели избавиться от списка аргументов, хотя (эти депилы все равно должны были быть рассмотрены внутри функции каким-то образом, верно?). Но теперь ясно, что единого списка недостаточно - его нужно где-то дублировать.

И вот здесь Array - упорядоченная последовательность элементов - пригодится. Теперь инжектору нужно отделить последний элемент этого массива, чтобы получить полный список депо. Это строки, а не переменные, поэтому они не будут модифицированы с помощью минификатора. Что еще лучше, теперь нам не нужно анализировать подпись, поэтому инжектор работает немного быстрее.


От теории к практике: это то, как эти два подхода реализуются в Angular 1.x DI модуле:

function annotate(fn, strictDi, name) { 
    var $inject, 
     fnText, 
     argDecl, 
     last; 

    if (typeof fn === 'function') { 
    // first approach: only function is passed, we need to analyze the args list 
    if (!($inject = fn.$inject)) { 
     $inject = []; 
     if (fn.length) { 
     if (strictDi) { 
      if (!isString(name) || !name) { 
      name = fn.name || anonFn(fn); 
      } 
      throw $injectorMinErr('strictdi', 
      '{0} is not using explicit annotation and cannot be invoked in strict mode', name); 
     } 
     // get rid of comments, it's possible to have those inside `()` 
     fnText = fn.toString().replace(STRIP_COMMENTS, ''); 
     // extract arguments 
     argDecl = fnText.match(FN_ARGS); 
     // push those into injector 
     forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { 
      arg.replace(FN_ARG, function(all, underscore, name) { 
      $inject.push(name); 
      }); 
     }); 
     // ... and that took some time 
     } 
     fn.$inject = $inject; 
    } 
    } else if (isArray(fn)) { 
    // second approach: an array is passed 
    last = fn.length - 1; 
    // make sure its last element is a function 
    assertArgFn(fn[last], 'fn'); 
    // use all but the last element as list of deps 
    $inject = fn.slice(0, last); 
    // ... and that's all, believe it or not! 
    } else { 
    assertArgFn(fn, 'fn', true); 
    } 
    return $inject; 
} 

Как вы видите, первый if ветвь для старинке - DEPS выражается как аргументы функции , Второй (гораздо легче читать и выполнять) - для отпечатков и функций, помещенных в массив (функция является последним элементом).

+0

Спасибо за удивительный ответ! Мне любопытно, возможно, что может быть целью «fn» в assertArgFn (fn [last], 'fn')?Само название метода, assertArg ** Fn **, не оставляет сомнений в том, что он должен делать. – user107986

+0

Вы правы, но в разных случаях применяются разные аргументы. Проверьте [исходный код] (https://github.com/angular/angular.js/blob/f13852c179ffd9ec18b7a94df27dec39eb5f19fc/src/Angular.js#L1731) для получения дополнительной информации; вы увидите, что в этом конкретном случае 'fn' является просто именем аргумента. – raina77ow

+0

Я хочу сказать, что этот funciton принимает аргумент «имя» и ничего не делает с ним в своем теле. Тогда в чем смысл этого аргумента? Я должен что-то упустить. – user107986

1

Это просто массив со строкой и функцией.

Нет ничего волшебного или угловатого о самой нотации. Функции могут быть членами массива, как и любой другой тип данных.

Смежные вопросы