javascript - Are variable bound / 1st class functions preferable over private method naming? How is hoisting affected? -
a few questions regarding structuring angular code , behavior of javascript when using variable bound vs private method naming function conventions. there performance or stylistic reason using variable bound functions / first class functions in angularjs on private method naming? how hoisting affected in each method? second method below reduce amount of hoisting performed , have noticeable affect on application performance?
an example of private method naming. recommended way structure angular code?
(function () { 'use strict' function modalcontroller(dataitemsservice, $scope) { var vm = this; function _getselecteditems() { return dataitemsservice.selecteditems(); } function _deleteselecteditems() { dataitemservice.deleteitem(); $("#existconfirmdialog").modal('hide'); } vm.selecteditems = _getselecteditems; vm.deleteitemrecord = _deleteitemrecord; } angular.module('app').controller('modalcontroller', ['dataitemservice', '$scope', modalcontroller] })();
an example of variable bound functions. method of structuring angular code within controller - there disadvantage or advantage in terms of performance/style?
angular.module('appname').controller("namectrl", ["$scope", "$log", "$window", "$http", "$timeout", "someservice", function ($scope, $log, $window, $http, $timeout, tabservice) { //your controller code $scope.tab = 0; $scope.changetab = function(newtab){ $scope.tab = newtab; }; $scope.isactivetab = function(tab){ return $scope.tab === tab; }; } ]);
the first method, using "private" methods , exposing them via public aliases, referred revealing module pattern, although in example methods aren't private.
the latter pretty standard constructor pattern, using $scope context.
is there performance or stylistic reason using
variable
bound functions / first class functions in angularjs on private method naming?is [there] recommended way structure angular code?
tl;dr
fundamentally, there isn't difference between 2 styles above. 1 uses
$scope
, otherthis
. 1 constructor function defined in closure, 1 defined inline.there scenarios may want private method or value. there stylistic , (probably insignificant) performance reasons using variable
this
/vm
on$scope
. these not mutually exclusive.you'll want use basic, bare bones, old school constructor pattern, , lot of people exposing state , behavior via
this
instead of$scope
.you can allow data privacy in controller, of time should leveraged service/factory. main exception data representative of state of view.
don't use jquery in controller, please.
references:
angularjs style guide todd motto.
to answer question thoroughly, think important understand responsibility of controller. every controller's job expose strict set of state , behavior view. put simply, assign this
or $scope
things don't mind user seeing or playing in view.
the variable
in question (vm
, $scope
) context (this
) of instance being created controller function.
$scope
angular's "special" context; has behaviors defined on use (e.g. $scope.$watch). $scopes
follow inheritance chain, i.e. $scope inherits state , behaviors assigned parent $scope.
take these 2 controllers:
angular.module("module") .controller("controller", ["$scope", function($scope) { $scope.tab = 0; $scope.incrementtab = function() { $scope.tab++; }; }]) .controller("othercontroller", ["$scope", function($scope) { // nothing }]);
and view
<div ng-controller="controller"> <p>{{ tab }}</p> <button ng-click="incrementtab();">increment</button> <div ng-controller="othercontroller"> <p>{{ tab }}</p> <button ng-click="incrementtab();">increment</button> </div> </div>
example here
what you'll notice though didn't define $scope.tab
in othercontroller, inherits controller because controller it's parent in dom. in both places tab displayed, should see "0". may "hoisting" you're referring to, although entirely different concept.
what's going happen when click on first button? in both places we've exposed "tab", display "1". both update , increment when press second button.
of course, may not want child tab same tab value parent. if change othercontroller this:
.controller("othercontroller", ["$scope", function($scope) { $scope.tab = 42; }]);
you'll notice behavior has changed - values tab no longer in sync.
but it's confusing: have 2 things called "tab" aren't same. else may write code later down line using "tab" , break code inadvertently.
we used resolve using namespace on $scope
, e.g. $scope.vm
, assign namespace: $scope.vm.tab = 0;
<div ng-controller="othercontroller"> <p>{{ vm.tab }}</p> <button ng-click="vm.incrementtab();">increment</button> </div>
another approach use simplicity , brevity of this
, take advantage of controlleras syntax.
.controller("othercontroller", function() { this.tab = 0; }); <div ng-controller="othercontroller oc"> <p>{{ oc.tab }}</p> </div>
this may more comfortable people used using plain js, , it's easier avoid conflicts other angular sources way. can change namespace on fly. it's bit "lighter" on performance since you're not creating new $scope
instance, i'm not sure there's gain.
in order achieve privacy, recommend encapsulating data in service or factory. remember, controllers aren't singletons; there 1:1 relationship between view , controller , may instantiate same controller more once! factories , service objects are, however, singletons. they're @ storing shared data.
let controllers copy of state singleton, , make sure controllers modifying singleton state using behaviors defined on service/factory.
function modalcontroller(dataitemsservice) { var vm = this; vm.selecteditems = dataitemsservice.selecteditems(); // copy of data vm.updateitem = dataitemservice.updateitem; // update source }
but wait, how know when part of app has changed private data? how know when new copy of selecteditems? $scope.$watch comes play:
function modalcontroller(dataitemsservice, $scope) { var vm = this; vm.updateitem = dataitemservice.updateitem; // update source // periodically check selecteditems , fresh copy. $scope.$watch(dataitemsservice.selecteditems, function(items) { vm.items = items; }); // $scope! }
if data not shared, or if private data representative of view layer , not model layer, it's totally ok keep in controller.
function controller() { var buttonclicked = false; this.click = function() { buttonclicked = true; // user can not lie , didn't. }; }
lastly, not use jquery in controller, reference did!
$("#existconfirmdialog").modal('hide');
this example might not purely evil, avoid accessing , modifying dom outside directive, don't want break other parts of app modifying dom underneath it.