angular源码学习第一篇 setupModuleLoader方法,angularasyncloader

angular源码其实结构非常清晰,划分的有条有理的,大概就是这样子:

angular源码学习第一篇 setupModuleLoader方法,angularasyncloader

angular源码其实结构非常清晰,划分的有条有理的,大概就是这样子:

(function(window,document,jquery,undefined){
 //一些工具函数
 //EXPR 编译器 自执行
 //setupModuleLoader方法,公司内部的框架是vxsetup方法,(只是定义,没有调用)
 //moduler方法()
 //angular初始化方法,公司内部的框架是vxinit方法
 //bootstrap
 //createInjector
 //一系列指令,服务,过滤器等指令
})(window,document,window.$)

其实阅读angular源码重要的是angular的整个架构思路,至于服务过滤器和指令可以先抛开。

setupModuleLoader方法写的有点复杂,尤其是直接三层闭包,如果逆着看,容易糊涂,还是顺着思路走比较容易。

首先是,我希望当我运行angualr的时候,可以在window下面创建一个angular属性。这个angualr是一个对象,可以用来创建一个module。于是产生了下面的代码:

function setupModuleLoader(window){

    //ensure方法比较通俗易懂,网上也很多解释。由此看来,window.angular这个对象是个单例的。

  var ensure=function(obj,name,factory){
    return obj[name]||(obj[name]=factory())
  }

  var angular = ensure(window,'angular',Object);

    //createModule方法是用来创建一个module实例的。
  var createModule = function(name,requires){
    var moduleInstance = {
      name:name,
            requires:requires
    };
    return moduleInstance;
  }
    //window.angular.module方法实际运行的是createModule方法,这个闭包只是为了保护一下变量(现在是简化版,变量还没有加)。
    //其实要给一个对象增加一个方法,在angular中经常使用ensure函数,传一个工厂函数,这样的好处是整齐并且保护作用域。
  ensure(angular,'module',function(){
    return function(name,requires){
      return createModule(name,requires)
    }
  })

} 

现在看起来这个angular.module方法就是这样了。这是注册的方法。

众所周知的是,angular.module(‘myapp’,[])这段代码是注册一个module,如果不传后面的第二个参数,就是取回一个app。

然而目前上面写的代码并没有取回一个module的功能。所以需要完善一下:

function setupModuleLoader(window){
  var ensure=function(obj,name,factory){
    return obj[name]||(obj[name]=factory())
  }
    //增加一个对象,用于存放每一个注册过的module,其实在angular里面,这个对象也是存在的
    //当然,这个modules对象的位置是在下面ensure(angular,'module',fn)的fn工厂函数里,这样放在闭包里就可以杜绝外界访问
    //如果你改一下angular的源码,把这个对象强行获取到,比如设置window.modulebox = modules;然后再去打印这个modulebox来看,你会发现所有注册的modules都能看到。
    //我放到这里是因为以后方便调试。我可以随时看到modules里面都有什么东西。但是其实不影响的。
    var modules={}

  var angular = ensure(window,'angular',Object);

  var createModule = function(name,requires,modules){
    var moduleInstance = {
      name:name
    };
        modules[name]=moduleInstance;//每注册一个module的时候都把这个module按照相应名称存入modules对象。
    return moduleInstance;
  }

  ensure(angular,'module',function(){
    return function(name,requires){
      if(requires){
        return createModule(name,requires,modules)//增加了一个参数,就是modules这个对象。
      }else{
        return getModule(name,modules);//这个getModule方法虽然还没定义,但是这一段代码看起来确实很明白了。g
      }
    }
  })
}

现在OK了,可以注册一个module也可以获取一个module了。至于getModules就是根据名称从modules对象中取出一个module,就不写了。

其实简化下来的setupModuleLoader就是这样,挺清晰的。

setupModuleLoader方法真正开始变的复杂是从它与injector的配合开始。

