This can be done by calling `$scope.$watch(attrs.myBinding)` directly with expression values passed in through element attributes. If necessary `scope: true` can be used create a child scope that inherits from the current scope. This is a good idea if your directive uses it's own controller. However this isn't necessary for most simple directives.
An isolated scope does exactly that, creates a scope for the directive completely isolated from the prototype chain of the containing scope (and thus the application's scope). This is used for complex directives like ng-repeat that need to create and expose their own scopes with the templates that you put inside the repeat blocks.
I know I initially fell into the trap of using isolate scopes to solve this problem. After looking through Angular's own directives for examples I learned other approaches.
I'm not sure exactly what the considered best practices are here (because there is almost no detail on issues like this in the documentation) but at least basing it off how the Angular core team builds their own directives I would suggest avoiding isolate scopes unless scope isolation is specifically necessary.