ã¯ããã«
é©åœãæ¥ãŠããŸãã JavaScriptã«æ°ãã«è¿œå ããããã®ã¯ãããŒã¿ãã€ã³ãã£ã³ã°ã«ã€ããŠãããŸã§ã«ç¥ã£ãŠãããã¹ãŠãå€æŽããŸãã ããã«ãã¢ãã«ã®ç·šéãšæŽæ°ãç£èŠããMVCã©ã€ãã©ãªã®ã¢ãããŒããå€ãããŸãã æºåã¯ããã§ãã
ããã åŒã£åŒµããŸããã Chrome 36ã®ããŒã¿çã«ç»å ŽããObject.observeïŒïŒã玹ä»ã§ããŠããããã§ãã[CROWD HAPPY]
Object.observeïŒïŒã¯ã次ã®ECMAScriptæšæºã®äžéšã§ãã ãµãŒãããŒãã£ã®ã©ã€ãã©ãªã䜿çšããã«ãJavaScriptãªããžã§ã¯ããžã®å€æŽãéåæã§è¿œè·¡ã§ããŸãããªãã¶ãŒããŒã¯ããªããžã§ã¯ãã®ç¶æ ã®å€åãçµæçã«è¿œè·¡ã§ããŸãã
// , var model = {}; // Object.observe(model, function(changes){ // , changes.forEach(function(change) { // , console.log(change.type, change.name, change.oldValue); }); });
ãªããžã§ã¯ããå€æŽãããã³ã«ãã¢ã©ãŒããåãåããŸãïŒ
Object.observeïŒïŒïŒOoïŒïŒãŸãã¯OoooooooãšåŒã³ããïŒã䜿çšãããšããã¬ãŒã ã¯ãŒã¯ã䜿çšããã«åæ¹åã®ããŒã¿ãã€ã³ãã£ã³ã°ãå®è£ ã§ããŸãã
ããã¯ã䜿çšãã¹ãã§ã¯ãªããšããæå³ã§ã¯ãããŸããã è€éãªããžãã¹ããžãã¯ãæã€å€§èŠæš¡ãªãããžã§ã¯ãã®å Žåããã¬ãŒã ã¯ãŒã¯ãå¿ èŠã§ããããããã®äœ¿çšãæããšã©ãŸãããã€ããã¯ãããŸããã æ°ããéçºè ã®äœæ¥ãç°¡çŽ åãããµããŒãããããã«å¿ èŠãªã³ãŒããå°ãªããŠæžã¿ãç¹å®ã®ãã³ãã¬ãŒããå°å ¥ããŠäžè¬çãªã¿ã¹ã¯ãåŠçããããšãç®æããŠããŸãã ãã®ãããªæ©èœãå¿ èŠãªãå Žåã¯ãããªããŒãªã©ã®ãã軜éãªãœãªã¥ãŒã·ã§ã³ã䜿çšã§ããŸãïŒã¡ãªã¿ã«ãæ¢ã«OoïŒïŒã䜿çšããŠããŸãïŒã
ãã¬ãŒã ã¯ãŒã¯ãŸãã¯MV *ã©ã€ãã©ãªãæ倧éã«äœ¿çšããŠããå Žåã§ããOoïŒïŒã䜿çšãããšãããã©ãŒãã³ã¹ãåäžããŸããããã¯ãè¿ éã§ç°¡çŽ åãããå®è£ ã«ãã£ãŠéæãããåæã«åãAPIã䜿çšãç¶ããŸãã ããšãã°ãæšå¹ŽãAngularéçºããŒã ãæ¯èŒåæãå®æœããçµæãããŒãã£ãã§ãã¯ã«ã¯çŽ40ããªç§ããããŸããããO.oïŒïŒã«ã¯çŽ1ã2ããªç§ããããŸããïŒ20ã40åé«éã§ããããšãããããŸããïŒã
倧éã®è€éãªã³ãŒãã䜿çšããå¿ èŠã®ãªãããŒã¿ãã€ã³ãã£ã³ã°ïŒ ããããããã¯ãŸããå€æŽã«ã€ããŠã¢ãã«ã«è³ªåããå¿ èŠããªããªã£ãããšãæå³ããŸãïŒ
O.oãäœãããŠããã®ããæ¢ã«ç解ããŠããå ŽåïŒïŒãæ°ããæ©èœã®èª¬æã«ããã«æ»ããããã®ã¢ãããŒãã解決ããåé¡ãèªãããšãã§ããŸãã
äœãèŠãŸããïŒ
ããŒã¿ã®ç£èŠã«ã€ããŠè©±ããšããéåžžãããã€ãã®ã¿ã€ãã®å€æŽã远跡ããããšãæå³ããŸãã
- ãã€ãã£ãJavaScriptãªããžã§ã¯ãã®å€æŽ
- ããããã£ã®è¿œå ãå€æŽããŸãã¯åé€
- ããŒã¿ãåé€ãŸãã¯ã¢ã¬ã€ã«è¿œå ããããšã
- ãããã¿ã€ããªããžã§ã¯ãã®å€æŽ
ããŒã¿ãã€ã³ãã£ã³ã°ã®éèŠæ§ã«ã€ããŠ
ã¢ãã«ãšãã¥ãŒã®çžäºäœçšã«åœ±é¿ãäžãå§ãããšãããŒã¿ãã€ã³ãã£ã³ã°ã¯ã¢ããªã±ãŒã·ã§ã³ã®éèŠãªéšåã«ãªãå§ããŸãã HTMLã¯åªãã宣èšã¡ã«ããºã ã§ãããå®å šã«éçã§ãã çæ³çã«ã¯ãããŒã¿ãDOMã«é¢é£ä»ããŠææ°ã®ç¶æ ã«ä¿ã¡ããã ãã§ãã OoïŒïŒã䜿çšãããœãªã¥ãŒã·ã§ã³ã§ã¯ãDOMã«æ°ããããŒã¿ãåçŽã«éä¿¡ããç¹°ãè¿ãã³ãŒãã®å€§ããªãã£ã³ã¯ãäœæããå¿ èŠããªããããå€ãã®æéãç¯çŽã§ããŸãã
ããŒã¿ãã€ã³ãã£ã³ã°ã¯ãã¢ãã«ã®ããŸããŸãªããããã£ãšããããåæ ããUIèŠçŽ ã®éã«å€æ°ã®æ¥ç¶ã確ç«ããå¿ èŠãããå æ¬çãªãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ãäœæããå Žåã«éåžžã«äŸ¿å©ã§ãã ããã¯ãSPAïŒã·ã³ã°ã«ããŒãžã¢ããªã±ãŒã·ã§ã³ïŒã¢ããªã±ãŒã·ã§ã³ãäœæããéã®æãäžè¬çãªã¿ã¹ã¯ã®1ã€ã§ãã
åœåãããŒã¿ãç£èŠããã¡ã«ããºã ã¯ãããŸããã§ããããä»æ¥ãŸã§äžçäžã§äœ¿çšãããŠããããŸããŸãªäœéããã¯ã«äŸåããŠãããŸããŸãªJavaScriptãã¬ãŒã ã¯ãŒã¯ã«è²¬ä»»ã移ããŸããïŒãŸãã¯å°ããªã©ã€ãã©ãªãäœæããŸããïŒã
ä»æ¥ã®äžçã¯äœã§ããïŒ
ããŒãã£ãã§ãã¯
ãããŸã§ããŒã¿ãã€ã³ãã£ã³ã°ãèŠãããšããããŸããïŒ ããŠãææ°ã®MV *ã©ã€ãã©ãªã䜿çšããŠWebã¢ããªã±ãŒã·ã§ã³ïŒAngularãKnockoutïŒãäœæããå ŽåãDOMãžã®ã¢ãã«ããŒã¿ãã€ã³ãã£ã³ã°ãæ¢ã«äœ¿çšããŠããå¯èœæ§ããããŸãã ãããã¡ã¢ãªå ã§æŽæ°ããããã«ãé»è©±åž³ã¢ããªã±ãŒã·ã§ã³ã®äŸã次ã«ç€ºããŸããããã§ã¯ãçªå·ã®é åããåé»è©±çªå·ããªã¹ãã¢ã€ãã ã«ãã€ã³ããããããã®éã§äžå®ã®åæãç¶æããŸãã
<html ng-app> <head> ... <script src="angular.js"></script> <script src="controller.js"></script> </head> <body ng-controller="PhoneListCtrl"> <ul> <li ng-repeat="phone in phones"> {{phone.name}} <p>{{phone.snippet}}</p> </li> </ul> </body> </html>
ããã³ã³ã³ãããŒã©ãŒçšã®JavaScriptïŒ
var phonecatApp = angular.module('phonecatApp', []); phonecatApp.controller('PhoneListCtrl', function($scope) { $scope.phones = [ {'name': 'Nexus S', 'snippet': 'Fast just got faster with Nexus S.'}, {'name': 'Motorola XOOM with Wi-Fi', 'snippet': 'The Next, Next Generation tablet.'}, {'name': 'MOTOROLA XOOM', 'snippet': 'The Next, Next Generation tablet.'} ]; });
ïŒãã¢ïŒ
ã¢ãã«ããŒã¿ãå€æŽããããã³ã«ãDOMã®ãªã¹ããæŽæ°ãããŸãã Angularã¯ã©ã®ããã«ãããéæããŸããïŒ ãŸãã圌ã¯èå°è£ã§ç§ãã¡ãããŒãã£ãã§ãã¯ãšåŒãã§ããããšãããŸãã
ããŒãã£ãã§ãã¯ã®åºæ¬çãªèãæ¹ã¯ãããŒã¿ã¯ãã€ã§ãå€æŽã§ããã©ã€ãã©ãªã¯ãããã©ã®ããã«å€æŽããããããã§ãã¯ããå¿ èŠããããšããããšã§ãã è§åºŠã®å Žåãããã¯ã远跡ããå¿ èŠããããã¹ãŠã®ã¢ãã«ããŒã¿ã®ç¶æ ãç»é²ããããšã«ãã£ãŠçºçããŸãã 圌ã¯ã¢ãã«ã®ä»¥åã®å€ãç¥ã£ãŠãããå€ãå€åãããšã察å¿ããã€ãã³ããçºçããŸãã éçºè ã«ãšã£ãŠã®äž»ãªå©çã¯ãä¿å®ããã³çµåã容æãªãã€ãã£ãJSãªããžã§ã¯ãã䜿çšããããšã§ãã äžæ¹ãã¢ã«ãŽãªãºã ãéåžžã«è²ªæ¬²ã§ããéããããã¯éåžžã«é«äŸ¡ãªãœãªã¥ãŒã·ã§ã³ã«ãªãå¯èœæ§ããããŸãã
ãã®ãããªæäœã®ã³ã¹ãã¯ã芳å¯ããããªããžã§ã¯ãã®ç·æ°ã«æ¯äŸããŸãã ç§ã¯ãã®ãããªãã§ãã¯ãããããããå¿ èŠããããããããŸããã ãå€åãã¢ãã«ãå€æŽããããšãã«ããŒãã£ãã§ãã¯ã€ãã³ããããªã¬ãŒããæ¹æ³ãå¿ èŠã«ãªãå¯èœæ§ããããŸãã ãã®ãããªãœãªã¥ãŒã·ã§ã³ãå®è£ ããããã«ããã¬ãŒã ã¯ãŒã¯ãé Œãã«ããŠããããã€ãã®ããªãã¯ããããŸãã ãã®æ±ºå®ãæãæµ®ãã¶ãã©ããã¯ãŸã äžæã§ãã
Webãšã³ã·ã¹ãã ã«ã¯ããã®å®£èšçã¡ã«ããºã ãæ¹åããã³éçºããããã®ããå€ãã®æ©äŒãå¿ èŠã§ããããšãã°ã
- ã»ãã¿ãŒ/ã²ãã¿ãŒãä»ããŠå±æ§ã«å€éšã¢ã¯ã»ã¹ã§ããã³ã³ãããŒã«åºã¥ãã¢ãã«ã®ã·ã¹ãã
- èªåä¿åã·ã¹ãã ïŒIndexedDBãŸãã¯localStorageãžã®å€æŽãä¿åïŒ
- ã³ã³ãããªããžã§ã¯ãïŒããã¯ããŒã³ããšã³ããŒãªã©ïŒ
ã³ã³ãããªããžã§ã¯ãã¯ããã¬ãŒã ã¯ãŒã¯ãèªèº«ã«ããŒã¿ãæ ŒçŽãããªããžã§ã¯ããäœæããããŒã¿ã¹ãã¬ãŒãžã¡ã«ããºã ã§ãããã¢ã¯ã»ãµãŒïŒã²ãã¿ãŒ/ã»ãã¿ãŒïŒã䜿çšããŠã¢ã¯ã»ã¹ãæäŸããããã®å€æŽããµãã¹ã¯ã©ã€ãããæ©èœãå®è£ ããŸãã ããã¯éåžžã«ããŸãæ©èœããŸããã¢ã«ãŽãªãºã ã¯éåžžã«é«éãªåŠçãæäŸããŸãã Emberã§ãã®ãããªãªããžã§ã¯ãã䜿çšããäŸã以äžã«ç€ºããŸãã
// - MyApp.president = Ember.Object.create({ name: "Barak Obama" }); MyApp.country = Ember.Object.create({ // "Binding" Ember , // presidentNameBinding: "MyApp.president.name" }); // , Ember MyApp.country.get("presidentName"); // " " // , // .. .
ãã®å Žåã®å€åãæ€åºããã³ã¹ãã¯ãå€åããããããã£ã®æ°ã«æ¯äŸããŸãã å¥ã®åé¡ã¯ãç°ãªãã¿ã€ãã®ãªããžã§ã¯ãã䜿çšããããšã§ãã ç°¡åã«èšãã°ããµãŒããŒããåä¿¡ããããŒã¿ãå€æããŠãç£èŠå¯èœãªãªããžã§ã¯ãã«ã€ã³ã¹ããŒã«ããŸãã
ããã¯ãæ¢åã®JSã³ãŒããšã¯ç¹ã«äºææ§ããããŸããã ã»ãšãã©ã®ã³ãŒãã¯ãéåžžã®ããŒã¿ïŒã³ã³ãããªããžã§ã¯ããªã©ã«ã©ãããããŠããªãïŒãšããåãã§ãããšæ³å®ããŠããŸããããããã®ç¹æ®ãªãªããžã§ã¯ããšã¯ããåãã§ããŸããã
Object.observeã®æŠèŠïŒïŒ
ããã2ã€ã®ãŠãããŒã¹ãæ倧éã«æŽ»çšã§ããã°ãæ¬åœã«ã¯ãŒã«ã§ããéåžžã®ãªããžã§ã¯ãïŒãã€ãã£ãJavaScriptãªããžã§ã¯ãïŒããµããŒãããŠããŒã¿ã®å€åã芳å¯ããããŒãã£ãã§ãã¯ãåé€ãã代ããã«é©åãªã¢ã«ãŽãªãºã ãè¿œå ããŠãã ãããç¹æ§ã ããããã¹ãŠã®ååããªè³è³ªãçµã¿åããããã©ãããã©ãŒã ã«çµã¿èŸŒãŸãã人ã ã ãããæºãã-Object.observeïŒïŒã䜿çšããæºåãã§ããŸããïŒ
ãªããžã§ã¯ããç£èŠããããããã£ãå€æŽããå€æŽã¬ããŒããä»ããŠå€æŽãç£èŠã§ããŸãã ããããååãªçè«ãã³ãŒããèŠãŠã¿ãŸãããïŒ
Object.observeïŒïŒããã³Object.unobserveïŒïŒ
ã¢ãã«ãè¡šããã€ãã£ãJSãªããžã§ã¯ãããããšæ³åããŠã¿ãŸãããã
// var todoModel = { label: 'Default', completed: false };
ãªããžã§ã¯ãã«å€æŽãå ãããããšããã«åŒã³åºãããreturné¢æ°ã宣èšããããšãã§ããŸã
function observer(changes){ changes.forEach(function(change, i){ console.log('what property changed? ' + change.name); console.log('how did it change? ' + change.type); console.log('whats the current value? ' + change.object[change.name]); console.log(change); // all changes }); }
泚ïŒãªãã¶ãŒããŒã§returné¢æ°ãåŒã³åºããããšãç£èŠå¯Ÿè±¡ãªããžã§ã¯ãã¯æ°åå€æŽãããå¯èœæ§ããããããå€æŽããšã«æ°ããå€ãšçŸåšã®å€ã¯å¿ ãããåãã§ã¯ãããŸããã
OoïŒïŒã䜿çšããŠãã®ãããªå€åã芳å¯ãã芳å¯ããããªããžã§ã¯ããæåã®åŒæ°ãšããŠãè¿ãããé¢æ°ã2çªç®ãšããŠæž¡ããŸãã
Object.observe(todoModel, observer);
ã¢ãã«ã§äœããè©ŠããŠã¿ãŸãããïŒ
todoModel.label = 'Buy some more milk';
ã³ã³ãœãŒã«ãèŠãŠãå€ãã®æçšãªæ å ±ãåŸãŸããïŒ ã©ã®ããããã£ãå€æŽãããããã©ã®ããã«å€æŽãããããã©ã®æ°ããå€ãå²ãåœãŠãããããããããŸãã
ããïŒ ããããªããããŒãã£ãã§ãã¯ïŒ ãã¥ãŒã ã¹ããŒã³ã®ç¢æã¯ãComic Sansã«ãã£ãŠåœ«ãããŸãã å¥ã®ããããã£ãå€æŽããŸãããã ä»åã¯å®äºããŸããïŒ
todoModel.completeBy = '01/01/2014';
ã芧ã®ããã«ãå€æŽã«é¢ããã¬ããŒããåã³åãåããŸããã
ããŠããªããžã§ã¯ããããcompletedãããããã£ãåé€ããããšã«ããå Žåã¯ã©ããªãã§ãããã
delete todoModel.completed;
ã芧ã®ãšãããå€æŽã¬ããŒãã«ã¯åé€æ å ±ãå«ãŸããŠããŸãã äºæ³ã©ãããæ°ããããããã£å€ã¯æªå®çŸ©ã§ãã ãããã£ãŠãæ°ããããããã£ãè¿œå ãŸãã¯åé€ãããããšã远跡ã§ããããšãããããŸããã ç°¡åã«èšãã°ããªããžã§ã¯ãã®å€ãã®ããããã£ïŒãæ°èŠãããåé€ãããåæ§æãïŒãšãã®ãããã¿ã€ããã§ãŒã³ã§ãã
ä»ã®ç£èŠã·ã¹ãã ãšåæ§ã«ããªããžã§ã¯ããžã®å€æŽã®ç£èŠãåæ¢ããæ¹æ³ãå¿ èŠã§ãã ç§ãã¡ã®å Žåãããã¯Object.unobserveïŒïŒã§ãããOoïŒïŒãšåã眲åãæã£ãŠããŸããã次ã®ããã«åŒã³åºãããšãã§ããŸãã
Object.unobserve(todoModel, observer);
以äžã«ç€ºãããã«ãæåŸã®ã¡ãœãããåŒã³åºããåŸã«å ããããå€æŽã¯ãã³ã³ãœãŒã«ãžã®å€æŽã®ã¬ããŒãã衚瀺ããªããªããŸãã
ããããã£ã«çŠç¹ãåœãŠã
ããã§ãåºæ¬ã«æ £ãããã芳å¯å¯Ÿè±¡ã®å€æŽã®ãªã¹ãã«æ»ããŸãããã
Object.observe(obj, callback, opt_acceptList)
äŸã«ç§»ãããããã©ã®ããã«äœ¿çšãããããèŠãŠã¿ãŸãããã
// , var todoModel = { label: 'Default', completed: false }; // // , function observer(changes){ changes.forEach(function(change, i){ console.log(change); }) }; // , // , Object.observe(todoModel, observer, ['delete']); // // todoModel.label = 'Buy some milk'; // , !
ããã§ããlabelãããããã£ãåé€ãããšãå€æŽã«é¢ããéç¥ãçºçããŸãã
delete todoModel.label;
OoïŒïŒã«é©çšå¯èœãªã¿ã€ãã®ãªã¹ããæå®ããªãå Žåãããã©ã«ãã§ã¯ãå€æŽãè¿œå ãããå éšããªããžã§ã¯ããæž¡ãããŸãããã®ãªããžã§ã¯ãã¯ããaddãããupdateãããdeleteãããreconfigureãã芳å¯å¯èœïŒã
éç¥
OoïŒïŒã«ã¯ãéç¥ïŒã¢ã©ãŒãïŒã®æŠå¿µããããŸãã 圌ãã¯ããªãã®æºåž¯é»è©±ã«çŸããè¿·æãªãã®ãšã¯äœã®é¢ä¿ããããŸããã圌ãã¯ã¯ããã«äŸ¿å©ã§ãã éç¥ã¯Mutation Observers ïŒããã³zag2artã®ãã ã«é¢ãããã°ãããèšäºïŒã«äŒŒãŠããŸãã ãããã¯ããã€ã¯ãã¿ã¹ã¯ã®å®äºæã«çºçããŸãã ãã©ãŠã¶ãŒã³ã³ããã¹ãã§ã¯ãã»ãšãã©ã®å ŽåãçŸåšã®ã€ãã³ããã³ãã©ãŒã®æåŸã«çºçããŸãã
ãã®ãããªæéã¯ãäž»èŠãªäœæ¥ããã§ã«å®äºããŠãããšããäºå®ã«ããéåžžã«äŸ¿å©ã§ããããªãã¶ãŒããŒã¯äž»èŠãªããžãã¯ã«å¹²æžããããšãªãäœæ¥ãéå§ã§ããŸãã ããã¯ãåªããã¹ããããã€ã¹ãããã®ã€ãã³ãåŠçã¢ãã«ã§ãã
ã¢ã©ãŒãã䜿çšããŠæ§ç¯ãããã¯ãŒã¯ãããŒã¯æ¬¡ã®ããã«ãªããŸãã
次ã«ãéç¥ã䜿çšããŠãªããžã§ã¯ãã®ç¶æ ã®å€åãéç¥ããæ¹æ³ã®äŸãèŠãŠã¿ãŸãããã ã³ã¡ã³ãã«æ³šæããŠãã ããïŒ
// var model = { a: {} }; // , // var _b = 2; // "b" "a" // Object.defineProperty(model.a, 'b', { get: function () { return _b; }, set: function (b) { // "b" , // // , . // Object.getNotifier(this).notify({ type: 'update', name: 'b', oldValue: _b }); // // - console.log('set', b); _b = b; } }); // function observer(changes) { changes.forEach(function (change, i) { console.log(change); }) } // model.a Object.observe(model.a, observer);
ããã§ã¯ãããŒã¿ãå€æŽïŒãæŽæ°ãïŒããããšãã«ã¢ã©ãŒãã衚瀺ããŸããå®éãnotifier.notifyChangeïŒïŒã¡ãœããã®åŒã³åºãã§ç€ºãããŠããå Žåã¯äœã§ã衚瀺ãããŸãã
ãŠã§ãéçºã®é·å¹Žã®çµéšãããåææäœãç§ãã¡ãæåã«åŠã¶ããšã§ããããšãããããŸããã ãã®ãããªæäœã ãã管çããã®ãæãç°¡åã§ãã åé¡ã¯ãããã«ããæœåšçã«å±éºãªåŠçã¢ãã«ïŒããŒã¿åŠçã¢ãã«ãªã© ïŒãäœæãããããšã§ãã ã³ãŒããæžããŠãããšãã°ããªããžã§ã¯ãã®ããããã£ãæŽæ°ããããšæžããå Žåããããæãã§ããããšãäœã§ãã§ããé¢æ°ã®éäžã§ä»»æã®ã³ãŒããããªã¬ãŒããããšã¯ã»ãšãã©æã¿ãŸããã
ãªãã¶ãŒããŒåŽããã§ãããµãŒãããŒãã£ã®é¢æ°ãçŸåšã®é¢æ°ã®éäžããåŒã³åºãããããšã¯æãŸãããããŸããã é¢æ°åŒã³åºãã®å Žæã®äžè²«æ§ãšæçåã¯è¿·æã§ãããïŒ ãããŠãããã«ããã«ãšã©ãŒãã§ãã¯ãããã³ãã®ã¢ãããŒãã§ç掻ãè€éã«ããä»ã®ç¶æ³ãè¿œå ããŸãã ãã®çµæããã®ãããªã¢ãã«ã§äœæ¥ããããšã¯æ¬åœã«é£ããããšãããããŸãã éåæã¢ãããŒãã¯ç解ããã®ãããå°é£ã§ãããããã§ããä»æ¥ãããããåªãããã®ã¯ãããŸããã
ãã®åé¡ã®è§£æ±ºçã¯ãç·åçãªã¬ã³ãŒãã®å€æŽã§ãã
ã¬ã³ãŒãã®ç·åçãªå€æŽ
ç°¡åã«èšããšãã¢ã¯ã»ãµãŸãã¯èšç®ãããããããã£ã«ã¢ã¯ã»ã¹ããå¿ èŠãããå ŽåïŒ ããã§ããããã£ã«ã€ããŠèªãããšãã§ããŸã ïŒããã®ããããã£ãå€æŽããããšãã«ã¢ã©ãŒããäœæãã責任ããããŸãã ããã¯å°ãäœæ¥ãè¿œå ããŸãããäžäŸ¿ãšããããã¯æ©èœã§ãã éç¥ã¯ãä»ã®ããããã£ã®å€æŽã®éç¥ãšãšãã«é ä¿¡ããã次ã®åœ¢åŒã«ãªããŸãã
ã¢ã¯ã»ãµã®ç£èŠãšèšç®ãããããããã£ã®å€æŽã¯ãnotifier.notifyã䜿çšããŠå®è¡ã§ããŸãïŒããã¯Object.observeä»æ§ã«ãå«ãŸããŠããŸãïŒã å€ãã®å€æŽç£èŠã·ã¹ãã ã¯ãå€æŽãããå€ã«é¢ããæ å ±ãæäŸããå¿ èŠããããççŽã«èšã£ãŠããããè¡ãæ¹æ³ã¯ããªããããŸãã Object.observeã¯ããæ£ããããã¹ãç§ãã¡ã«èª²ããŸããã
Webéçºè ã¯ãèšç®ãããããããã£ã®å€æŽã®éç¥ãæ¯æŽããããã«ãã©ã€ãã©ãªããæ¢è£œã®ãœãªã¥ãŒã·ã§ã³ãæåŸ ã§ãããšæããŸãã
次ã«ãCircleã¯ã©ã¹ã®äœæã瀺ã次ã®äŸã«é²ã¿ãŸãããã äžçªäžã®è¡ã¯ãåãšãã®ãååŸãããããã£ãããããšã§ãã ãã®äŸã§ã¯ãååŸã¯ã¢ã¯ã»ãµãŒã«ãªããå€ãå€æŽããããšããããéç¥ããã€ãã³ããçºçããŸãã ãªããžã§ã¯ãã®å€æŽã«é¢ããä»ã®ãã¹ãŠã®éç¥ãšãšãã«é ä¿¡ãããŸãã
DevToolsã§ã³ãŒããã©ã®ããã«æ©èœããããèŠãŠã¿ãŸãããã
function Circle(r) { var radius = r; var notifier = Object.getNotifier(this); function notifyAreaAndRadius(radius) { notifier.notify({ type: 'update', name: 'radius', oldValue: radius }) notifier.notify({ type: 'update', name: 'area', oldValue: Math.pow(radius * Math.PI, 2) }); } Object.defineProperty(this, 'radius', { get: function() { return radius; }, set: function(r) { if (radius === r) return; notifyAreaAndRadius(radius); radius = r; } }); Object.defineProperty(this, 'area', { get: function() { return Math.pow(radius, 2) * Math.PI; }, set: function(a) { r = Math.sqrt(a)/Math.PI; notifyAreaAndRadius(radius); radius = r; } }); } function observer(changes){ changes.forEach(function(change, i){ console.log(change); }) }
ã¢ã¯ã»ãµããããã£
ã¢ã¯ã»ãµã®ããããã£ã«é¢ããå°ããªã¡ã¢ã åã«ãããããã£å€ã®å€åã芳å¯ããããšã«ã€ããŠã®ã¿èª¬æããŸããããã¢ã¯ã»ãµãŸãã¯èšç®ãããããããã£ã®ãã®ãããªåäœã«ã€ããŠã¯ãŸã£ããèšåããŸããã§ããã ãã®çç±ã¯ãå®éã«ã¯JavaScriptãã¢ã¯ã»ãµã®å€ã®å€åã远跡ããæ©èœãæã£ãŠããªããšããäºå®ã§ããå®éããããã¯é¢æ°ã®ã³ã¬ã¯ã·ã§ã³ã«ãããªãããã§ãã
ã¢ã¯ã»ãµãŒãæ¢ã«äœ¿çšããŠããå Žåãããããã©ã®ããã«æ©èœãããæ³åã§ããŸãããããã¯ãããããã£ãžã®ã¢ã¯ã»ã¹ãæäŸããé¢æ°ã®ã»ãããæäŸããã ãã§ããã以äžã®ãã®ã¯ãããŸããã
åäžã®ãªã¿ãŒã³é¢æ°ã§è€æ°ã®ãªããžã§ã¯ããç£èŠãã
OoïŒïŒã䜿çšããå Žåã®ãã1ã€ã®å¯èœãªãã¿ãŒã³ã¯ãåäžã®æ»ãé¢æ°ã§ãªããžã§ã¯ã芳枬ã䜿çšããè¡šèšæ³ã§ãã ããã«ããããã®é¢æ°ãä»»æã®æ°ã®ç°ãªããªããžã§ã¯ãã®ãªãã¶ãŒããŒé¢æ°ãšããŠäœ¿çšã§ããŸãã è¿ãããé¢æ°ã¯ã远跡ãããã¹ãŠã®ãªããžã§ã¯ãã®å€æŽã®å®å šãªã»ãããæ¯åæäŸããŸãïŒããã¯ããã¹ãŠã®ãã€ã¯ãã¿ã¹ã¯ã®çµäºæã«çºçããŸããçªç¶å€ç°ãªãã¶ãŒããŒãåç §ããŠãã ããïŒã
倧èŠæš¡ãªå€æŽ
ãããããããªãã¯æ¬åœã«ããããžã§ã¯ãã«åãçµãã§ãããå®æçã«å€§èŠæš¡ãªå€æŽã«å¯ŸåŠããå¿ èŠããããŸãã
OoïŒïŒã¯ããã§ã«èª¬æããnotifier.performChangeïŒïŒãšnotifier.notifyïŒïŒã®2ã€ã®ç¹å®ã®é¢æ°ã§ãããæ¯æŽããŸãã
æ°åŠçé¢æ°ïŒmultiplyãincrementãincrementAndMultiplyïŒã䜿çšããŠThingyãªããžã§ã¯ãã䜿çšããŠå€§èŠæš¡ãªå€æŽãèšè¿°ããæ¹æ³ã®äŸãèŠãŠã¿ãŸãããã é¢æ°ã䜿çšãããã³ã«ãäœæ¥ã®ã³ã¬ã¯ã·ã§ã³ã«ç¹å®ã®çš®é¡ã®å€æŽãå«ãŸããŠããããšãã·ã¹ãã ã«éç¥ããŸãã
äŸïŒnotifier.performChangeïŒ 'foo'ãperformFooChangeFnïŒ;
function Thingy(a, b, c) { this.a = a; this.b = b; } Thingy.MULTIPLY = 'multiply'; Thingy.INCREMENT = 'increment'; Thingy.INCREMENT_AND_MULTIPLY = 'incrementAndMultiply'; Thingy.prototype = { increment: function(amount) { var notifier = Object.getNotifier(this); // , // : // notifier.performChange('foo', performFooChangeFn); // notifier.notify('foo', 'fooChangeRecord'); notifier.performChange(Thingy.INCREMENT, function() { this.a += amount; this.b += amount; }, this); notifier.notify({ object: this, type: Thingy.INCREMENT, incremented: amount }); }, multiply: function(amount) { var notifier = Object.getNotifier(this); notifier.performChange(Thingy.MULTIPLY, function() { this.a *= amount; this.b *= amount; }, this); notifier.notify({ object: this, type: Thingy.MULTIPLY, multiplied: amount }); }, incrementAndMultiply: function(incAmount, multAmount) { var notifier = Object.getNotifier(this); notifier.performChange(Thingy.INCREMENT_AND_MULTIPLY, function() { this.increment(incAmount); this.multiply(multAmount); }, this); notifier.notify({ object: this, type: Thingy.INCREMENT_AND_MULTIPLY, incremented: incAmount, multiplied: multAmount }); } }
æœèšã«å¯ŸããŠ2ã€ã®ãªãã¶ãŒããŒã宣èšããŸãã1ã€ã¯ãã¹ãŠã®å€æŽãç£èŠãããã1ã€ã¯äžèšã®ç¹å®ã®å€æŽãå ±åããããã®ãã®ã§ãïŒThingy.INCREMENTãThingy.MULTIPLYãThingy.INCREMENT_AND_MULTIPLYïŒã
var observer, observer2 = { records: undefined, callbackCount: 0, reset: function() { this.records = undefined; this.callbackCount = 0; }, }; observer.callback = function(r) { console.log(r); observer.records = r; observer.callbackCount++; }; observer2.callback = function(r){ console.log('Observer 2', r); } Thingy.observe = function(thingy, callback) { // Object.observe(obj, callback, optAcceptList) Object.observe(thingy, callback, [Thingy.INCREMENT, Thingy.MULTIPLY, Thingy.INCREMENT_AND_MULTIPLY, 'update']); } Thingy.unobserve = function(thingy, callback) { Object.unobserve(thingy); }
ããŠãããã§ã³ãŒããå°ãè©Šãããšãã§ããŸããæ°ããThingyãçºè¡šããŸãããïŒ
var thingy = new Thingy(2, 4);
ããã芳å¯ããããã€ãã®å€æŽãå ããŸãããã£ãããïŒ
// thingy (, " ") Object.observe(thingy, observer.callback); Thingy.observe(thingy, observer2.callback); // , thingy thingy.increment(3); // { a: 5, b: 7 } thingy.b++; // { a: 5, b: 8 } thingy.multiply(2); // { a: 10, b: 16 } thingy.a++; // { a: 11, b: 16 } thingy.incrementAndMultiply(2, 2); // { a: 26, b: 36 }
ãå®è¡ãããæ©èœãå ã«ãããã¹ãŠã®ãã®ã¯ããå€æ°ã®å€æŽãã䌎ãäœæ¥ãšèŠãªãããŸããã倧ããªå€åããåãå ¥ãããªãã¶ãŒããŒã¯ããããåãåãã ãã§ããæ®ãã®ãªãã¶ãŒããŒã¯æ®ãã®å€æŽãåãåããŸãã
ã¢ã¬ã€ç£èŠ
ãªããžã§ã¯ãã®å€åã芳å¯ããããšã«ã€ããŠè©±ããŸããããé åã«ã€ããŠã¯ã©ãã§ããïŒãã質åã§ãïŒãšããã§ã圌ããç§ã«ãçŽ æŽããã質åããšèšããã³ã«ãç§ã¯çãã決ããŠèããŸããããã®ãããªè¯ã質åã«èªåèªèº«ãç¥çŠããããšã«ããŸãã«ãéäžããŠããŸããããæ°ãæ£ããŸãã:)é åãæ±ãããã®æ°ããæ¹æ³ããããŸãïŒ
Array.observe()
ãªããžã§ã¯ãèªäœã«å¯Ÿããå€æ°ã®å€æŽïŒã¹ãã©ã€ã¹ãã·ãã解é€ãã¹ãã©ã€ã¹ãªã©ã®é·ããå€æŽããäœãïŒãåŠçããã¡ãœããã§ãã
ãããè¡ãããã«ã圌ã¯
notifier.performChange("splice",...)
ãé åãã¢ãã«ã芳å¯ããŠããäŸãšãåæ§ã«ãããŒã¿ãå€æŽããã¢ã¯ã·ã§ã³ãã¢ãã«ã§å®è¡ããããšãã«å€æŽã®ãªã¹ããååŸããäŸã䜿çšããŸãã
var model = ['Buy some milk', 'Learn to code', 'Wear some plaid']; var count = 0; Array.observe(model, function(changeRecords) { count++; console.log('Array observe', changeRecords, count); }); model[0] = 'Teach Paul Lewis to code'; model[1] = 'Channel your inner Paul Irish';
æ§èœ
OoïŒïŒã®èšç®é床ã¯ããã£ãã·ã¥èªã¿åãé床ãšèããããšãã§ããŸããäžè¬çã«ããã£ãã·ã¥ã¯æ¬¡ã®å Žåã«éèŠãªéžæè¢ã§ãïŒéèŠåºŠã®é«ãé ã«ïŒã
- æžã蟌ã¿é »åºŠããé«ãèªã¿åãé床
- èªã¿åãæäœã®æžã蟌ã¿æéãåºå®æéã«ç ç²ã«ãããã£ãã·ã¥ãäœæããæ©äŒãããå Žå
- èšé²æäœã®äžå®ã®é 延æéã¯èš±å®¹ç¯å²ã§ã
OoïŒïŒã¯ãæåã®ãããªãŠãŒã¹ã±ãŒã¹åãã«èšèšãããŠããŸãã
ããŒãã£ãã§ãã¯ã§ã¯ãç£èŠããŠãããã¹ãŠã®ããŒã¿ã®ã³ããŒãä¿æããå¿ èŠããããŸããããã¯ãOoïŒïŒã§ã¯æ±ºããŠåŸãããªãã¡ã¢ãªãã¬ã€ã³ãåŸãããããšãæå³ããŸããããŒãã£ãã§ãã¯ã¯äžçš®ã®ã®ã£ã°ã§ãããããã¯äžçš®ã®äžå¿ èŠãªæœè±¡åãåŒãèµ·ãããçµæãšããŠã¢ããªã±ãŒã·ã§ã³ã«äžå¿ èŠãªè€éãããããããŸãã
ãªãã§ïŒããŒãã£ãã§ãã¯ã¯ãããŒã¿ãå€æŽããããã³ã«èµ·åãããããã§ããããã¯ãã®ãããªæ€èšŒã®ä¿¡é Œã§ããæ¹æ³ã§ã¯ãªããããšãã°ã¬ã³ããªã³ã°ã³ãŒãïŒãªã©ïŒãšèšç®ã³ãŒãã®ç«¶åãªã©ãé倧ãªæ¬ ç¹ããããŸãïŒçµå±ãJSã¯ã€ã³ã¿ãŒãã§ã€ã¹ãšèšç®ã®äž¡æ¹ã«1ã€ã®ã¹ããªãŒã ã䜿çšããããšã誰ããç¥ã£ãŠããŸããïŒïŒãããŒãã£ãã§ãã¯ã«ã¯ãã°ããŒãã«ãªãã¶ãŒãã¬ãžã¹ããªã®æ¥ç¶ãå¿ èŠã§ãããããã¡ã¢ãªãªãŒã¯ãªã©ã®ãªã¹ã¯ãçºçããOoïŒïŒãåé¿ãããŸãã
ããã€ãã®æ°åãèŠãŠã¿ãŸãããã
以äžã®ãã³ãããŒã¯ïŒGitHubã§å©çšå¯èœïŒã«ãããããŒãã£ãã§ãã¯ãšOoïŒïŒãæ¯èŒã§ããŸãããããã¯ã暪座æšObserved-Object-Set-SizeãšçžŠåº§æšã®Number-Of-Mutationsãæã€ã°ã©ãã®åœ¢åŒã§è¡šç€ºãããŸãã
äž»ãªçµæã¯ãããŒãã£ãã§ãã¯ã®ããã©ãŒãã³ã¹ã¯èŠ³æž¬ããããªããžã§ã¯ãã®æ°ã«æ¯äŸããOoïŒïŒã®ããã©ãŒãã³ã¹ã¯äœæããçªç¶å€ç°ã®æ°ã«æ¯äŸããããšã§ãã
æ±ãããã§ãã¯
Object.observeïŒïŒ
å€ããã©ãŠã¶ã®Object.observeïŒïŒ
ã¯ãŒã«ãOoïŒïŒã¯Chrome 36ããŒã¿çã§äœ¿çšã§ããŸãããä»ã®ãã©ãŠã¶ã¯ã©ãã§ããïŒãæäŒãããŸãã Observe-JSã¯ãPolymerã®ããªããŒã§ããã衚瀺ããããšããã«ãã€ãã£ãå®è£ ã䜿çšããŸããããã®äžã«ããã€ãã®æçšãªãã®ãå«ãŸããŠããŸãã圌ã¯ã芳å¯ããããªããžã§ã¯ãã®äžè¬åããããã¥ãŒã䜿çšããäžè¬çãªå€æŽã«ã€ããŠå ±åããããšãææ¡ããŸããããã«åœŒãæäŸããããã€ãã®äŸ¿å©ãªãã®ããããŸãïŒ
1ïŒããã¹ããèŠãããšãã§ããŸããããã¯ãéžæãããªããžã§ã¯ãã®ãã¡ãã£ãšãfoo.bar.bazã远跡ãããããšèšãããšãã§ããããããã£ã®å€æŽãçºçãããšããã«éç¥ããããšãæå³ããŸãããã¹ã䜿çšã§ããªãå Žåããè¿ã
undefined
ãŸãã
æå®ããããªããžã§ã¯ãã®ãã¹ã«æ²¿ã£ãŠå€ã芳å¯ããäŸïŒ
var obj = { foo: { bar: 'baz' } }; var observer = new PathObserver(obj, 'foo.bar'); observer.open(function(newValue, oldValue) { // , obj.foo.bar });
2ïŒã¢ã¬ã€ã®é·ãã®å€æŽãéç¥ããŸãããã®å Žåã®é åã®é·ãã®å€æŽã¯ãå€ãç¶æ ããæ°ããïŒå€æŽãããïŒç¶æ ã«é åã転éããããã«é åã§è¡ãå¿ èŠãããã¹ãã©ã€ã¹æäœã®æå°æ°ã§ãã
ã¹ãã©ã€ã¹æäœã®æå°éã®ã»ãããªã©ãé åã«é¢ãããã®ãããªå€æŽã®éç¥ã®äŸïŒ
var arr = [0, 1, 2, 4]; var observer = new ArrayObserver(arr); observer.open(function(splices) { // splices.forEach(function(splice) { splice.index; // , splice.removed; // , , splice.addedCount; // , }); });
ãã¬ãŒã ã¯ãŒã¯ãšObject.observeïŒïŒ
åè¿°ããããã«ãOoïŒïŒã¯ãã¬ãŒã ã¯ãŒã¯ãšã©ã€ãã©ãªã«ããã®é©æ°ããµããŒããããã©ãŠã¶ãŒã§ã®ããŒã¿ãã€ã³ãã£ã³ã°ã¡ã«ããºã ã®ããã©ãŒãã³ã¹ãåäžããã絶奜ã®æ©äŒãäžããŸãã
Emberã®Yehuda KatzãšEric Brinã¯ãEmberã®ä»åŸã®ããŒããããã§OoïŒïŒãµããŒããæ¿èªããŸããã Misko HerveyïŒAngularããïŒã¯ãå€æŽæ€åºã®æ¹åã«é¢ãã圌ã®Angular 2.0ããã¥ã¡ã³ãã®ãã©ããã«ãæžããŸããã
Emberã®Yehuda KatzãšErik Brynã¯ãOoïŒïŒã®ãµããŒãã®è¿œå ãEmberã®çæããŒããããã«ããããšã確èªããŸããã Angularã®Misko Hervyã¯ãAngular 2.0ã®æ¹è¯ãããå€æŽæ€åºã«é¢ããèšèšããã¥ã¡ã³ããäœæããŸããããã®æ©èœãChrome 36å®å®çããã±ãŒãžã«ç»å Žãããšããã®æ¹åãžã®åããäºæ³ãããå¯èœæ§ãæãé«ããšæããŸãã
ãŸãšã
OoïŒïŒã¯ãä»æ¥äœ¿çšã§ããWebãã©ãããã©ãŒã ã®åŒ·åãªé©æ°ã§ãã
ãã®æ©èœãããã«ä»ã®ãã©ãŠã¶ã«è¡šç€ºãããJavaScriptãã¬ãŒã ã¯ãŒã¯ããªããžã§ã¯ãã®æ°ãããã€ãã£ãæ©èœã䜿çšããŠããã©ãŒãã³ã¹ãåäžãããç£èŠã§ããããã«ãªãããšãé¡ã£ãŠããŸããChrome 36ã«å ããŠããã®æ©èœã¯ä»åŸã®OperaãªãªãŒã¹ã§ãå©çšå¯èœã«ãªããŸãã
ããŠãããã§ãJSãã¬ãŒã ã¯ãŒã¯ã®äœæè ã«Object.observeïŒïŒãšãããã䜿çšããŠããŒã¿ãã€ã³ãã£ã³ã°ã¡ã«ããºã ãæ¹åããæ¹æ³ãäŒããããšãã§ããŸãã
æ¬åœã«çŽ æŽãããæ代ããã£ãŠããããã§ãïŒ
䜿çšããããªãœãŒã¹ïŒ
- Harmony wikiã®Object.observeïŒïŒ
- Object.observeïŒïŒã«ããããŒã¿ãã€ã³ãã£ã³ã°by Rick Waldron
- Object.observeïŒïŒã«ã€ããŠç¥ãããããšãã¹ãŠ-JSConf
- Object.observeïŒïŒãES7ã®æé«ã®æ©èœã§ããçç±
UPDïŒããã€ã³ãã£ã³ã°ããããã€ã³ãã£ã³ã°ãã«å€ãããŸãã
UPD 2ïŒã³ã¡ã³ãããã·ã¢èª
UPD 3ïŒç¿»èš³ãããææ³ãšå¥èªç¹ã®ãšã©ãŒã«ç¿»èš³ãããŸãããããããšãMingun