web-dev-qa-db-ja.com

AngularJSコントローラーと「use strict」

私は最近JSHintの使用を開始し、「use strict」の関数形式を使用する必要があります。それ以降、AngularJSはエラーをスローします。

「エラー:引数 'webAddressController'は関数ではなく、未定義になりました」

「use strict」の関数形式を削除すると、コントローラーは正常にロードされます。

コントローラー:

(function () {
    "use strict";

    function webAddressController($scope, $rootScope, web_address_service) {
             // Do things
    }

}());

ここで何が起こっているのか、誰にも洞察がありますか?

28
Chris Bier

最初に、pkozlowskiがAngularで彼のものを本当に知っていると述べたいと思いますが、これは実際にはAngularの問題ではなく、クロージャーの問題です。

Angularは2つの場所でコントローラーを探しています。

  1. module.controller()を介して登録されたコントローラの独自のレジストリ内
  2. global変数(またはグローバル関数宣言)

問題は、「use strict」のクロージャー内のすべてがグローバルではないことです。これは、それを含む匿名関数にラップされ、民営化されています。

(function() {
   // nothing in here is global or even public.
   // "use strict" or not.

   "use strict"; // this is mostly irrelevant.

   // this will not work, because it's wrapped and not global
   function ThisDoesntWork($scope) {
   };

   // window is the global root variable. So this works.
   window.ThisWorks = function($scope) {

   };

   // this will work, because it's explicitly registering the controller
   // presuming app is your Module variable from outside of the closure.
   app.controller('ThisIsBest', function($scope) {

   });

})();

//this works because it's global.
function ThisAlsoWorks($scope) {

}

// if you declare a global var, then set it inside
// of your closure, you're good to go too.
var ThisWillWorkToo;

(function {
    //here we're setting it again.
    ThisWillWorkToo = function($scope) {
    };
})();


// if you're really crazy you can even do this...
 var ThisWillWorkButItsWeird = (function() {
      "use strict";

       function ThisWillWorkButItsWeird($scope) {

       }

       return ThisWillWorkButItsWeird;
  })();

一日の終わりには、任意の関数内、または必要に応じてファイルレベルで「use strict」を使用できます。 「厳密な使用」自体は、あなたにとって何も壊しません。ご覧のとおり、コントローラーを登録する方法は千通りあります。おそらく最良の選択は、提案されているように.controllerメソッドでそれらを明示的に登録することです。

44
Ben Lesh

JSHintがここであなたに伝えようとしていることは、グローバル変数を避けることだと思います(明らかに非常に良い方法です!)。

AngularJSは、同じ問題の解決(つまり、グローバル変数の回避)について少し意見が異なり、モジュールでコントローラーを定義できます(グローバルangular名前空間を使用)。次のようなモジュールを使用して例を書き換えることができます。

angular.module('myApp',[]).controller('webAddressController', function($scope) {
    // Do things
});

これが実際にこれを示すjsFiddleです: http://jsfiddle.net/t3vBE/1/

このアプローチを使用すると、コントローラーのコンストラクターでグローバル名前空間を汚染することはありません。

厳格モードを使用する場合は、JSHint構成を変更してangularグローバル変数を許可する必要があります。または、コード全体を(もう一度、モジュールを使用して)ラップして、すぐに実行される関数にすることもできます。

(function () {
    "use strict";

angular.module('myApp',[]).controller('webAddressController', function($scope) {

    $scope.name = 'World';
    // Do things
});

}());​

JsFiddleは次のとおりです。 http://jsfiddle.net/t3vBE/4/

私にとってこれは、純粋なJavaScript、「ヘルパー」関数を定義する場合にのみ意味があります。そうでない場合は、AngularJSサービスに依存します。

14

angularモジュールが既に他の場所にロードされている場合に@pkzolowskiが行うことを行う別の方法:

var app = angular.module('myApp');
app.controller(...);
app.service(...);
...

ここからのコメントに基づいています: angularjsは異なるモジュールの同じモジュールのサービスを定義しています

Angular.module( 'myModule'、[])を使用すると、モジュールmyModuleが作成され、myModuleという名前の既存のモジュールが上書きされることに注意してください。 angular.module( 'myModule')を使用して、既存のモジュールを取得します。

4
zeusstl

あなたは「use strict」を外側と前に書いてみましたか(function()

"use strict"; // <-- add it here
(function () {
    //"use strict"; <-- remove from here

    function webAddressController($scope, $rootScope, web_address_service) {
         // Do things
    }

}());

私の答えは、 Yeoman によって生成されたファイルに基づいています

2
Siddhesh T