setupModuleLoader方法先放到这儿,下一篇分析一下injector方法。然后回过头来在搞setupModuleLoader。

看看他们是怎么配合的。

重要的是,injector这个东西一定要先理解透彻,同时$provider我希望看到这篇博客的你(当然也包括我)能够理解透彻。

这样的话会很容易搞懂angularJs。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持帮客之家。

setupModuleLoader方法,angularasyncloader
angular源码其实结构非常清晰,划分的有条有理的,大概就是这样子:
(function(wind…

首先贴出ng-click实现的源码,我做了一些注释

angular中提供了forEach()方法用于遍历对象或数组,供大家参考,具体内容如下

angular forEach方法遍历源码解读,angularforeach

angular中提供了forEach()方法用于遍历对象或数组,供大家参考,具体内容如下

function forEach(obj, iterator, context) {
 var key, length;
 if (obj) {
  if (isFunction(obj)) {
   for (key in obj) {
    // Need to check if hasOwnProperty exists,
    // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
    if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  } else if (isArray(obj) || isArrayLike(obj)) {
   var isPrimitive = typeof obj !== 'object';
   for (key = 0, length = obj.length; key < length; key++) {
    if (isPrimitive || key in obj) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  } else if (obj.forEach && obj.forEach !== forEach) {
    obj.forEach(iterator, context, obj);
  } else if (isBlankObject(obj)) {
   // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
   for (key in obj) {
    iterator.call(context, obj[key], key, obj);
   }
  } else if (typeof obj.hasOwnProperty === 'function') {
   // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
   for (key in obj) {
    if (obj.hasOwnProperty(key)) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  } else {
   // Slow path for objects which do not have a method `hasOwnProperty`
   for (key in obj) {
    if (hasOwnProperty.call(obj, key)) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  }
 }
 return obj;
}

官方描述:

forEach方法可以遍历数组或对象,函数有三个参数为别为:value,key,obj。
1)、value value指当遍历的对象或数组元素当前的值
2)、 key 是对象属性的的key或者数组的索引
3)、 obj obj即被遍历的对象或数组本身

示例:

   var values = {name: 'misko', gender: 'male'};
   var log = [];
   angular.forEach(values, function(value, key) {
    this.push(key + ': ' + value);
   }, log);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持帮客之家。

forEach方法遍历源码解读,angularforeach
angular中提供了forEach()方法用于遍历对象或数组,供大家参考,具体内容如下
function forEach(obj,…

(function(window,document,jquery,undefined){
 //一些工具函数
 //EXPR 编译器 自执行
 //setupModuleLoader方法,公司内部的框架是vxsetup方法,(只是定义,没有调用)
 //moduler方法()
 //angular初始化方法,公司内部的框架是vxinit方法
 //bootstrap
 //createInjector
 //一系列指令,服务,过滤器等指令
})(window,document,window.$)
forEach(//依次生成ng-click/ng-dblclick...
  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
  function(eventName) {//@eventName 'click'
    var directiveName = directiveNormalize('ng-' + eventName);//将'ng-click'转化成'ngClick'
    //得到全局变量ngEventDirectives,用于生成directive
    ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
      //知道directive就知道这是干嘛的,不知道的可以先搜一下directive
      return {
        restrict: 'A',
        compile: function($element, attr) {
          // 根据ng-click中的表达式转换成一个function fn,关于$parse服务的详细说明下面会提一下
          var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
          return function ngEventHandler(scope, element) {
            //绑定click事件
            element.on(eventName, function(event) {
              var callback = function() {
                fn(scope, {$event:event});
              };
              //forceAsyncEvents={'blur':true,'focus':true}
              // 如果是blur,focus事件则异步调用【个人认为是为了响应流畅,有其它见解请不吝赐教】
              if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
                scope.$evalAsync(callback);
              } else {
                scope.$apply(callback);
              }
            });
          };
        }
      };
    }];
  }
);
function forEach(obj, iterator, context) {
 var key, length;
 if (obj) {
  if (isFunction(obj)) {
   for (key in obj) {
    // Need to check if hasOwnProperty exists,
    // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
    if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  } else if (isArray(obj) || isArrayLike(obj)) {
   var isPrimitive = typeof obj !== 'object';
   for (key = 0, length = obj.length; key < length; key++) {
    if (isPrimitive || key in obj) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  } else if (obj.forEach && obj.forEach !== forEach) {
    obj.forEach(iterator, context, obj);
  } else if (isBlankObject(obj)) {
   // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
   for (key in obj) {
    iterator.call(context, obj[key], key, obj);
   }
  } else if (typeof obj.hasOwnProperty === 'function') {
   // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
   for (key in obj) {
    if (obj.hasOwnProperty(key)) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  } else {
   // Slow path for objects which do not have a method `hasOwnProperty`
   for (key in obj) {
    if (hasOwnProperty.call(obj, key)) {
     iterator.call(context, obj[key], key, obj);
    }
   }
  }
 }
 return obj;
}

其实阅读angular源码重要的是angular的整个架构思路,至于服务过滤器和指令可以先抛开。

只要听说过angular的service,directive理解起来没什么问题
根据它很容易写出监听其它事件的directive

官方描述:

setupModuleLoader方法写的有点复杂,尤其是直接三层闭包,如果逆着看,容易糊涂,还是顺着思路走比较容易。

.directive('ngTap', ['$parse',function($parse) {
  return {
   restrict: 'A',
   compile: function($element, attr) {
    var fn = $parse(attr["ngTap"]);
    return function ngEventHandler(scope, element) {
     element.on('tap', function(event) {
      var callback = function() {
       fn(scope, {
        $event: event
       });
      };
      scope.$apply(callback);
     });
    };
   }
  };
 }])

forEach方法可以遍历数组或对象,函数有三个参数为别为:value,key,obj。
1)、value value指当遍历的对象或数组元素当前的值
2)、 key 是对象属性的的key或者数组的索引
3)、 obj obj即被遍历的对象或数组本身

首先是,我希望当我运行angualr的时候,可以在window下面创建一个angular属性。这个angualr是一个对象,可以用来创建一个module。于是产生了下面的代码:

这里主要提一下$parse服务
例子

示例:

function setupModuleLoader(window){

    //ensure方法比较通俗易懂,网上也很多解释。由此看来,window.angular这个对象是个单例的。

  var ensure=function(obj,name,factory){
    return obj[name]||(obj[name]=factory())
  }

  var angular = ensure(window,'angular',Object);

    //createModule方法是用来创建一个module实例的。
  var createModule = function(name,requires){
    var moduleInstance = {
      name:name,
            requires:requires
    };
    return moduleInstance;
  }
    //window.angular.module方法实际运行的是createModule方法,这个闭包只是为了保护一下变量(现在是简化版,变量还没有加)。
    //其实要给一个对象增加一个方法,在angular中经常使用ensure函数,传一个工厂函数,这样的好处是整齐并且保护作用域。
  ensure(angular,'module',function(){
    return function(name,requires){
      return createModule(name,requires)
    }
  })

} 
  • $parse
   var values = {name: 'misko', gender: 'male'};
   var log = [];
   angular.forEach(values, function(value, key) {
    this.push(key + ': ' + value);
   }, log);

现在看起来这个angular.module方法就是这样了。这是注册的方法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

众所周知的是,angular.module(‘myapp’,[])这段代码是注册一个module,如果不传后面的第二个参数,就是取回一个app。

  • 作用:将一个AngularJS表达式转换成一个函数

您可能感兴趣的文章:

  • angular.foreach
    循环方法使用指南
  • AngularJS ng-repeat指令中使用track
    by子语句解决重复数据遍历错误问题
  • Angular
    ng-repeat遍历渲染完页面后执行其他操作详细介绍
  • Angular ng-repeat
    对象和数组遍历实例
  • AngularJS入门(用ng-repeat指令实现循环输出
  • angular.element方法汇总
  • angularJS中$apply()方法详解
  • 使用AngularJS来实现HTML页面嵌套的方法
  • angularjs
    处理多个异步请求方法汇总
  • 解决angular的$http.post()提交数据时后台接收不到参数值问题的方法

然而目前上面写的代码并没有取回一个module的功能。所以需要完善一下:

function setupModuleLoader(window){
  var ensure=function(obj,name,factory){
    return obj[name]||(obj[name]=factory())
  }
    //增加一个对象,用于存放每一个注册过的module,其实在angular里面,这个对象也是存在的
    //当然,这个modules对象的位置是在下面ensure(angular,'module',fn)的fn工厂函数里,这样放在闭包里就可以杜绝外界访问
    //如果你改一下angular的源码,把这个对象强行获取到,比如设置window.modulebox = modules;然后再去打印这个modulebox来看,你会发现所有注册的modules都能看到。
    //我放到这里是因为以后方便调试。我可以随时看到modules里面都有什么东西。但是其实不影响的。
    var modules={}

  var angular = ensure(window,'angular',Object);

  var createModule = function(name,requires,modules){
    var moduleInstance = {
      name:name
    };
        modules[name]=moduleInstance;//每注册一个module的时候都把这个module按照相应名称存入modules对象。
    return moduleInstance;
  }

  ensure(angular,'module',function(){
    return function(name,requires){
      if(requires){
        return createModule(name,requires,modules)//增加了一个参数,就是modules这个对象。
      }else{
        return getModule(name,modules);//这个getModule方法虽然还没定义,但是这一段代码看起来确实很明白了。g
      }
    }
  })
}
  • Usage

现在OK了,可以注册一个module也可以获取一个module了。至于getModules就是根据名称从modules对象中取出一个module,就不写了。

其实简化下来的setupModuleLoader就是这样,挺清晰的。

  • $parse(expression)

setupModuleLoader方法真正开始变的复杂是从它与injector的配合开始。

setupModuleLoader方法先放到这儿,下一篇分析一下injector方法。然后回过头来在搞setupModuleLoader。

  • arguments

看看他们是怎么配合的。

重要的是,injector这个东西一定要先理解透彻,同时$provider我希望看到这篇博客的你(当然也包括我)能够理解透彻。

  • expression:string,需要被编译的AngularJS语句,’::’开头表示当表达式的值为undefine时忽略拦截函数,直接返回undefined
  • interceptorFn:function,拦截函数,形式interceptorFn(value, scope,
    locals),value是表达式的值
  • expensiveCheck:bool,使用cacheExpensive并且做更多的检查,check if obj is Function that is fast and works across iframes and other contexts?

这样的话会很容易搞懂angularJs。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • return

您可能感兴趣的文章:

  • AngularJS动态生成div的ID源码解析
  • angularjs 源码解析之scope
  • angularjs
    源码解析之injector
  • Angular中$compile源码分析
  • angular.foreach
    循环方法使用指南
  • angular.element方法汇总
  • angularJS中$apply()方法详解
  • angularjs
    处理多个异步请求方法汇总
  • 使用AngularJS来实现HTML页面嵌套的方法
  • 解决angular的$http.post()提交数据时后台接收不到参数值问题的方法

  • returnsfunc(context, locals)
    • context[object]:针对你要解析的语句,这个对象中含有你要解析的语句中的表达式(通常是一个scope
      object)
    • locals[object]:
      关于context中变量的本地变量,对于覆盖context中的变量值很有用。
    • 返回的函数还有下面三个特性:
      • literal[boolean]:表达式的顶节点是否是一个javascript字面量
      • constant[boolean]:表达式是否全部是由javascript的常量字面量组成
      • assign[func(context,
        local)]:可以用来在给定的上下文中修改表达式的值

相关文章