<input type="button" value="increase 1" id="J-increase" /> <span id="J-count"></span>js:
<script> var bindDate = {count: 1,appy: function () { document.querySelector("#J-count").innerHTML = this.count;},increase: function () { var _this = this; document.querySelector("#J-increase").addEventListener("click", function () {_this.count++;appy(); }, true);},initialize: function () {// 初始化 this.appy();// this.increase(); }};bindDate.initialize(); </script>在上面的例子中,存在两个过程:// 对angular里面的源码进行了精简$watch: function(watchExp, listener, objectEquality) {var scope = this, array = scope.$$watchers,watcher = {fn: listener,last: initWatchVal, get: get, exp: watchExp,eq: !!objectEquality};if (!array) { array = scope.$$watchers = []; }array.unshift(watcher); }第二步. dirty-check:就是当有某个scope作用域下的数据发生变化后,需要遍历检测注册的$$watchers = [...] $digest: function() { while (length--) { watch = watchers[length];watch.fn(value, lastValue, scope); } }这样就实现了数据的双向绑定,上面的实现是否跟自定义事件很像呢?可以看到使用了观察者设计模式或(publisher-subscriber)。 function Car() { ...} Car.prototype = { run: function () {...}} function Benz() { var cat = new Car(); }Benz.prototype = {...} 在上面的例子中,类Benz依赖于类Car,直接通过内部New来解决这种依赖关系。这样做的弊端非常明显,代码耦合性变高,不利于维护。后端框架很早就意识到了这个问题,spring早期通过在xml文件中注册对象之间的依赖关系,后来有通过anotation的方式更加方便地解决DI问题,COS端的同学可以看看后端的代码。 // 注解的模拟 function annotate(fn, strictDi, name) { var $inject; if (!($inject = fn.$inject)) {$inject = [];$inject.push(name); }else if (isArray(fn)) {$inject = fn.slice(0, last); }return $inject; } createInjector.$$annotate = annotate;2. 注入对象的创建 function createInjector(modulesToLoad, strictDi) {//通过singleton模式创建对象var providerCache = {$provide: {provider: supportObject(provider),factory: supportObject(factory),service: supportObject(service),value: supportObject(value),constant: supportObject(constant), decorator: decorator } },instanceCache = {},instanceInjector = (instanceCache.$injector =createInternalInjector(instanceCache, function(serviceName, caller) {var provider = providerInjector.get(serviceName + providerSuffix, caller); return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);})); return instanceInjector; }3. 获取注入对象function invoke(fn, self, locals, serviceName) { var args = [],$inject = annotate(fn, strictDi, serviceName); for (...) {key = $inject[i]; // 替换成依赖的对象 args.push( locals && locals.hasOwnProperty(key) ? locals[key]: getService(key, serviceName) ); }if (isArray(fn)) {fn = fn[length];} return fn.apply(self, args);} 到这里,是否是看到很多后端框架设计的思路,没有anotation就模拟一个,难怪PPK要说angular是" a front-end framework by non-front-enders for non-front-enders" //controller1app.controller("controller1", function ($rootScope) { $rootScope.$on("eventType", function (arg) {......}) })// controller2app.controller("controller2", function ($rootScope) { $rootScope.$emit("eventType",arg); or$rootScope.$broadcast("eventType",arg); }) 2.通过service: 充分利用angular的DI特性,利用service是单例的特点,在不同controller之间起到桥梁作用// 注册serviceapp.service("Message", function () { return {count: void(0); } }) // controller1,修改service的count值app.controller("controller1", function ($scope, Message) {$scope.count = 1; Message.count = $scope.count;}); // controller2, 获取service的count值app.controller("controller2", function ($scope, Message) {$scope.num = Message.count; });4.service的特点
本文涉及的内容还不是很全民,之后还会有相应补充,希望大家也可以对angular框架进行学习探讨。