Потому что должно быть вот так:
<body ng-app="app">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>
<script src="jquery-2.1.4.min.js"></script>
<div ng-controller="MainController"></div>
<script>
var app = angular.module('app', []);
app.service('$myService', function(){
return {hello: 'world'};
});
app.controller('MainController', ['$scope', '$myService', function($scope, $myService){
console.log($myService); // почему $myService undefined?
}]);
</script>
</body>
Конкретно вот эта строчка:
app.controller('MainController', ['$scope', '$myService', function($scope, $myService){
Такой способ записи называется "
inline array annotation". Подробнее про него можно почитать
тут.
Если в кратце:
Angular автоматически определяет объекты которые вы передаете в функцию по их именам.
Т.е, если мы передаем в контроллер $myService, то Angular будет искать directive/factory/filter/etc с таким именем, и подставит его в параметры.
Когда мы используем обфускаторы\минимизаторы JS кода, то имена переменных могут быть измененны в итоговом коде, и Angular не поймет что мы хотим передать в функцию.
Чтобы разрешить эту проблему, разработчики Angular добавили дополнительный синтаксис(array notation).
Мы можем передать вторым параметром массив, в котором указать названия всех необходимых нам объектов, и последним параметром указать функцию, которая принимает ВСЕ эти параметры, в таком же порядке.