{"id":201832,"date":"2013-11-12T16:56:02","date_gmt":"2013-11-12T12:56:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=201832"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=201832","title":{"rendered":"<span class=\"post_title\">\u0421\u0434\u0435\u043b\u0430\u0439 \u0441\u0432\u043e\u0439 AngularJS: \u0427\u0430\u0441\u0442\u044c 1 \u2014 Scope \u0438 Digest<\/span>"},"content":{"rendered":"<div class=\"content html_format\">       Angular \u2014 \u0437\u0440\u0435\u043b\u044b\u0439 \u0438 \u043c\u043e\u0449\u043d\u044b\u0439 JavaScript-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u041e\u043d \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438 \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435 \u043d\u043e\u0432\u044b\u0445 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0441\u0432\u043e\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0438\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0437\u043d\u0430\u043a\u043e\u043c\u044f\u0441\u044c \u0441 Angular, \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441 \u043e\u0434\u043d\u0438\u043c\u0438 \u0438 \u0442\u0435\u043c\u0438 \u0436\u0435 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u043c\u0438. \u0427\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f digest? \u041a\u0430\u043a\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432? \u0427\u0435\u043c \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0438\u0441 \u043e\u0442 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430?<\/p>\n<p>  \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0443 Angular \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u0430\u044f <a href=\"http:\/\/docs.angularjs.org\/\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a>, \u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0443\u0447\u0430 <a href=\"http:\/\/syntaxspectrum.com\/tag\/angularjs\/\">\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432<\/a>, \u043d\u0435\u0442 \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044e, \u0447\u0435\u043c \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0435\u0435 \u043f\u043e \u043a\u0443\u0441\u043e\u0447\u043a\u0430\u043c \u0438 \u0432\u0441\u043a\u0440\u044b\u0442\u044c \u0435\u0435 \u043c\u0430\u0433\u0438\u044e.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u0432\u043e\u0441\u0441\u043e\u0437\u0434\u0430\u0442\u044c AngularJS \u0441 \u043d\u0443\u043b\u044f. \u041c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e \u0432\u043c\u0435\u0441\u0442\u0435 \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c, \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0447\u0435\u0433\u043e, \u0432\u044b \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0433\u043b\u0443\u0431\u0436\u0435 \u043f\u043e\u0439\u043c\u0435\u0442\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e Angular.<br \/>  <a name=\"habracut\"><\/a><br \/>  \u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 (scope), \u0438 \u0442\u043e, \u043a\u0430\u043a, \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 <b>$eval<\/b>, <b>$digest<\/b> \u0438 <b>$apply<\/b>. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 (dirty-checking) \u0432 Angular \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043c\u0430\u0433\u0438\u0435\u0439, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u2014 \u0432\u044b \u0432\u0441\u0435 \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0441\u0430\u043c\u0438.<\/p>\n<h4>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h4>\n<p>  <a href=\"https:\/\/github.com\/teropa\/schmangular.js\">\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a> \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 github, \u043d\u043e \u044f \u0431\u044b \u043d\u0435 \u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430\u043b \u0432\u0430\u043c \u0438\u0445 \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0431\u0435. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e, \u044f \u043d\u0430\u0441\u0442\u0430\u0438\u0432\u0430\u044e \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0432\u0441\u0435 \u0441\u0430\u043c\u0438, \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c, \u043f\u043e\u0438\u0433\u0440\u0430\u0432\u0448\u0438\u0441\u044c \u0441 \u043a\u043e\u0434\u043e\u043c \u0438 \u043f\u043e\u043a\u043e\u043f\u0430\u0432\u0448\u0438\u0441\u044c \u0432 \u043d\u0435\u043c. \u0412 \u0442\u0435\u043a\u0441\u0442\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e <a href=\"http:\/\/jsbin.com\/\">JS Bin<\/a>, \u0442\u0430\u043a \u0447\u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u0434, \u0434\u0430\u0436\u0435 \u043d\u0435 \u043f\u043e\u043a\u0438\u0434\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 (\u043f\u0440\u0438\u043c. \u043f\u0435\u0440. \u2014 \u0432 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 JSBin \u043a\u043e\u0434).<\/p>\n<p>  \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"http:\/\/lodash.com\/\">Lo-Dash<\/a> \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0441 \u043c\u0430\u0441\u0441\u0438\u0432\u0430\u043c\u0438 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438. \u0421\u0430\u043c Angular \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 Lo-Dash, \u043d\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0443\u0431\u0440\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u043e\u0433\u043e \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u0412\u0435\u0437\u0434\u0435, \u0433\u0434\u0435 \u0432\u044b \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u0435 \u0432 \u043a\u043e\u0434\u0435 (<b>_<\/b>) (\u043d\u0438\u0436\u043d\u0435\u0435 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435) \u2014 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Lo-Dash.<\/p>\n<p>  \u0422\u0430\u043a \u0436\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>console.assert<\/b> \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a. \u041e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0432\u043e \u0432\u0441\u0435\u0445 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 JavaScript-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\u0445.<\/p>\n<p>  \u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 Lo-Dash \u0438 assert \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438:<br \/>  <a href=\"http:\/\/jsbin.com\/UGOVUk\/4\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var a = [1, 2, 3]; var b = [1, 2, 3]; var c = _.map(a, function(i) {   return i * 2; });  console.assert(a !== b); console.assert(_.isEqual(a, b)); console.assert(_.isEqual([2, 4, 6], c)); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u041e\u0431\u044a\u0435\u043a\u0442\u044b \u2014 \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 (scope-\u044b)<\/h4>\n<p>  \u041e\u0431\u044a\u0435\u043a\u0442\u044b \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 Angular \u2014 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0435 JavaScript-\u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u041e\u043d\u0438 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 <b>Scope<\/b>. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0443\u044e \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e:<\/p>\n<pre><code class=\"javascript\">function Scope() { } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <b>new<\/b> \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c scope-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u043d\u0438\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430.<\/p>\n<pre><code class=\"javascript\">var aScope = new Scope(); aScope.firstName = 'Jane'; aScope.lastName = 'Smith'; <\/code><\/pre>\n<p>  \u0412 \u044d\u0442\u0438\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0433\u043e. \u041d\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0442\u0442\u0435\u0440\u043e\u0432 (setters), \u043d\u0435\u0442 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043d\u0430 \u0442\u0438\u043f\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u044f \u043c\u0430\u0433\u0438\u044f \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0432 \u0434\u0432\u0443\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445: <b>$watch<\/b> \u0438 <b>$digest<\/b>.<\/p>\n<h4>\u041d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0437\u0430 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430: $watch \u0438 $digest<\/h4>\n<p>  <b>$watch<\/b> \u0438 <b>$digest <\/b> \u2014 \u0434\u0432\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043e\u0434\u043d\u043e\u0439 \u043c\u0435\u0434\u0430\u043b\u0438. \u0412\u043c\u0435\u0441\u0442\u0435 \u043e\u043d\u0438 \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u044f\u0434\u0440\u043e \u0442\u043e\u0433\u043e, \u0447\u0435\u043c \u0432 Angular \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f scope-\u043e\u0431\u044a\u0435\u043a\u0442\u044b: \u0440\u0435\u0430\u043a\u0446\u0438\u044e \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <b>$watch<\/b> \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 scope \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f\u201d. \u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c \u2014 \u044d\u0442\u043e \u0442\u043e \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0433\u0434\u0430 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c scope \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435. <\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0432 <b>$watch<\/b> \u0434\u0432\u0443\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439:<\/p>\n<ul>\n<li><i>watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f<\/i>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e<\/li>\n<li><i>listener-\u0444\u0443\u043d\u043a\u0446\u0438\u044f<\/i>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/li>\n<\/ul>\n<p>  <\/p>\n<blockquote><p>\u0412 Angular \u0432\u044b \u0432\u043c\u0435\u0441\u0442\u043e watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 watch-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435. \u042d\u0442\u043e \u0441\u0442\u0440\u043e\u043a\u0430 (\u0447\u0442\u043e-\u0442\u043e \u0442\u0438\u043f\u0430 \u00abuser.firstName\u00bb), \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438 \u0432 html \u043f\u0440\u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0438, \u043a\u0430\u043a \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u044b, \u0438\u043b\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u0437 JavaScript. \u042d\u0442\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0430\u0441\u044c \u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043b\u0430\u0441\u044c Angular-\u043e\u043c \u0432, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0443\u044e \u043d\u0430\u0448\u0435\u0439, watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u0412 \u044d\u0442\u043e\u0439 \u0436\u0435 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p><\/blockquote>\n<p>  \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <b>$watch<\/b>, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0433\u0434\u0435-\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u043b\u044f \u043d\u0438\u0445 \u043c\u0430\u0441\u0441\u0438\u0432 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <b>Scope<\/b>:<\/p>\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; } <\/code><\/pre>\n<p>  \u041f\u0440\u0435\u0444\u0438\u043a\u0441 <b>$$<\/b> \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0439 \u0432\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 Angular \u0438 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043a\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$watch<\/b>. \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0434\u0432\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0438\u0445 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 <b>$$watchers<\/b>. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0443\u0436\u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c\u0443 scope-\u043e\u0431\u044a\u0435\u043a\u0442\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0435\u0435 \u0432 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn   };   this.$$watchers.push(watcher); }; <\/code><\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u043e\u0439 \u043c\u0435\u0434\u0430\u043b\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <b>$digest<\/b>. \u041e\u043d\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u0441\u0435\u0445 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u043f\u0438\u0448\u0435\u043c \u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0438, \u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f listener-\u0444\u0443\u043d\u043a\u0446\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$digest = function() {   _.forEach(this.$$watchers, function(watch) {     watch.listenerFn();   });  }; <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c <b>$digest<\/b>, \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0447\u0435\u0433\u043e \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0435\u0433\u043e listener-\u0444\u0443\u043d\u043a\u0446\u0438\u044f:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/oMaQoxa\/2\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn   };   this.$$watchers.push(watcher); };  Scope.prototype.$digest = function() {   _.forEach(this.$$watchers, function(watch) {     watch.listenerFn();   });   };  var scope = new Scope(); scope.$watch(   function() {console.log('watchFn'); },   function() {console.log('listener'); } );  scope.$digest(); scope.$digest(); scope.$digest(); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> &quot;listener&quot; &quot;listener&quot; &quot;listener&quot;<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0421\u0430\u043c\u043e \u043f\u043e \u0441\u0435\u0431\u0435 \u044d\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e. \u0427\u0435\u0433\u043e \u0431\u044b \u043d\u0430\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0442\u0430\u043a \u044d\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0435 \u0432 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p>\n<h4>\u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/h4>\n<p>  \u041a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u043e\u0441\u044c \u0440\u0430\u043d\u044c\u0448\u0435, watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0439 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b. \u041e\u0431\u044b\u0447\u043d\u043e \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 scope, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430, scope \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0435\u0439 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430. Watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u044e\u0449\u0430\u044f \u0437\u0430 <b>firstName<\/b> \u0438\u0437 scope \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"javascript\">function(scope) {   return scope.firstName; } <\/code><\/pre>\n<p>  \u0412 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a: \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 scope \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u0445.<\/p>\n<p>  \u0420\u0430\u0431\u043e\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>$digest<\/b> \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u044d\u0442\u0443 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u043e\u0442 \u043d\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0430 \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437. \u0415\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u2014 \u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u201c\u0433\u0440\u044f\u0437\u043d\u044b\u0435\u201d, \u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e listener-\u0444\u0443\u043d\u043a\u0446\u0438\u044e.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e, <b>$digest<\/b> \u0434\u043e\u043b\u0436\u043d\u0430 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a \u043a\u0430\u043a \u0443 \u043d\u0430\u0441 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043d\u0435\u043c. \u0412\u043e\u0442 \u043d\u043e\u0432\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>$digest<\/b>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$digest = function() {   var self = this;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);     }     watch.last = newValue;   });  }; <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u0439 scope \u043a\u0430\u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442. \u0414\u0430\u043b\u0435\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c, \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u043c \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0435 <b>last<\/b>. \u0415\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u2014 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f listener. \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430, \u0432 listener \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043e\u0431\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 scope. \u0412 \u043a\u043e\u043d\u0446\u0435, \u0432 <b>last<\/b>-\u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437.<\/p>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0432 \u044d\u0442\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f listener-\u044b \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <b>$digest<\/b>:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/OsITIZu\/3\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn   };   this.$$watchers.push(watcher); };  Scope.prototype.$digest = function() {   var self = this;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);     }     watch.last = newValue;   });   };  var scope = new Scope(); scope.firstName = 'Joe'; scope.counter = 0;  scope.$watch(   function(scope) {     return scope.firstName;   },   function(newValue, oldValue, scope) {     scope.counter++;   } );  \/\/ We haven't run $digest yet so counter should be untouched: console.assert(scope.counter === 0);  \/\/ The first digest causes the listener to be run scope.$digest(); console.assert(scope.counter === 1);  \/\/ Further digests don't call the listener... scope.$digest(); scope.$digest(); console.assert(scope.counter === 1);  \/\/ ... until the value that the watch function is watching changes again scope.firstName = 'Jane'; scope.$digest(); console.assert(scope.counter === 2); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true true true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u044f\u0434\u0440\u043e Angular-\u043e\u0432\u0441\u043e\u0433\u043e scope: \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u0438\u0445 \u0432 \u0444\u0443\u043a\u043d\u0446\u0438\u0438 <b>$digest<\/b>.<\/p>\n<p>  \u0422\u0430\u043a \u0436\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0443\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0430\u0440\u0443 \u0432\u044b\u0432\u043e\u0434\u043e\u0432, \u043a\u0430\u0441\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 scope-\u043e\u0432 \u0432 Angular:<\/p>\n<ul>\n<li>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 scope \u0441\u0430\u043c\u043e \u043f\u043e \u0441\u0435\u0431\u0435 \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439, \u0441\u043b\u0435\u0434\u044f\u0449\u0438\u0445 \u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0442\u043e \u0431\u0435\u0437 \u0440\u0430\u0437\u043d\u0438\u0446\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 scope \u0438\u043b\u0438 \u043d\u0435\u0442. Angular \u043d\u0435 \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 scope, \u043e\u043d \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439.<\/li>\n<li>\u041a\u0430\u0436\u0434\u0430\u044f watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b $digest. \u041f\u043e \u044d\u0442\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0443\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0442\u043e\u043c\u0443, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443 \u0432\u0430\u0441 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0430\u043c\u043e\u0439 \u043f\u043e \u0441\u0435\u0431\u0435.<\/li>\n<\/ul>\n<p>  <\/p>\n<h4>\u041e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 digest<\/h4>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f, \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f <b>$digest<\/b>, \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u0435\u043c \u0444\u0430\u043a\u0442\u043e\u043c, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u0430\u044f watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u044b $digest, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f. \u041d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0431\u0435\u0437 listener.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0443\u0447\u0435\u0441\u0442\u044c \u044d\u0442\u043e, \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>$watch<\/b> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u043d\u0435 \u043f\u0440\u043e\u043f\u0443\u0449\u0435\u043d \u043b\u0438 listener, \u0438 \u0435\u0441\u043b\u0438 \u0434\u0430 \u2014 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0443:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() { }   };   this.$$watchers.push(watcher); }; <\/code><\/pre>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u044d\u0442\u043e\u0442 \u0448\u0430\u0431\u043b\u043e\u043d, \u0438\u043c\u0435\u0439\u0442\u0435 \u0432\u0432\u0438\u0434\u0443, Angular \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0435 \u0438\u0437 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 listener-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0430. \u0415\u0441\u043b\u0438 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u043b\u0438\u0431\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439 \u043b\u0438\u0448\u043d\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u2014 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0439\u0442\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f <b>undefined<\/b>:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/OsITIZu\/4\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() { }   };   this.$$watchers.push(watcher); };  Scope.prototype.$digest = function() {   var self = this;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);     }     watch.last = newValue;   });   };  var scope = new Scope();  scope.$watch(function() {   console.log('digest listener fired'); });  scope.$digest(); scope.$digest(); scope.$digest(); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> &quot;digest listener fired&quot; &quot;digest listener fired&quot; &quot;digest listener fired&quot;<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u042f\u0434\u0440\u043e \u0433\u043e\u0442\u043e\u0432\u043e, \u043d\u043e \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0435\u0449\u0435 \u0434\u0430\u043b\u0435\u043a\u043e. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0435 \u0443\u0447\u0442\u0435\u043d \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439: listener-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0430\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0438\u0437 scope. \u0415\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0435 \u0441\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u0430 \u0437\u0430 \u044d\u0442\u0438\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u0441\u043b\u0435\u0434\u0438\u043b \u0434\u0440\u0443\u0433\u043e\u0439 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c, \u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438, \u043f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435 \u0432 \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0445\u043e\u0434 <b>$digest<\/b>:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/eTIpUyE\/2\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() {}   };   this.$$watchers.push(watcher); };  Scope.prototype.$digest = function() {   var self = this;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);     }     watch.last = newValue;   });   };  var scope = new Scope(); scope.firstName = 'Joe'; scope.counter = 0;  scope.$watch(   function(scope) {     return scope.counter;   },   function(newValue, oldValue, scope) {     scope.counterIsTwo = (newValue === 2);   } );  scope.$watch(   function(scope) {     return scope.firstName;   },   function(newValue, oldValue, scope) {     scope.counter++;   } );  \/\/ After the first digest the counter is 1 scope.$digest(); console.assert(scope.counter === 1);  \/\/ On the next change the counter becomes two, but our other watch hasn't noticed this yet scope.firstName = 'Jane'; scope.$digest(); console.assert(scope.counter === 2); console.assert(scope.counterIsTwo); \/\/ false  \/\/ Only sometime in the future, when $digest() is called again, does our other watch get run scope.$digest(); console.assert(scope.counterIsTwo); \/\/ true <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true false true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u043c \u044d\u0442\u043e.<\/p>\n<h4>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c $digest \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0435\u0441\u0442\u044c \u201c\u0433\u0440\u044f\u0437\u043d\u044b\u0435\u201d \u0434\u0430\u043d\u043d\u044b\u0435<\/h4>\n<p>  \u041d\u0443\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c <b>$digest<\/b> \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u043b \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0443\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f.<\/p>\n<p>  \u0421\u043d\u0430\u0447\u0430\u043b\u0430, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e $digest \u0432 <b>$$digestOnce<\/b>, \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0435\u0435 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430, \u043f\u0440\u043e\u0431\u0435\u0433\u0430\u044f \u0432\u0441\u0435 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0430 \u0431\u0443\u043b\u0435\u0432\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e, \u0441\u043e\u043e\u0431\u0449\u0430\u044e\u0449\u0443\u044e \u0431\u044b\u043b\u043e \u043b\u0438 \u0445\u043e\u0442\u044c \u043e\u0434\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0438\u043b\u0438 \u043d\u0435\u0442:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = newValue;   });   return dirty; }; <\/code><\/pre>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e, \u0437\u0430\u043d\u043e\u0432\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$digest<\/b>, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u0432 \u0446\u0438\u043a\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0430 <b>$$digestOnce<\/b> \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440 \u043f\u043e\u043a\u0430 \u0435\u0441\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$digest = function() {   var dirty;   do {     dirty = this.$$digestOnce();   } while (dirty); }; <\/code><\/pre>\n<p>  <b>$digest<\/b> \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435 \u043e\u0434\u0438\u043d \u0440\u0430\u0437. \u0415\u0441\u043b\u0438 \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u0440\u043e\u0445\u043e\u0434\u0435, \u043a\u0430\u043a\u043e\u0435-\u043b\u0438\u0431\u043e \u0438\u0437 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c, \u043f\u0440\u043e\u0445\u043e\u0434 \u043f\u043e\u043c\u0435\u0447\u0430\u0435\u0442\u0441\u044f, \u043a\u0430\u043a \u00ab\u0433\u0440\u044f\u0437\u043d\u044b\u0439\u00bb, \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0445\u043e\u0434. \u0422\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0437\u0430 \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0445\u043e\u0434 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f.  <\/p>\n<blockquote><p>\u0423 scope-\u043e\u0432 \u0432 Angular, \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u043d\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 $$digestOnce. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0442\u0430\u043c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u044f \u0432 \u0446\u0438\u043a\u043b \u043f\u0440\u044f\u043c\u043e \u0432 $digest. \u0414\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u044f\u0441\u043d\u043e\u0441\u0442\u044c \u0438 \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u0430\u0436\u043d\u0435\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433.<\/p><\/blockquote>\n<p>  \u0412\u043e\u0442 \u043d\u043e\u0432\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/Imoyosa\/3\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn ||function() { }   };   this.$$watchers.push(watcher); };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = newValue;   });   return dirty; };  Scope.prototype.$digest = function() {   var dirty;   do {     dirty = this.$$digestOnce();   } while (dirty); };  var scope = new Scope(); scope.firstName = 'Joe'; scope.counter = 0;  scope.$watch(   function(scope) {     return scope.counter;   },   function(newValue, oldValue, scope) {     scope.counterIsTwo = (newValue === 2);   } );  scope.$watch(   function(scope) {     return scope.firstName;   },   function(newValue, oldValue, scope) {     scope.counter++;   } );  \/\/ After the first digest the counter is 1 scope.$digest(); console.assert(scope.counter === 1);  \/\/ On the next change the counter becomes two, and the other watch listener is also run because of the dirty check scope.firstName = 'Jane'; scope.$digest(); console.assert(scope.counter === 2); console.assert(scope.counterIsTwo);  <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0432\u0430\u0436\u043d\u044b\u0439 \u0432\u044b\u0432\u043e\u0434, \u043a\u0430\u0441\u0430\u044e\u0449\u0438\u0439\u0441\u044f watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0439: \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u043e\u0442\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u044b $digest. \u0412\u043e\u0442 \u043f\u043e\u0447\u0435\u043c\u0443, \u0447\u0430\u0441\u0442\u043e \u0433\u043e\u0432\u043e\u0440\u044f\u0442, \u0447\u0442\u043e watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0438\u0434\u0435\u043c\u043f\u043e\u0442\u0435\u043d\u0442\u043d\u044b\u043c\u0438: \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432, \u043b\u0438\u0431\u043e \u0442\u0430\u043c \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437. \u0415\u0441\u043b\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0435\u0441\u0442\u044c AJAX-\u0437\u0430\u043f\u0440\u043e\u0441, \u043d\u0435\u0442 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0439 \u043d\u0430 \u0442\u043e, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u044d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f.<\/p>\n<p>  \u0412 \u043d\u0430\u0448\u0435\u0439 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438\u0437\u044a\u044f\u043d: \u0447\u0442\u043e \u0441\u043b\u0443\u0447\u0438\u0442\u0441\u044c\u044f, \u0435\u0441\u043b\u0438 \u0434\u0432\u0430 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f \u0431\u0443\u0434\u0443\u0442 \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430? \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f? \u041f\u043e\u0434\u043e\u0431\u043d\u0430\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0432 \u043a\u043e\u0434\u0435 \u043d\u0438\u0436\u0435. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0437\u043e\u0432 <b>$digest<\/b> \u0437\u0430\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d. <\/p>\n<p>  \u0420\u0430\u0441\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0435\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e \u0441\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/eKEvOYa\/3\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() { }   };   this.$$watchers.push(watcher); };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = newValue;   });   return dirty; };  Scope.prototype.$digest = function() {   var dirty;   do {     dirty = this.$$digestOnce();   } while (dirty); };  var scope = new Scope(); scope.counter1 = 0; scope.counter2 = 0;  scope.$watch(   function(scope) {     return scope.counter1;   },   function(newValue, oldValue, scope) {     scope.counter2++;   } );  scope.$watch(   function(scope) {     return scope.counter2;   },   function(newValue, oldValue, scope) {     scope.counter1++;   } );  \/\/ Uncomment this to run the digest \/\/ scope.$digest();  console.log(scope.counter1); \u041a\u043e\u043d\u0441\u043e\u043b\u044c: &lt;pre&gt; 0&lt;\/pre&gt; &lt;\/spoiler&gt; JSBin \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f (\u043d\u0430 \u043c\u043e\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u043a\u043e\u043b\u043e 100000 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439). \u0415\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u0434 node.js, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432\u0435\u0447\u043d\u043e.   &lt;h4&gt;\u0418\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u043c\u0441\u044f \u043e\u0442 \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432 $digest&lt;\/h4&gt; \u0412\u0441\u0435 \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u0442\u0430\u043a \u044d\u0442\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 &lt;b&gt;$digest&lt;\/b&gt; \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439. \u0415\u0441\u043b\u0438 scope \u0432\u0441\u0435-\u0435\u0449\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439, \u043c\u044b \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c \u0440\u0443\u043a\u0438 \u0438 \u0441\u0434\u0430\u0435\u043c\u0441\u044f - \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u044f\u0432\u043d\u043e \u043d\u0435 \u0442\u0430\u043a\u043e\u0435, \u043a\u0430\u043a\u0438\u043c \u0435\u0433\u043e \u043e\u0436\u0438\u0434\u0430\u043b \u0432\u0438\u0434\u0435\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c.  \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f TTL (\u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043e\u0442 time to live - \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438). \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0435\u0433\u043e \u0440\u0430\u0432\u043d\u044b\u043c 10. \u042d\u0442\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c (\u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438 digest \u043e\u043a\u043e\u043b\u043e 100000 \u0440\u0430\u0437), \u043d\u043e \u0443\u0447\u0442\u0438\u0442\u0435, \u044d\u0442\u043e \u0443\u0436\u0435 \u0432\u043e\u043f\u0440\u043e\u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 - digest \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u043e, \u0438 \u0432 \u043d\u0435\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043e\u0442\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u0432\u0441\u0435 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043c\u0430\u043b\u043e\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u044b\u043c, \u0447\u0442\u043e \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0431\u0443\u0434\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 10 \u0432\u044b\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u0439. &lt;blockquote&gt;\u0412 Angular TTL \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c. \u041c\u044b \u0435\u0449\u0435 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u044d\u0442\u043e\u043c\u0443 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.&lt;\/blockquote&gt; \u041d\u0443 \u043b\u0430\u0434\u043d\u043e, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c - \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0432 digest-\u0446\u0438\u043a\u043b. \u0415\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0438 TTL - \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:  &lt;source lang=&quot;javascript&quot;&gt; Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   do {     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty); }; <\/code><\/pre>\n<p>  \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/uNapUWe\/2\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() { }   };   this.$$watchers.push(watcher); };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (newValue !== oldValue) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = newValue;   });   return dirty; };  Scope.prototype.$digest = function(){   var ttl = 10;   var dirty;   do {     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty); };  var scope = new Scope(); scope.counter1 = 0; scope.counter2 = 0;  scope.$watch(   function(scope) {     return scope.counter1;   },   function(newValue, oldValue, scope) {     scope.counter2++;   } );  scope.$watch(   function(scope) {     return scope.counter2;   },   function(newValue, oldValue, scope) {     scope.counter1++;   } );  scope.$digest(); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> &quot;Uncaught 10 digest iterations reached (line 36)&quot;<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041e\u0442 \u0437\u0430\u0446\u0438\u043a\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432 digest \u0438\u0437\u0431\u0430\u0432\u0438\u043b\u0438\u0441\u044c.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u043e, <i>\u043a\u0430\u043a<\/i> \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c, \u0447\u0442\u043e \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c.<\/p>\n<h4>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e<\/h4>\n<p>  \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043c\u044b \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u043e \u0441\u0442\u0430\u0440\u044b\u043c\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0441\u0442\u0440\u043e\u0433\u043e\u0433\u043e \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u0430 <b>===<\/b>. \u0412 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442: \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 (\u0447\u0438\u0441\u043b\u0430, \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u0442.\u0434.), \u0442\u0430\u043a \u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0435\u0441\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u043b\u0438 \u043c\u0430\u0441\u0441\u0438\u0432 \u0437\u0430\u043c\u0435\u043d\u0435\u043d \u0434\u0440\u0443\u0433\u0438\u043c. \u041d\u043e \u0432 Angular \u0435\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u043e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0437\u043d\u0430\u0442\u044c \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c \u043b\u0438 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c<i> \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e<\/i>, \u0430 \u043d\u0435 <i>\u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435<\/i>.<\/p>\n<p>  \u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$watch<\/b> \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0442\u0440\u0435\u0442\u0438\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0431\u0443\u043b\u0435\u0432\u043e\u0433\u043e \u0442\u0438\u043f\u0430. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0444\u043b\u0430\u0433 \u0440\u0430\u0432\u0435\u043d true \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c <b>$watch<\/b> \u2014 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0444\u043b\u0430\u0433 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435 (\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <b>watcher<\/b>):<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn,     valueEq: !!valueEq   };   this.$$watchers.push(watcher); }; <\/code><\/pre>\n<p>  \u0412\u0441\u0435 \u0447\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438, \u044d\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044e \u0444\u043b\u0430\u0433, \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u044f \u0435\u0433\u043e \u043a \u0431\u0443\u043b\u0435\u0432\u0443 \u0442\u0438\u043f\u0443, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0432\u0448\u0438\u0441\u044c \u0434\u0432\u043e\u0439\u043d\u044b\u043c \u043e\u0442\u0440\u0438\u0446\u0430\u043d\u0438\u0435\u043c. \u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u044b\u0437\u043e\u0432\u0435\u0442 <b>$watch<\/b> \u0431\u0435\u0437 \u0442\u0440\u0435\u0442\u044c\u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430, <b>valueEq<\/b> \u0431\u0443\u0434\u0435\u0442 <b>undefined<\/b>, \u0447\u0442\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 <b>false<\/b> \u0432 watcher-\u043e\u0431\u044a\u0435\u043a\u0442\u0435.<\/p>\n<p>  \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0438\u043b\u0438 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u043c, \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0431\u0435\u0433\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043f\u043e \u0441\u0442\u0430\u0440\u043e\u043c\u0443, \u0442\u0430\u043a \u0438 \u043f\u043e \u043d\u043e\u0432\u043e\u043c\u0443 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443. \u0415\u0441\u043b\u0438 \u043d\u0430\u0439\u0434\u0443\u0442\u0441\u044f \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u043e\u0442\u043b\u0438\u0447\u0438\u044f, \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043c\u0435\u0447\u0430\u0435\u0442\u0441\u044f, \u043a\u0430\u043a \u201c\u0433\u0440\u044f\u0437\u043d\u044b\u0439\u201d. \u0412 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c\u0441\u044f \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438\u043b\u0438 \u043c\u0430\u0441\u0441\u0438\u0432\u044b, \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0445 \u0442\u043e\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e.<\/p>\n<p>  \u0412 Angular \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u044f <a href=\"https:\/\/github.com\/angular\/angular.js\/blob\/8d4e3fdd31eabadd87db38aa0590253e14791956\/src\/Angular.js#L812\">\u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e<\/a>, \u043d\u043e \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0442\u043e\u0439, \u0447\u0442\u043e <a href=\"http:\/\/lodash.com\/docs#isEqual\">\u0435\u0441\u0442\u044c \u0432 Lo-Dash<\/a>. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0443\u044e \u043f\u0430\u0440\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438 \u0444\u043b\u0430\u0433:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue;   } }; <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u201c\u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e\u201d, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u201c\u0441\u0442\u0430\u0440\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u201d. \u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0442\u0430\u043a-\u043a\u0430\u043a \u043b\u044e\u0431\u044b\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u043f\u0430\u0434\u0443\u0442 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0438 \u0432 \u0445\u0440\u0430\u043d\u0438\u043c\u044b\u0439 \u043d\u0430\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442. \u041c\u044b \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u043e\u0441\u044c \u0447\u0442\u043e-\u0442\u043e \u0438\u043b\u0438 \u043d\u0435\u0442 \u0435\u0441\u043b\u0438 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$$areEqual<\/b> \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043f\u0430\u0434\u0430\u0442\u044c \u0434\u0432\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043e\u0434\u043d\u0438 \u0438 \u0442\u0435-\u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e, \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u044d\u0442\u0443 \u043a\u043e\u043f\u0438\u044e.<\/p>\n<p>  \u0422\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f, \u0432 Angular \u0435\u0441\u0442\u044c <a href=\"https:\/\/github.com\/angular\/angular.js\/blob\/8d4e3fdd31eabadd87db38aa0590253e14791956\/src\/Angular.js#L725\">\u0441\u0432\u043e\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/a>, \u043d\u043e \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f <a href=\"http:\/\/lodash.com\/docs#cloneDeep\">\u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0439 \u0438\u0437 Lo-Dash<\/a>. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c <b>$$digestOnce<\/b>, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430 <b>$$areEqual<\/b> \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0438 \u0434\u0435\u043b\u0430\u043b\u0430 \u043a\u043e\u043f\u0438\u044e \u0432 <b>last<\/b> \u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);   });   return dirty; }; <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/ARiWENO\/3\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() { },     valueEq: !!valueEq   };   this.$$watchers.push(watcher); };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue;   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);   });   return dirty; };  Scope.prototype.$digest = function(){   var ttl = 10;   var dirty;   do {     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty); };  var scope = new Scope(); scope.counterByRef = 0; scope.counterByValue = 0; scope.value = [1, 2, {three: [4, 5]}];  \/\/ Set up two watches for value. One checks references, the other by value. scope.$watch(   function(scope) {     return scope.value;   },   function(newValue, oldValue, scope) {     scope.counterByRef++;   } ); scope.$watch(   function(scope) {     return scope.value;   },   function(newValue, oldValue, scope) {     scope.counterByValue++;   },   true );   scope.$digest(); console.assert(scope.counterByRef === 1); console.assert(scope.counterByValue === 1);  \/\/ When changes are made within the value, the by-reference watcher does not notice, but the by-value watcher does. scope.value[2].three.push(6); scope.$digest(); console.assert(scope.counterByRef === 1); console.assert(scope.counterByValue === 2);  \/\/ Both watches notice when the reference changes. scope.value = {aNew: &quot;value&quot;}; scope.$digest(); console.assert(scope.counterByRef === 2); console.assert(scope.counterByValue === 3);  delete scope.value; scope.$digest(); console.assert(scope.counterByRef === 3); console.assert(scope.counterByValue === 4); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true true true true true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e, \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0431\u043e\u043b\u0435\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u0430 \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c, \u0447\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435. \u041f\u0435\u0440\u0435\u0431\u043e\u0440 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043f\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0441\u0445\u043e\u0434 \u043f\u0430\u043c\u044f\u0442\u0438. \u0412\u043e\u0442 \u043f\u043e\u0447\u0435\u043c\u0443 \u0432 Angular \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0412\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0444\u043b\u0430\u0433.  <\/p>\n<blockquote><p>\u0412 Angular \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u0438 \u0442\u0440\u0435\u0442\u0438\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435: \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0437\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438\u201d. \u0422\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c, \u043e\u043d \u0432\u044b\u044f\u0432\u043b\u044f\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432, \u043d\u043e \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 \u043d\u0435\u0433\u043e, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0431\u0435\u0437 \u0443\u0433\u043b\u0443\u0431\u043b\u0435\u043d\u0438\u044f \u0432\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0443\u0440\u043e\u0432\u043d\u0438. \u042d\u0442\u043e \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435. \u041d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0437\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 $watchCollection \u2014 \u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u0441\u0435\u0440\u0438\u0438.<\/p><\/blockquote>\n<p>  \u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0441\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0447\u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0443 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c JavaScript.<\/p>\n<h4>\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u044f NaN<\/h4>\n<p>  \u0412 \u044f\u0437\u044b\u043a\u0435 JavaScript \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <b>NaN<\/b> (not a number \u2014 \u043d\u0435 \u0447\u0438\u0441\u043b\u043e) \u043d\u0435 \u0440\u0430\u0432\u043d\u043e \u0441\u0430\u043c\u043e\u043c\u0443 \u0441\u0435\u0431\u0435. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0432\u0443\u0447\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u043d\u043e, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0430\u043a \u043e\u043d\u043e \u0438 \u0435\u0441\u0442\u044c. \u041c\u044b \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043b\u0438 <b>NaN<\/b> \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432 \u043d\u0430\u0448\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u044e\u0449\u0430\u044f \u0437\u0430 <b>NaN<\/b> \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043c\u0435\u0447\u0430\u0442\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c, \u043a\u0430\u043a \u201c\u0433\u0440\u044f\u0437\u043d\u044b\u0439\u201d.<\/p>\n<p>  \u0412 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u201c\u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e\u201d \u044d\u0442\u043e\u0442 \u0441\u043b\u0443\u0447\u0430\u0439 \u0443\u0436\u0435 \u0443\u0447\u0442\u0435\u043d \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>isEqual<\/b> \u0438\u0437 Lo-Dash. \u0412 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u201c\u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435\u201d \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0441\u0430\u043c\u0438\u043c. \u0427\u0442\u043e \u0436\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$$areEqual<\/b>:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/ijINaRA\/2\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">&lt;source lang=&quot;javascript&quot;&gt; Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } }; <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0438 \u0441 <b>NaN<\/b> \u0432\u0435\u0434\u0443\u0442 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u043e:<\/p>\n<p>  function Scope() {<br \/>   this.$$watchers = [];<br \/>  }<\/p>\n<p>  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {<br \/>   var watcher = {<br \/>   watchFn: watchFn,<br \/>   listenerFn: listenerFn || function() {},<br \/>   valueEq: !!valueEq<br \/>   };<br \/>   this.$$watchers.push(watcher);<br \/>  };<\/p>\n<p>  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {<br \/>   if (valueEq) {<br \/>   return _.isEqual(newValue, oldValue);<br \/>   } else {<br \/>   return newValue === oldValue ||<br \/>   (typeof newValue === &#8216;number&#8217; &#038;&#038; typeof oldValue === &#8216;number&#8217; &#038;&#038;<br \/>   isNaN(newValue) &#038;&#038; isNaN(oldValue));<br \/>   }<br \/>  };<\/p>\n<p>  Scope.prototype.$$digestOnce = function() {<br \/>   var self = this;<br \/>   var dirty;<br \/>   _.forEach(this.$$watchers, function(watch) {<br \/>   var newValue = watch.watchFn(self);<br \/>   var oldValue = watch.last;<br \/>   if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {<br \/>   watch.listenerFn(newValue, oldValue, self);<br \/>   dirty = true;<br \/>   }<br \/>   watch.last = (watch.valueEq? _.cloneDeep(newValue): newValue);<br \/>   });<br \/>   return dirty;<br \/>  };<\/p>\n<p>  Scope.prototype.$digest = function(){<br \/>   var ttl = 10;<br \/>   var dirty;<br \/>   do {<br \/>   dirty = this.$$digestOnce();<br \/>   if (dirty &#038;&#038; !(ttl&#8212;)) {<br \/>   throw \u00ab10 digest iterations reached\u00bb;<br \/>   }<br \/>   } while (dirty);<br \/>  };<\/p>\n<p>  var scope = new Scope();<br \/>  scope.number = 0;<br \/>  scope.counter = 0;<\/p>\n<p>  scope.$watch(<br \/>   function(scope) {<br \/>   return scope.number;<br \/>   },<br \/>   function(newValue, oldValue, scope) {<br \/>   scope.counter++;<br \/>   }<br \/>  );<\/p>\n<p>  scope.$digest();<br \/>  console.assert(scope.counter === 1);<\/p>\n<p>  scope.number = parseInt(&#8216;wat&#8217;, 10); \/\/ Becomes NaN<br \/>  scope.$digest();<br \/>  console.assert(scope.counter === 2);  <\/div>\n<\/div>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043c\u0435\u0441\u0442\u0438\u043c \u0444\u043e\u043a\u0443\u0441 \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441\u043e scope \u0438\u0437 \u043a\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<h4>$eval \u2014 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 scope<\/h4>\n<p>  \u0412 Angular \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043a\u043e\u0434\u0430 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 scope. \u041f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0439 \u0438\u0437 \u043d\u0438\u0445 \u2014 \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f <b>$eval<\/b>. \u041e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430, \u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u2014 \u044d\u0442\u043e \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0435\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u044f \u0435\u0439 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 scope, \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440. \u041d\u0443 \u0430 \u043f\u043e\u0442\u043e\u043c \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. <b>$eval<\/b> \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043d\u0430 \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0432 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e.<\/p>\n<p>  \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <b>$eval<\/b> \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u0430\u044f:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); }; <\/code><\/pre>\n<p>  \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <b>$eval<\/b> \u0442\u0430\u043a \u0436\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/UzaWUC\/1\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() {},     valueEq: !!valueEq   };   this.$$watchers.push(watcher); };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);   });   return dirty; };  Scope.prototype.$digest = function(){   var ttl = 10;   var dirty;   do {     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty); };  Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); };  var scope = new Scope(); scope.number = 1;  scope.$eval(function(theScope) {   console.log('Number during $eval:', theScope.number); }); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> &quot;Number during $eval:&quot; 1<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0430\u043a \u0432 \u0447\u0435\u043c \u0436\u0435 \u043f\u043e\u043b\u044c\u0437\u0430 \u043e\u0442 \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u044b\u0447\u0443\u0440\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438? \u041e\u0434\u043d\u043e \u0438\u0437 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e <b>$eval<\/b> \u0434\u0435\u043b\u0430\u0435\u0442 \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u043c \u043a\u043e\u0434, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c scope. \u0422\u0430\u043a \u0436\u0435 <b>$eval<\/b> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0441\u0442\u0430\u0432\u043d\u044b\u043c \u0431\u043b\u043e\u043a\u043e\u043c \u0434\u043b\u044f <b>$apply<\/b>, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u0432\u0441\u043a\u043e\u0440\u0435 \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f.<\/p>\n<p>  \u041e\u0434\u043d\u0430\u043a\u043e, \u0441\u0430\u043c\u0430\u044f \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u043f\u043e\u043b\u044c\u0437\u0430 \u043e\u0442 <b>$eval<\/b> \u043f\u0440\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u201c\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439\u201d \u0432\u043c\u0435\u0441\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u0422\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 <b>$watch<\/b>, \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$eval<\/b> \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435. \u041e\u043d\u0430 \u0435\u0433\u043e \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 scope. \u0414\u0430\u043b\u044c\u0448\u0435 \u0432 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u044d\u0442\u043e.<\/p>\n<h4>$apply \u2014 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u0441 \u0446\u0438\u043a\u043b\u043e\u043c $digest<\/h4>\n<p>  \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e, <b>$apply<\/b> \u0441\u0430\u043c\u0430\u044f \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u0438\u0437 \u0432\u0441\u0435\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 <b>Scope<\/b>. \u041e\u043d\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u043a\u0430\u043a \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a c Angular. \u0418 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u044b.<\/p>\n<p>  $apply \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043a\u0430\u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <b>$eval<\/b>, \u043d\u0443 \u0430 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <b>$digest<\/b>. \u0412\u043e\u0442 \u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$apply = function(expr) {   try {     return this.$eval(expr);   } finally {     this.$digest();   } }; <\/code><\/pre>\n<p>  <b>$digest<\/b> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0431\u043b\u043e\u043a\u0435 <b>finally<\/b> \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u0418\u0434\u0435\u044f \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <b>$apply<\/b>, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u0434, \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u0441 Angular. \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 scope, \u0430 <b>$apply<\/b> \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u0438\u0442\u0441\u044f \u043e \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0438 \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u0438\u043b\u0438 \u044d\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0438 \u0438 \u0438\u043c\u0435\u044e\u0442 \u0432\u0432\u0438\u0434\u0443, \u043a\u043e\u0433\u0434\u0430 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u043e\u0431 \u00ab\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430 \u0432 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b Angular\u00bb. \u042d\u0442\u043e \u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435.<\/p>\n<p>  <b>$apply<\/b> \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/UzaWUC\/2\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = []; }  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() {},     valueEq: !!valueEq   };   this.$$watchers.push(watcher); };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);   });   return dirty; };  Scope.prototype.$digest = function(){   var ttl = 10;   var dirty;   do {     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty); };  Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); };  Scope.prototype.$apply = function(expr) {   try {     return this.$eval(expr);   } finally {     this.$digest();   } };  var scope = new Scope(); scope.counter = 0;  scope.$watch(   function(scope) {     return scope.aValue;   },   function(newValue, oldValue, scope) {     scope.counter++;   } );  scope.$apply(function(scope) {   scope.aValue = 'Hello from &quot;outside&quot;'; }); console.assert(scope.counter === 1); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true<\/pre>\n<p>  <\/div>\n<\/div>\n<h4>\u041e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u2014 $evalAsync<\/h4>\n<p>  \u0412 JavaScript \u0447\u0430\u0441\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0443\u0447\u0430\u0441\u0442\u043e\u043a \u043a\u043e\u0434\u0430 \u00ab\u043f\u043e\u0437\u0436\u0435\u00bb \u2014 \u0442\u043e \u0435\u0441\u0442\u044c \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043e \u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0433\u0434\u0430 \u0432\u0435\u0441\u044c \u043a\u043e\u0434 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d. \u041e\u0431\u044b\u0447\u043d\u043e \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u044e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <b>SetTimeout()<\/b> \u0441 \u043d\u0443\u043b\u0435\u0432\u043e\u0439 (\u0438\u043b\u0438 \u0431\u043b\u0438\u0437\u043a\u043e\u0439 \u043a \u043d\u0443\u043b\u044e) \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439.<\/p>\n<p>  \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u0438\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0432 Angular \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u0445\u043e\u0442\u044f \u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u0435\u0435 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"http:\/\/docs.angularjs.org\/api\/ng.$timeout\">\u0441\u0435\u0440\u0432\u0438\u0441<\/a> <b>$timeout<\/b>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0440\u043e\u043c\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0447\u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442 \u0432\u044b\u0437\u043e\u0432 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441 digest-\u0446\u0438\u043a\u043b\u043e\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <b>$apply<\/b>.<\/p>\n<p>  \u041d\u043e \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0432 Angular \u2014 \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f <b>$evalAsync<\/b>. \u041e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0437\u0436\u0435, \u043d\u043e \u043b\u0438\u0431\u043e \u043f\u0440\u044f\u043c \u0432\u043d\u0443\u0442\u0440\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0446\u0438\u043a\u043b\u0430 digest (\u0435\u0441\u043b\u0438 \u043e\u043d \u0441\u0435\u0439\u0447\u0430\u0441 \u043e\u0442\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442), \u043b\u0438\u0431\u043e \u0436\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c digest-\u0446\u0438\u043a\u043b\u043e\u043c. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u043a\u043e\u0434\u0430 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u0437 listener-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f, \u0437\u043d\u0430\u044f, \u0447\u0442\u043e, \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043a\u043e\u0434 \u043e\u0442\u043b\u043e\u0436\u0435\u043d, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 digest-\u0446\u0438\u043a\u043b\u0430.<\/p>\n<p>  \u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0442\u0435\u043c, \u0433\u0434\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438, \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 <b>$$evalAsync<\/b>. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0432 \u0435\u0433\u043e \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 <b>Scope<\/b>:<\/p>\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = []; } <\/code><\/pre>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u0430\u043c\u0443 <b>$evalAsync<\/b>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$evalAsync = function(expr) {   this.$$asyncQueue.push({scope: this, expression: expr}); }; <\/code><\/pre>\n<p>  <\/p>\n<blockquote><p>\u041f\u0440\u0438\u0447\u0438\u043d\u0430 \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u044f\u0432\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c scope \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 (scope-\u043e\u0432), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0435\u0440\u0438\u0438.<\/p><\/blockquote>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0432 <b>$digest<\/b>, \u044d\u0442\u043e \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0435\u0441\u0442\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430, \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u0445, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <b>$eval<\/b>:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   do {     while (this.$$asyncQueue.length) {       var asyncTask = this.$$asyncQueue.shift();       this.$eval(asyncTask.expression);     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty); }; <\/code><\/pre>\n<p>  \u042d\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u043e\u0442\u043b\u043e\u0436\u0438\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0430 scope \u0431\u044b\u043b \u043f\u043e\u043c\u0435\u0447\u0435\u043d, \u043a\u0430\u043a \u201c\u0433\u0440\u044f\u0437\u043d\u044b\u0439\u201d \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u0430 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043e, \u043d\u043e \u0432 \u0442\u043e\u043c \u0436\u0435 digest-\u0446\u0438\u043a\u043b\u0435.<\/p>\n<p>  \u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a <b>$evalAsync<\/b> \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/ilepOwI\/1\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = []; }  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() {},     valueEq: !!valueEq   };   this.$$watchers.push(watcher); };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);   });   return dirty; };  Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   do {     while (this.$$asyncQueue.length) {       var asyncTask = this.$$asyncQueue.shift();       this.$eval(asyncTask.expression);     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty); };  Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); };  Scope.prototype.$apply = function(expr) {   try {     return this.$eval(expr);   } finally {     this.$digest();   } };  Scope.prototype.$evalAsync = function(expr) {   this.$$asyncQueue.push({scope: this, expression: expr}); };  var scope = new Scope(); scope.asyncEvaled = false;  scope.$watch(   function(scope) {     return scope.aValue;   },   function(newValue, oldValue, scope) {     scope.counter++;     scope.$evalAsync(function(scope) {       scope.asyncEvaled = true;     });     console.log(&quot;Evaled inside listener: &quot;+scope.asyncEvaled);   } );  scope.aValue = &quot;test&quot;; scope.$digest(); console.log(&quot;Evaled after digest: &quot;+scope.asyncEvaled); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> &quot;Evaled inside listener: false&quot; &quot;Evaled after digest: true&quot;<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u0424\u0430\u0437\u044b \u0432 scope<\/h4>\n<p>  \u0424\u0443\u043d\u043a\u0446\u0438\u044f <b>$evalAsync<\/b> \u0434\u0435\u043b\u0430\u0435\u0442 \u0435\u0449\u0435 \u043a\u043e\u0435-\u0447\u0442\u043e, \u043e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 digest, \u0435\u0441\u043b\u0438 \u043e\u043d \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f. \u0421\u043c\u044b\u0441\u043b \u044d\u0442\u043e\u0433\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u0431\u044b \u0432\u044b \u043d\u0435 \u0432\u044b\u0437\u0432\u0430\u043b\u0438 <b>$evalAsync<\/b>, \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0432\u0430\u0448\u0430 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u00ab\u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043a\u043e\u0440\u043e\u00bb, \u0430 \u043d\u0435 \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0435\u0449\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 digest.<\/p>\n<p>  <b>$evalAsync<\/b> \u0434\u043e\u043b\u0436\u043d\u0430 \u043a\u0430\u043a-\u0442\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0441\u0435\u0439\u0447\u0430\u0441 digest \u0438\u043b\u0438 \u043d\u0435\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0439 \u0446\u0435\u043b\u0438 \u0432 Angular scope \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u00ab\u0444\u0430\u0437\u0430\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043e\u0431\u044b\u0447\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0432 scope, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442.<\/p>\n<p>  \u0412\u043d\u0435\u0441\u0435\u043c \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <b>$scope<\/b> \u043f\u043e\u043b\u0435 <b>$$phase<\/b>, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0432 \u0435\u0433\u043e \u0432 <b>null<\/b>:<\/p>\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = [];   this.$$phase = null; } <\/code><\/pre>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0430\u0440\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0444\u0430\u0437\u044b: \u043e\u0434\u043d\u0443 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u0434\u0440\u0443\u0433\u0443\u044e \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438. \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0444\u0430\u0437\u0443, \u043d\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$beginPhase = function(phase) {   if (this.$$phase) {     throw this.$$phase + ' already in progress.';   }   this.$$phase = phase; };   Scope.prototype.$clearPhase = function() {   this.$$phase = null; }; <\/code><\/pre>\n<p>  \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>$digest<\/b> \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0444\u0430\u0437\u0443 \u201c$digest\u201d, \u043e\u0431\u0435\u0440\u043d\u0435\u043c \u0432 \u043d\u0435\u0435 digest-\u0446\u0438\u043a\u043b:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   this.$beginPhase(&quot;$digest&quot;);   do {     while (this.$$asyncQueue.length) {       var asyncTask = this.$$asyncQueue.shift();       this.$eval(asyncTask.expression);     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       this.$clearPhase();       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty);   this.$clearPhase(); }; <\/code><\/pre>\n<p>  \u041f\u043e\u043a\u0430 \u043c\u044b \u0437\u0434\u0435\u0441\u044c, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u043e\u0434\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c <b>$apply<\/b>, \u0447\u0442\u043e\u0431\u044b \u0438 \u0442\u0443\u0442 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0430\u0441\u044c \u0444\u0430\u0437\u0430. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043e\u0442\u043b\u0430\u0434\u043a\u0438:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$apply = function(expr) {   try {     this.$beginPhase(&quot;$apply&quot;);     return this.$eval(expr);   } finally {     this.$clearPhase();     this.$digest();   } }; <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432 <b>$digest<\/b> \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>$evalAsync<\/b>. \u0417\u0434\u0435\u0441\u044c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0444\u0430\u0437\u0443, \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u043f\u0443\u0441\u0442\u0430 (\u0438 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0435\u0449\u0435 \u043d\u0435 \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043e) \u2014 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 <b>$digest<\/b>:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$evalAsync = function(expr) {   var self = this;   if (!self.$$phase && !self.$$asyncQueue.length) {     setTimeout(function() {       if (self.$$asyncQueue.length) {         self.$digest();       }     }, 0);   }   self.$$asyncQueue.push({scope: self, expression: expr}); }; <\/code><\/pre>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0432\u044b\u0437\u044b\u0432\u0430\u044f <b>$evalAsync<\/b>, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e digest \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0432 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u0432\u0440\u0435\u043c\u044f, \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043e\u0442\u043a\u0443\u0434\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u043b \u0432\u044b\u0437\u043e\u0432:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/iKeSaGi\/1\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = [];   this.$$phase = null; }  Scope.prototype.$beginPhase = function(phase) {   if (this.$$phase) {     throw this.$$phase + ' already in progress.';   }   this.$$phase = phase; };  Scope.prototype.$clearPhase = function() {   this.$$phase = null; };  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() {},     valueEq: !!valueEq   };   this.$$watchers.push(watcher); };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);   });   return dirty; };  Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   this.$beginPhase(&quot;$digest&quot;);   do {     while (this.$$asyncQueue.length) {       var asyncTask = this.$$asyncQueue.shift();       this.$eval(asyncTask.expression);     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       this.$clearPhase();       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty);   this.$clearPhase(); };  Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); };  Scope.prototype.$apply = function(expr) {   try {     this.$beginPhase(&quot;$apply&quot;);     return this.$eval(expr);   } finally {     this.$clearPhase();     this.$digest();   } };  Scope.prototype.$evalAsync = function(expr) {   var self = this;   if (!self.$$phase && !self.$$asyncQueue.length) {     setTimeout(function() {       if (self.$$asyncQueue.length) {         self.$digest();       }     }, 0);   }   self.$$asyncQueue.push({scope: self, expression: expr}); };  var scope = new Scope(); scope.asyncEvaled = false;  scope.$evalAsync(function(scope) {   scope.asyncEvaled = true; });  setTimeout(function() {   console.log(&quot;Evaled after a while: &quot;+scope.asyncEvaled); }, 100); \/\/ Check after a delay to make sure the digest has had a chance to run. <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> &quot;Evaled after a while: true&quot;<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u0434\u0430 \u043f\u043e\u0441\u043b\u0435 digest \u2014 $$postDigest<\/h4>\n<p>  \u0415\u0441\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0432\u043e\u0439 \u043a\u043e\u0434 \u0432 \u043f\u043e\u0442\u043e\u043a \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f digest-\u0446\u0438\u043a\u043b\u0430 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$$postDigest<\/b>.<\/p>\n<p>  \u0414\u0432\u043e\u0439\u043d\u043e\u0439 \u0434\u043e\u043b\u043b\u0430\u0440 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0438\u043c\u0435\u043d\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u0433\u043b\u0443\u0431\u0438\u043d\u043d\u0430\u044f Angular-\u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 Angular-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u043e \u043d\u0430\u043c \u044d\u0442\u043e \u043d\u0435 \u0432\u0430\u0436\u043d\u043e, \u043c\u044b \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c.<\/p>\n<p>  \u0422\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 <b>$evalAsync<\/b>, <b>$$postDigest<\/b> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 \u201c\u043f\u043e\u0442\u043e\u043c\u201d. \u0411\u043e\u043b\u0435\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e, \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 digest \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <b>$$postDigest<\/b> \u043d\u0435 \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 <b>$digest<\/b>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0430\u043f\u0443\u0441\u043a \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u0434\u043e \u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0433\u0434\u0430 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0439 \u043a\u043e\u0434 \u043d\u0435 \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u0442 digest. \u041a\u0430\u043a \u0438\u043c\u044f \u0438 \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442, <b>$$postDigest<\/b> \u0432\u0441\u0435\u0433\u043e-\u043b\u0438\u0448\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 digest, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0432\u044b \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043b\u0438 scope \u0432 \u043a\u043e\u0434\u0435, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u043c \u0432 <b>$$postDigest<\/b>, \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <b>$digest<\/b> \u0438\u043b\u0438 <b>$apply<\/b>, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u0438\u043b\u0438\u0441\u044c.<\/p>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <b>Scope<\/b>, \u043d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0434\u043b\u044f <b>$$postDigest<\/b>:<\/p>\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = [];   this.$$postDigestQueue = [];   this.$$phase = null; } <\/code><\/pre>\n<p>  \u0414\u0430\u043b\u0435\u0435, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u0430\u043c\u0443 <b>$$postDigest<\/b>. \u0412\u0441\u0435 \u0447\u0442\u043e \u043e\u043d\u0430 \u0434\u0435\u043b\u0430\u0435\u0442, \u044d\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$$postDigest = function(fn) {   this.$$postDigestQueue.push(fn); }; <\/code><\/pre>\n<p>  \u041d\u0443 \u0438 \u0432 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435, \u0432 \u043a\u043e\u043d\u0446\u0435 <b>$digest<\/b>, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0437\u0430 \u0440\u0430\u0437 \u0438 \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u043e\u0447\u0435\u0440\u0435\u0434\u044c:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   this.$beginPhase(&quot;$digest&quot;);   do {     while (this.$$asyncQueue.length) {       var asyncTask = this.$$asyncQueue.shift();       this.$eval(asyncTask.expression);     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       this.$clearPhase();       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty);   this.$clearPhase();     while (this.$$postDigestQueue.length) {     this.$$postDigestQueue.shift()();   } }; <\/code><\/pre>\n<p>  \u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <b>$$postDigest<\/b>:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/IMEhowO\/1\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = [];   this.$$postDigestQueue = [];   this.$$phase = null; }  Scope.prototype.$beginPhase = function(phase) {   if (this.$$phase) {     throw this.$$phase + ' already in progress.';   }   this.$$phase = phase; };  Scope.prototype.$clearPhase = function() {   this.$$phase = null; };  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() {},     valueEq: !!valueEq   };   this.$$watchers.push(watcher); };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     var newValue = watch.watchFn(self);     var oldValue = watch.last;     if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {       watch.listenerFn(newValue, oldValue, self);       dirty = true;     }     watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);   });   return dirty; };  Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   this.$beginPhase(&quot;$digest&quot;);   do {     while (this.$$asyncQueue.length) {       var asyncTask = this.$$asyncQueue.shift();       this.$eval(asyncTask.expression);     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       this.$clearPhase();       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty);   this.$clearPhase();    while (this.$$postDigestQueue.length) {     this.$$postDigestQueue.shift()();   } };  Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); };  Scope.prototype.$apply = function(expr) {   try {     this.$beginPhase(&quot;$apply&quot;);     return this.$eval(expr);   } finally {     this.$clearPhase();     this.$digest();   } };  Scope.prototype.$evalAsync = function(expr) {   var self = this;   if (!self.$$phase && !self.$$asyncQueue.length) {     setTimeout(function() {       if (self.$$asyncQueue.length) {         self.$digest();       }     }, 0);   }   self.$$asyncQueue.push({scope: self, expression: expr}); };  Scope.prototype.$$postDigest = function(fn) {   this.$$postDigestQueue.push(fn); };   var scope = new Scope(); var postDigestInvoked = false;  scope.$$postDigest(function() {   postDigestInvoked = true; });  console.assert(!postDigestInvoked);  scope.$digest(); console.assert(postDigestInvoked); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439<\/h4>\n<p>  \u041d\u0430\u0448\u0430 \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <b>$scope<\/b> \u0432\u0441\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0430\u0435\u0442\u0441\u044f \u043a \u0432\u0435\u0440\u0441\u0438\u0438 \u0432 Angular. \u041e\u0434\u043d\u0430\u043a\u043e \u043e\u043d\u0430 \u0435\u0449\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0445\u0440\u0443\u043f\u043a\u0430. \u042d\u0442\u043e \u043e\u0442\u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u0443\u0434\u0435\u043b\u044f\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439.<\/p>\n<p>  Scope-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 Angular \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c: \u043a\u043e\u0433\u0434\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0432 watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445, <b>$evalAsync<\/b> \u0438\u043b\u0438 \u0432 <b>$$postDigest<\/b> \u2014 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442 digest-\u0446\u0438\u043a\u043b. \u0412 \u043d\u0430\u0448\u0435\u0439 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u044e\u0431\u0430\u044f \u0438\u0437 \u044d\u0442\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442 \u043d\u0430\u0441 \u0438\u0437 digest.<\/p>\n<p>  \u041c\u043e\u0436\u043d\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u044d\u0442\u043e, \u043e\u0431\u0435\u0440\u043d\u0443\u0432 \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0431\u043b\u043e\u043a \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 <b>try\u2026catch<\/b>  <\/p>\n<blockquote><p>\u0412 Angular \u044d\u0442\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 $exceptionHandler. \u0423 \u043d\u0430\u0441 \u0435\u0433\u043e \u043f\u043e\u043a\u0430 \u043d\u0435\u0442, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u044b \u043f\u043e\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c.<\/p><\/blockquote>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0434\u043b\u044f <b>$evalAsync<\/b> \u0438 <b>$$postDigest<\/b> \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>$digest<\/b>. \u0412 \u043e\u0431\u043e\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u0430 digest \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   this.$beginPhase(&quot;$digest&quot;);   do {     while (this.$$asyncQueue.length) {       try {         var asyncTask = this.$$asyncQueue.shift();         this.$eval(asyncTask.expression);       } catch (e) {         (console.error || console.log)(e);       }     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       this.$clearPhase();       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty);   this.$clearPhase();     while (this.$$postDigestQueue.length) {     try {       this.$$postDigestQueue.shift()();     } catch (e) {       (console.error || console.log)(e);     }   } }; <\/code><\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0434\u043b\u044f watch-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0432 <b>$digestOnce<\/b>:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     try {       var newValue = watch.watchFn(self);       var oldValue = watch.last;       if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {         watch.listenerFn(newValue, oldValue, self);         dirty = true;       }       watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);     } catch (e) {       (console.error || console.log)(e);     }   });   return dirty; };  <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448 digest-\u0446\u0438\u043a\u043b \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043d\u0430\u0434\u0435\u0436\u043d\u0435\u0439 \u043a \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f\u043c:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/IMEhowO\/2\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = [];   this.$$postDigestQueue = [];   this.$$phase = null; }  Scope.prototype.$beginPhase = function(phase) {   if (this.$$phase) {     throw this.$$phase + ' already in progress.';   }   this.$$phase = phase; };  Scope.prototype.$clearPhase = function() {   this.$$phase = null; };  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() {},     valueEq: !!valueEq   };   this.$$watchers.push(watcher); };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     try {       var newValue = watch.watchFn(self);       var oldValue = watch.last;       if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {         watch.listenerFn(newValue, oldValue, self);         dirty = true;       }       watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);     } catch (e) {       (console.error || console.log)(e);     }   });   return dirty; };  Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   this.$beginPhase(&quot;$digest&quot;);   do {     while (this.$$asyncQueue.length) {       try {         var asyncTask = this.$$asyncQueue.shift();         this.$eval(asyncTask.expression);       } catch (e) {         (console.error || console.log)(e);       }     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       this.$clearPhase();       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty);   this.$clearPhase();    while (this.$$postDigestQueue.length) {     try {       this.$$postDigestQueue.shift()();     } catch (e) {       (console.error || console.log)(e);     }   } };  Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); };  Scope.prototype.$apply = function(expr) {   try {     this.$beginPhase(&quot;$apply&quot;);     return this.$eval(expr);   } finally {     this.$clearPhase();     this.$digest();   } };  Scope.prototype.$evalAsync = function(expr) {   var self = this;   if (!self.$$phase && !self.$$asyncQueue.length) {     setTimeout(function() {       if (self.$$asyncQueue.length) {         self.$digest();       }     }, 0);   }   self.$$asyncQueue.push({scope: self, expression: expr}); };  Scope.prototype.$$postDigest = function(fn) {   this.$$postDigestQueue.push(fn); };   var scope = new Scope(); scope.aValue = &quot;abc&quot;; scope.counter = 0;  scope.$watch(function() {   throw &quot;Watch fail&quot;; }); scope.$watch(   function(scope) {     scope.$evalAsync(function(scope) {       throw &quot;async fail&quot;;     });     return scope.aValue;   },   function(newValue, oldValue, scope) {     scope.counter++;   } );  scope.$digest(); console.assert(scope.counter === 1); <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> &quot;Watch fail&quot; &quot;async fail&quot; &quot;Watch fail&quot; true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u041e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f<\/h4>\n<p>  \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c, \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432, \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u0430\u0441\u044c \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0432\u0441\u0435 \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 scope-\u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0438 \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u044f\u0432\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0435\u0433\u043e. \u041d\u043e \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f, \u043a\u0430\u043a scope \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/p>\n<p>  \u0424\u0443\u043d\u043a\u0446\u0438\u044f <b>$watch<\/b> \u0432 Angular \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0432\u044b\u0437\u043e\u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439, \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c. \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e, \u0432\u0441\u0435 \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u044d\u0442\u043e \u0447\u0442\u043e\u0431\u044b <b>$watch<\/b> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0443\u0434\u0430\u043b\u044f\u044e\u0449\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 <b>$$watchers<\/b>:<\/p>\n<pre><code class=\"javascript\">Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var self = this;   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn,     valueEq: !!valueEq   };   self.$$watchers.push(watcher);   return function() {     var index = self.$$watchers.indexOf(watcher);     if (index &gt;= 0) {       self.$$watchers.splice(index, 1);     }   }; };  <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0443\u044e \u0438\u0437 <b>$watch<\/b> \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0438 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0435\u0435 \u043f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0438\u0442\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c:<\/p>\n<p>  <a href=\"http:\/\/jsbin.com\/IMEhowO\/4\/edit\">\u041a\u043e\u0434 \u043d\u0430 JS Bin<\/a>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">function Scope() {   this.$$watchers = [];   this.$$asyncQueue = [];   this.$$postDigestQueue = [];   this.$$phase = null; }  Scope.prototype.$beginPhase = function(phase) {   if (this.$$phase) {     throw this.$$phase + ' already in progress.';   }   this.$$phase = phase; };  Scope.prototype.$clearPhase = function() {   this.$$phase = null; };  Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {   var self = this;   var watcher = {     watchFn: watchFn,     listenerFn: listenerFn || function() { },     valueEq: !!valueEq   };   self.$$watchers.push(watcher);   return function() {     var index = self.$$watchers.indexOf(watcher);     if (index &gt;= 0) {       self.$$watchers.splice(index, 1);     }   }; };  Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {   if (valueEq) {     return _.isEqual(newValue, oldValue);   } else {     return newValue === oldValue ||       (typeof newValue === 'number' && typeof oldValue === 'number' &&        isNaN(newValue) && isNaN(oldValue));   } };  Scope.prototype.$$digestOnce = function() {   var self  = this;   var dirty;   _.forEach(this.$$watchers, function(watch) {     try {       var newValue = watch.watchFn(self);       var oldValue = watch.last;       if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {         watch.listenerFn(newValue, oldValue, self);         dirty = true;       }       watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);     } catch (e) {       (console.error || console.log)(e);     }   });   return dirty; };  Scope.prototype.$digest = function() {   var ttl = 10;   var dirty;   this.$beginPhase(&quot;$digest&quot;);   do {     while (this.$$asyncQueue.length) {       try {         var asyncTask = this.$$asyncQueue.shift();         this.$eval(asyncTask.expression);       } catch (e) {         (console.error || console.log)(e);       }     }     dirty = this.$$digestOnce();     if (dirty && !(ttl--)) {       this.$clearPhase();       throw &quot;10 digest iterations reached&quot;;     }   } while (dirty);   this.$clearPhase();    while (this.$$postDigestQueue.length) {     try {       this.$$postDigestQueue.shift()();     } catch (e) {       (console.error || console.log)(e);     }   } };  Scope.prototype.$eval = function(expr, locals) {   return expr(this, locals); };  Scope.prototype.$apply = function(expr) {   try {     this.$beginPhase(&quot;$apply&quot;);     return this.$eval(expr);   } finally {     this.$clearPhase();     this.$digest();   } };  Scope.prototype.$evalAsync = function(expr) {   var self = this;   if (!self.$$phase && !self.$$asyncQueue.length) {     setTimeout(function() {       if (self.$$asyncQueue.length) {         self.$digest();       }     }, 0);   }   self.$$asyncQueue.push({scope: self, expression: expr}); };  Scope.prototype.$$postDigest = function(fn) {   this.$$postDigestQueue.push(fn); };   var scope = new Scope(); scope.aValue = &quot;abc&quot;; scope.counter = 0;  var removeWatch = scope.$watch(   function(scope) {     return scope.aValue;   },   function(newValue, oldValue, scope) {     scope.counter++;   } );  scope.$digest(); console.assert(scope.counter === 1);  scope.aValue = 'def'; scope.$digest(); console.assert(scope.counter === 2);  removeWatch(); scope.aValue = 'ghi'; scope.$digest(); console.assert(scope.counter === 2); \/\/ No longer incrementing <\/code><\/pre>\n<p>  \u041a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre> true true true<\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h4>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435<\/h4>\n<p>  \u041c\u044b \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u043b\u0438 \u0434\u043e\u043b\u0433\u0438\u0439 \u043f\u0443\u0442\u044c, \u0438 \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u043e\u0442\u043b\u0438\u0447\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e scope-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0432 \u043b\u0443\u0447\u0448\u0438\u0445 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u044f\u0445 Angular. \u041d\u043e \u0432 scope-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 Angular \u2014 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0442\u043e, \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u0443 \u043d\u0430\u0441.<\/p>\n<p>  \u041d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 \u0432\u0430\u0436\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u0442\u043e, \u0447\u0442\u043e scope \u0432 Angular, \u044d\u0442\u043e \u043d\u0435 \u043e\u0431\u043e\u0441\u043e\u0431\u043b\u0435\u043d\u043d\u044b\u0435 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b. \u041d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, scope-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 scope-\u043e\u0432, \u0430 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0438\u0437 scope, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u043d\u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b, \u043d\u043e \u0438 \u0437\u0430 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 scope-\u043e\u0432. \u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434, \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u043e \u0441\u0443\u0442\u0438 \u2014 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043c\u043d\u043e\u0433\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0443 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 (scope) \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0435\u0440\u0438\u0438.<\/p>\n<p>  \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0441\u0443\u0434\u0438\u043c \u043f\u043e\u0434\u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0442\u043e\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0432 <b>Scope<\/b>.   \t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/201832\/\"> http:\/\/habrahabr.ru\/post\/201832\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\">       Angular \u2014 \u0437\u0440\u0435\u043b\u044b\u0439 \u0438 \u043c\u043e\u0449\u043d\u044b\u0439 JavaScript-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u041e\u043d \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438 \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435 \u043d\u043e\u0432\u044b\u0445 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0441\u0432\u043e\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0438\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0437\u043d\u0430\u043a\u043e\u043c\u044f\u0441\u044c \u0441 Angular, \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441 \u043e\u0434\u043d\u0438\u043c\u0438 \u0438 \u0442\u0435\u043c\u0438 \u0436\u0435 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044f\u043c\u0438. \u0427\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f digest? \u041a\u0430\u043a\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432? \u0427\u0435\u043c \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0438\u0441 \u043e\u0442 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430?<\/p>\n<p>  \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0443 Angular \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u0430\u044f <a href=\"http:\/\/docs.angularjs.org\/\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a>, \u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0443\u0447\u0430 <a href=\"http:\/\/syntaxspectrum.com\/tag\/angularjs\/\">\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432<\/a>, \u043d\u0435\u0442 \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044e, \u0447\u0435\u043c \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0435\u0435 \u043f\u043e \u043a\u0443\u0441\u043e\u0447\u043a\u0430\u043c \u0438 \u0432\u0441\u043a\u0440\u044b\u0442\u044c \u0435\u0435 \u043c\u0430\u0433\u0438\u044e.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u0432\u043e\u0441\u0441\u043e\u0437\u0434\u0430\u0442\u044c AngularJS \u0441 \u043d\u0443\u043b\u044f. \u041c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e \u0432\u043c\u0435\u0441\u0442\u0435 \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c, \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0447\u0435\u0433\u043e, \u0432\u044b \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0433\u043b\u0443\u0431\u0436\u0435 \u043f\u043e\u0439\u043c\u0435\u0442\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e Angular.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-201832","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/201832","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=201832"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/201832\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=201832"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=201832"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=201832"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}