angularjs 学习

/**
 * @license AngularJS v1.3.0-beta.15
 * (c) 2010-2014 Google, Inc. http://angularjs.org
 * License: MIT
 */
(function(window, document, undefined) {'use strict';

    /**
     * @description
     *
     * This object provides a utility for producing rich Error messages within
     * Angular. It can be called as follows:
     *当Angular在发生错误的时候,这个对象提供一个处理错误的工具类,它的调用方式如下:
     * 例如:
     * var exampleMinErr = minErr('example');
     * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
     *
     * The above creates an instance of minErr in the example namespace. The
     * resulting error will have a namespaced error code of example.one.  The
     * resulting error will replace {0} with the value of foo, and {1} with the
     * value of bar. The object is not restricted in the number of arguments it can
* take. *在上面的代码中,在example命名空间中创建了一个minErr的实例。错误的结果会在example, *里面生成一个错误码的example.one命名空间。这个错误的结果会用foo的值和bar的值, *来进行替换前面的点位符{0},{1}.这个对象不严格必须给定错误参数,因此错误参数可有可无。 * * If fewer arguments are specified than necessary for interpolation, the extra * interpolation markers will be preserved in the final string. *如果指定的错误对象中的错误参数,则它会保留在最终生成的字符串中。 * * Since data will be parsed statically during a build step, some restrictions * are applied with respect to how minErr instances are created and called. * Instances should have names of the form namespaceMinErr for a minErr created * using minErr('namespace') . Error codes, namespaces and template strings * should all be static strings, not variables or general expressions. *在编译阶段,错误参数中的数据会自己生成与解析,错误对象中的一些限制将会监视错误对象的 实例该如何被创建与如何被调用。 * * @param {string} module The namespace to use for the new minErr instance. * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
*/ //module:模板名称,将会用于新的错误对象的实例中 function minErr(module) { return function () {//直接进行返回操作 //获取错误参数中的错误标识符,如,上面示例中的one var code = arguments[0], //获取错误对象模板的前缀 prefix = '[' + (module ? module + ':' : '') + code + '] ', template = arguments[1], templateArgs = arguments, //这个属于偏置函数 stringify = function (obj) { if (typeof obj === 'function') {//如果参数是一个函数 //返回的结果,如:{'item in items '}-->'' return obj.toString().replace(/ \{[\s\S]*$/, ''); } else if (typeof obj === 'undefined') { return 'undefined'; } else if (typeof obj !== 'string') { return JSON.stringify(obj);//强制参数转换为Json的字符串形式 } return obj; }, message, i; message = prefix + template.replace(/\{\d+\}/g, function (match) { var index = +match.slice(1, -1), arg; if (index + 2 < templateArgs.length) { arg = templateArgs[index + 2]; if (typeof arg === 'function') { return arg.toString().replace(/ ?\{[\s\S]*$/, ''); } else if (typeof arg === 'undefined') { return 'undefined'; } else if (typeof arg !== 'string') { return toJson(arg); } return arg; } return match; }); message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.15/' + (module ? module + '/' : '') + code; for (i = 2; i < arguments.length; i++) { message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + encodeURIComponent(stringify(arguments[i])); } return new Error(message); }; } /* We need to tell jshint what variables are being exported */ /* global angular: true, msie: true, jqLite: true, jQuery: true, slice: true, push: true, toString: true, ngMinErr: true, angularModule: true, nodeName_: true, uid: true, REGEX_STRING_REGEXP: true, VALIDITY_STATE_PROPERTY: true, lowercase: true, uppercase: true, manualLowercase: true, manualUppercase: true, nodeName_: true, isArrayLike: true, forEach: true, sortedKeys: true, forEachSorted: true, reverseParams: true, nextUid: true, setHashKey: true, extend: true, int: true, inherit: true, noop: true, identity: true, valueFn: true, isUndefined: true, isDefined: true, isObject: true, isString: true, isNumber: true, isDate: true, isArray: true, isFunction: true, isRegExp: true, isWindow: true, isScope: true, isFile: true, isBlob: true, isBoolean: true, trim: true, isElement: true, makeMap: true, map: true, size: true, includes: true, indexOf: true, arrayRemove: true, isLeafNode: true, copy: true, shallowCopy: true, equals: true, csp: true, concat: true, sliceArgs: true, bind: true, toJsonReplacer: true, toJson: true, fromJson: true, startingTag: true, tryDecodeURIComponent: true, parseKeyValue: true, toKeyValue: true, encodeUriSegment: true, encodeUriQuery: true, angularInit: true, bootstrap: true, snake_case: true, bindJQuery: true, assertArg: true, assertArgFn: true, assertNotHasOwnProperty: true, getter: true, getBlockElements: true, hasOwnProperty: true, */ //////////////////////////////////// /** * @ngdoc module * @name ng * @module ng * @description * * # ng (core module) * The ng module is loaded by default when an AngularJS application is started. The module itself * contains the essential components for an AngularJS application to function. The table below * lists a high level breakdown of each of the services/factories, filters, directives and testing * components available within this core module. * * <div doc-module-components="ng"></div> * * ng模板默认在Angular应用程序启动的时候会被自动加载。这个模板包含了Angular应用程序运行所必须的组件。 * 下表列出了在这个核心的模块中所包含的服务/工厂,过滤器,指令和一些测试的组件 */ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; // The name of a form control's ValidityState property. // This is used so that it's possible for internal tests to create mock ValidityStates. var VALIDITY_STATE_PROPERTY = 'validity'; /** * @ngdoc function * @name angular.lowercase * @module ng * @kind function * * @description Converts the specified string to lowercase. * @param {string} string String to be converted to lowercase. * @returns {string} Lowercased string. */ //转换指定的字符串为小写 var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;}; var hasOwnProperty = Object.prototype.hasOwnProperty; /** * @ngdoc function * @name angular.uppercase * @module ng * @kind function * * @description Converts the specified string to uppercase. * @param {string} string String to be converted to uppercase. * @returns {string} Uppercased string. */ //转换指定的字符串为大写 var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;}; var manualLowercase = function(s) { /* jshint bitwise: false */ return isString(s) ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) : s; }; var manualUppercase = function(s) { /* jshint bitwise: false */ return isString(s) ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) : s; }; // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods // with correct but slower alternatives. if ('i' !== 'I'.toLowerCase()) { lowercase = manualLowercase; uppercase = manualUppercase; } var /** holds major version number for IE or NaN for real browsers */ msie, jqLite, // delay binding since jQuery could be loaded after us. jQuery, // delay binding slice = [].slice,//取出指定位置的数组数据 push = [].push,//把指定的数据放到数据里面 toString = Object.prototype.toString,//重写Object原型中的toString方法 ngMinErr = minErr('ng'),//定义一个全局的错误对象,对应的错误参数为,ng /** @name angular */ //判断系统是否注册了angular应用程序,如果没有注册则注册angular应用程序的为空对象 angular = window.angular || (window.angular = {}), angularModule, nodeName_, uid = 0; /** * IE 11 changed the format of the UserAgent string. * See http://msdn.microsoft.com/en-us/library/ms537503.aspx */ //判断浏览器的类型 msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); if (isNaN(msie)) { msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); } /** * @private * @param {*} obj * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, * String ...) */ //判断传入的对象obj是否是数组或有类似数组的行为,它可以是json字符串或数组 function isArrayLike(obj) { if (obj == null || isWindow(obj)) {//为空或window对象,则返回false return false; } var length = obj.length;//获取数组的长度 if (obj.nodeType === 1 && length) {//判断obj的节点类型,如果为元素,则返回true return true; } return isString(obj) || isArray(obj) || length === 0 || typeof length === 'number' && length > 0 && (length - 1) in obj; } /** * @ngdoc function * @name angular.forEach * @module ng * @kind function * * @description * Invokes the `iterator` function once for each item in `obj` collection, which can be either an * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value` * is the value of an object property or an array element and `key` is the object property key or * array element index. Specifying a `context` for the function is optional. * * It is worth noting that `.forEach` does not iterate over inherited properties because it filters * using the `hasOwnProperty` method. * ```js var values = {name: 'misko', gender: 'male'}; var log = []; angular.forEach(values, function(value, key) { this.push(key + ': ' + value); }, log); expect(log).toEqual(['name: misko', 'gender: male']); ``` * * @param {Object|Array} obj Object to iterate over.//可以是一个对象或一个数组 * @param {Function} iterator Iterator function.//迭代器是一个函数 * @param {Object=} context Object to become context (`this`) for the iterator function.//这个对象是一个上下文对象充当this的角色 * @returns {Object|Array} Reference to `obj`. */ //其中context可选参数,iterator是一个迭代器,它是一个函数 //它不能获取的继承的属性,因为程序中用hasOwnProperty来过滤了 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); } } } else if (isArray(obj) || isArrayLike(obj)) { for (key = 0, length = obj.length; key < length; key++) { iterator.call(context, obj[key], key); } } else if (obj.forEach && obj.forEach !== forEach) { obj.forEach(iterator, context); } else { for (key in obj) { if (obj.hasOwnProperty(key)) { iterator.call(context, obj[key], key); } } } } return obj; } function sortedKeys(obj) {//按照键来排序 var keys = []; for (var key in obj) { if (obj.hasOwnProperty(key)) { keys.push(key); } } return keys.sort();//采用数组默认的排序方式 } function forEachSorted(obj, iterator, context) {//先按照键排序,然后再遍历|迭代 var keys = sortedKeys(obj); for ( var i = 0; i < keys.length; i++) { iterator.call(context, obj[keys[i]], keys[i]); } return keys; } /** * when using forEach the params are value, key, but it is often useful to have key, value. * @param {function(string, *)} iteratorFn * @returns {function(*, string)} */ function reverseParams(iteratorFn) { return function(value, key) { iteratorFn(key, value); }; } /** * A consistent way of creating unique IDs in angular. * * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before * we hit number precision issues in JavaScript. * * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M * * @returns {number} an unique alpha-numeric string */ function nextUid() {//生成一个常量,它在andular里面是唯一的 return ++uid; } /** * Set or clear the hashkey for an object. * @param obj object//参数是一个对象 * @param h the hashkey (!truthy to delete the hashkey) */ function setHashKey(obj, h) { if (h) {//如果存在就设置 obj.$$hashKey = h; } else {//如果不存在则删除 delete obj.$$hashKey; } } /** * @ngdoc function * @name angular.extend * @module ng * @kind function * * @description * Extends the destination object `dst` by copying all of the properties from the `src` object(s) * to `dst`. You can specify multiple `src` objects. * * @param {Object} dst Destination object.//最终的对象 * @param {...Object} src Source object(s).//源对象 * @returns {Object} Reference to `dst`.//返回最终的对象 */ function extend(dst) {//在javascript中实现继承 var h = dst.$$hashKey; forEach(arguments, function(obj) {//这里采用拷贝属性的方式实现继承 if (obj !== dst) { forEach(obj, function(value, key) { dst[key] = value; }); } }); setHashKey(dst,h); return dst; } function int(str) {//转换为整形 return parseInt(str, 10); } function inherit(parent, extra) {//继承 return extend(new (extend(function() {}, {prototype:parent}))(), extra); } /** * @ngdoc function * @name angular.noop * @module ng * @kind function * * @description * A function that performs no operations. This function can be useful when writing code in the * functional style. ```js function foo(callback) { var result = calculateResult(); (callback || angular.noop)(result); } ``` */ function noop() {}//在写样式代码的时候会被用到 noop.$inject = []; /** * @ngdoc function * @name angular.identity * @module ng * @kind function * * @description * A function that returns its first argument. This function is useful when writing code in the * functional style. * ```js function transformer(transformationFn, value) { return (transformationFn || angular.identity)(value); }; ``` */ function identity($) {return $;}//在写样式代码的时候会被用到//定义angular的标识 identity.$inject = []; function valueFn(value) {return function() {return value;};} /** * @ngdoc function * @name angular.isUndefined * @module ng * @kind function * * @description * Determines if a reference is undefined. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is undefined. */ function isUndefined(value){return typeof value === 'undefined';} /** * @ngdoc function * @name angular.isDefined * @module ng * @kind function * * @description * Determines if a reference is defined. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is defined. */ function isDefined(value){return typeof value !== 'undefined';} /** * @ngdoc function * @name angular.isObject * @module ng * @kind function * * @description * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not * considered to be objects. Note that JavaScript arrays are objects. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Object` but not `null`. */ function isObject(value){return value != null && typeof value === 'object';} /** * @ngdoc function * @name angular.isString * @module ng * @kind function * * @description * Determines if a reference is a `String`. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `String`. */ function isString(value){return typeof value === 'string';} /** * @ngdoc function * @name angular.isNumber * @module ng * @kind function * * @description * Determines if a reference is a `Number`. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Number`. */ function isNumber(value){return typeof value === 'number';} /** * @ngdoc function * @name angular.isDate * @module ng * @kind function * * @description * Determines if a value is a date. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Date`. */ function isDate(value) { return toString.call(value) === '[object Date]'; } /** * @ngdoc function * @name angular.isArray * @module ng * @kind function * * @description * Determines if a reference is an `Array`. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Array`. */ var isArray = (function() { if (!isFunction(Array.isArray)) { return function(value) { return toString.call(value) === '[object Array]'; }; } return Array.isArray; })(); /** * @ngdoc function * @name angular.isFunction * @module ng * @kind function * * @description * Determines if a reference is a `Function`. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Function`. */ function isFunction(value){return typeof value === 'function';} /** * Determines if a value is a regular expression object. * * @private * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `RegExp`. */ function isRegExp(value) { return toString.call(value) === '[object RegExp]'; } /** * Checks if `obj` is a window object. * * @private * @param {*} obj Object to check * @returns {boolean} True if `obj` is a window obj. */ function isWindow(obj) { return obj && obj.window === obj; } function isScope(obj) { return obj && obj.$evalAsync && obj.$watch; } function isFile(obj) { return toString.call(obj) === '[object File]'; } function isBlob(obj) { return toString.call(obj) === '[object Blob]'; } function isBoolean(value) { return typeof value === 'boolean'; } var trim = (function() { // native trim is way faster: http://jsperf.com/angular-trim-test // but IE doesn't have it... :-( // TODO: we should move this into IE/ES5 polyfill if (!String.prototype.trim) { return function(value) { return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value; }; } return function(value) { return isString(value) ? value.trim() : value; }; })(); /** * @ngdoc function * @name angular.isElement * @module ng * @kind function * * @description * Determines if a reference is a DOM element (or wrapped jQuery element). * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element). */ function isElement(node) { return !!(node && (node.nodeName // we are a direct element || (node.prop && node.attr && node.find))); // we have an on and find method part of jQuery API } /** * @param str 'key1,key2,...' * @returns {object} in the form of {key1:true, key2:true, ...} */ function makeMap(str) { var obj = {}, items = str.split(","), i; for ( i = 0; i < items.length; i++ ) obj[ items[i] ] = true; return obj; } if (msie < 9) { nodeName_ = function(element) { element = element.nodeName ? element : element[0]; return lowercase( (element.scopeName && element.scopeName != 'HTML') ? element.scopeName + ':' + element.nodeName : element.nodeName ); }; } else { nodeName_ = function(element) { return lowercase(element.nodeName ? element.nodeName : element[0].nodeName); }; } function map(obj, iterator, context) { var results = []; forEach(obj, function(value, index, list) { results.push(iterator.call(context, value, index, list)); }); return results; } /** * @description * Determines the number of elements in an array, the number of properties an object has, or * the length of a string. * * Note: This function is used to augment the Object type in Angular expressions. See * {@link angular.Object} for more information about Angular arrays. * * @param {Object|Array|string} obj Object, array, or string to inspect. * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array. */ function size(obj, ownPropsOnly) { var count = 0, key; if (isArray(obj) || isString(obj)) { return obj.length; } else if (isObject(obj)) { for (key in obj) if (!ownPropsOnly || obj.hasOwnProperty(key)) count++; } return count; } function includes(array, obj) { return indexOf(array, obj) != -1; } function indexOf(array, obj) { if (array.indexOf) return array.indexOf(obj); for (var i = 0; i < array.length; i++) { if (obj === array[i]) return i; } return -1; } function arrayRemove(array, value) { var index = indexOf(array, value); if (index >=0) array.splice(index, 1); return value; } function isLeafNode (node) { if (node) { switch (nodeName_(node)) { case "option": case "pre": case "title": return true; } } return false; } /** * @ngdoc function * @name angular.copy * @module ng * @kind function * * @description * Creates a deep copy of `source`, which should be an object or an array. *创建一个深拷贝的源,它可以是一个对象或一个数组 * * If no destination is supplied, a copy of the object or array is created * 如果未指定dest,对象或数组的一个副本会被创建 * * If a destination is provided, all of its elements (for array) or properties (for objects) * are deleted and then all elements/properties from the source are copied to it. * 如果指定了它的dest,则它的所有属性或元素将会被删除,并且它的所有元素或属性将会从源里面拷贝出来。 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. * 如果源不是一个对象或数组,则操作会立即停止执行 * * If `source` is identical to 'destination' an exception will be thrown. *如果源被标识为一个dest,则会抛出一个异常 * @param {*} source The source that will be used to make a copy.//源,进行拷贝的参照对象,可以是任意类型 * Can be any type, including primitives, `null`, and `undefined`. * @param {(Object|Array)=} destination Destination into which the source is copied. If * provided, must be of the same type as `source`.//参数为一个对象或数组,如果被提供,则必须与源的类型相同 * @returns {*} The copy or updated `destination`, if `destination` was specified. * 如果dest被指定的话,则更新dest;如果dest未被指定的话,是返回源的拷贝副本。 * * @example <example module="copyExample"> <file name="index.html"> <div ng-controller="ExampleController"> <form novalidate class="simple-form"> Name: <input type="text" ng-model="user.name" /><br /> E-mail: <input type="email" ng-model="user.email" /><br /> Gender: <input type="radio" ng-model="user.gender" value="male" />male <input type="radio" ng-model="user.gender" value="female" />female<br /> <button ng-click="reset()">RESET</button> <button ng-click="update(user)">SAVE</button> </form> <pre>form = {{user | json}}</pre>//user是一个json对象 <pre>master = {{master | json}}</pre>master是一个json对象 </div> <script> angular.module('copyExample') .controller('ExampleController', ['$scope', function($scope) {//$scope默认会被注入 $scope.master= {}; $scope.update = function(user) { // Example with 1 argument $scope.master= angular.copy(user); }; $scope.reset = function() { // Example with 2 arguments angular.copy($scope.master, $scope.user); }; $scope.reset(); }]); </script> </file> </example> */ function copy(source, destination, stackSource, stackDest) { if (isWindow(source) || isScope(source)) { throw ngMinErr('cpws', "Can't copy! Making copies of Window or Scope instances is not supported."); } if (!destination) {//如果指定dest destination = source; if (source) { if (isArray(source)) { destination = copy(source, [], stackSource, stackDest); } else if (isDate(source)) { destination = new Date(source.getTime()); } else if (isRegExp(source)) { destination = new RegExp(source.source); } else if (isObject(source)) { var emptyObject = Object.create(Object.getPrototypeOf(source)); destination = copy(source, emptyObject, stackSource, stackDest); } } } else {//如果不指定dest if (source === destination) throw ngMinErr('cpi', "Can't copy! Source and destination are identical."); stackSource = stackSource || []; stackDest = stackDest || []; if (isObject(source)) { var index = indexOf(stackSource, source); if (index !== -1) return stackDest[index]; stackSource.push(source); stackDest.push(destination); } var result; if (isArray(source)) { destination.length = 0; for ( var i = 0; i < source.length; i++) { result = copy(source[i], null, stackSource, stackDest); if (isObject(source[i])) { stackSource.push(source[i]); stackDest.push(result); } destination.push(result); } } else { var h = destination.$$hashKey; forEach(destination, function(value, key) { delete destination[key]; }); for ( var key in source) { if(source.hasOwnProperty(key)) { result = copy(source[key], null, stackSource, stackDest); if (isObject(source[key])) { stackSource.push(source[key]); stackDest.push(result); } destination[key] = result; } } setHashKey(destination,h); } } return destination; } /** * Creates a shallow copy of an object, an array or a primitive * 创建一个浅副本,可以是一个数组或一个原始数据 */ function shallowCopy(src, dst) { var i = 0; if (isArray(src)) { dst = dst || []; for (; i < src.length; i++) { dst[i] = src[i]; } } else if (isObject(src)) { dst = dst || {}; var keys = Object.keys(src); for (var l = keys.length; i < l; i++) { var key = keys[i]; if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { dst[key] = src[key]; } } } return dst || src; } /** * @ngdoc function * @name angular.equals * @module ng * @kind function * * @description * Determines if two objects or two values are equivalent. Supports value types, regular * expressions, arrays and objects. * * Two objects or values are considered equivalent if at least one of the following is true: * * * Both objects or values pass `===` comparison. * * Both objects or values are of the same type and all of their properties are equal by * comparing them with `angular.equals`. * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) * * Both values represent the same regular expression (In JavaScript, * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual * representation matches). * * During a property comparison, properties of `function` type and properties with names * that begin with `$` are ignored. * * Scope and DOMWindow objects are being compared only by identify (`===`). * * @param {*} o1 Object or value to compare. * @param {*} o2 Object or value to compare. * @returns {boolean} True if arguments are equal. */ function equals(o1, o2) { if (o1 === o2) return true; if (o1 === null || o2 === null) return false; if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN var t1 = typeof o1, t2 = typeof o2, length, key, keySet; if (t1 == t2) { if (t1 == 'object') { if (isArray(o1)) { if (!isArray(o2)) return false; if ((length = o1.length) == o2.length) { for(key=0; key<length; key++) { if (!equals(o1[key], o2[key])) return false; } return true; } } else if (isDate(o1)) { return isDate(o2) && o1.getTime() == o2.getTime(); } else if (isRegExp(o1) && isRegExp(o2)) { return o1.toString() == o2.toString(); } else { if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false; keySet = {}; for(key in o1) { if (key.charAt(0) === '$' || isFunction(o1[key])) continue; if (!equals(o1[key], o2[key])) return false; keySet[key] = true; } for(key in o2) { if (!keySet.hasOwnProperty(key) && key.charAt(0) !== '$' && o2[key] !== undefined && !isFunction(o2[key])) return false; } return true; } } } return false; } function csp() { return (document.securityPolicy && document.securityPolicy.isActive) || (document.querySelector && !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]'))); } function concat(array1, array2, index) { return array1.concat(slice.call(array2, index));//连接两个数组,call(obj,具体的参数) } //分割指定位置的数组数据 function sliceArgs(args, startIndex) { return slice.call(args, startIndex || 0);//[].splice } /* jshint -W101 */ /** * @ngdoc function * @name angular.bind * @module ng * @kind function * * @description * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for * `fn`). You can supply optional `args` that are prebound to the function. This feature is also * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application). *当调用fn函数时,bn会被绑定到self,其中,self相当于this的作用。可以指定args参数绑定到预先形成的函数中。 * 返回一个函数的调用 * @param {Object} self Context which `fn` should be evaluated in.//一个上下文对象 * @param {function()} fn Function to be bound.//一个函数,它将会被绑定到self对象中 * @param {...*} args Optional arguments to be prebound to the `fn` function call.//可选参数将会被绑定到fn函数中 * @returns {function()} Function that wraps the `fn` with all the specified bindings. */ /* jshint +W101 */ function bind(self, fn) { //判断可选参数是否被提供,如果被提供则为sliceArg(argumentts,2),如果未被提供则为空数组,[] var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : []; if (isFunction(fn) && !(fn instanceof RegExp)) {//如果fn是一个函数 return curryArgs.length//判断可选参数是否被提供 ? function() { return arguments.length ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))//如果可选参数被提供,则把可选参数绑定到self中 : fn.apply(self, curryArgs);//如果可选参数未被提供,则返回self本身 } : function() { return arguments.length ? fn.apply(self, arguments) : fn.call(self); }; } else { // in IE, native methods are not functions so they cannot be bound (note: they don't need to be) return fn;//在IE里面没有这些函数,所以绑定不了,直接返回fn函数 } } function toJsonReplacer(key, value) { var val = value; if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') { val = undefined; } else if (isWindow(value)) { val = '$WINDOW'; } else if (value && document === value) { val = '$DOCUMENT'; } else if (isScope(value)) { val = '$SCOPE'; } return val; } /** * @ngdoc function * @name angular.toJson * @module ng * @kind function * * @description * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be * stripped since angular uses this notation internally. * * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace. * @returns {string|undefined} JSON-ified string representing `obj`. */ //把指定的对象转换成json字符串,并把json字符串里面的值 替换成与之相对应的对象,如:$$scope,$widnow,$document function toJson(obj, pretty) { if (typeof obj === 'undefined') return undefined; return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null); } /** * @ngdoc function * @name angular.fromJson * @module ng * @kind function * * @description * Deserializes a JSON string. * * @param {string} json JSON string to deserialize.//一个json字符串 * @returns {Object|Array|string|number} Deserialized thingy.,返回一个数组,对象 */ function fromJson(json) {// return isString(json) ? JSON.parse(json) : json; } /** * @returns {string} Returns the string representation of the element. */ function startingTag(element) {//查找angular的ng指令,如ngapp,ngrepeat,ngswitch etc. element = jqLite(element).clone();//克隆element元素 try { // turns out IE does not let you set .html() on elements which // are not allowed to have children. So we just ignore it. element.empty();//IE不允许用设置.html()设置元素,也就是说不允许有子元素,因此置为空 } catch(e) {} // As Per DOM Standards var TEXT_NODE = 3;//标准的文节点 var elemHtml = jqLite('<div>').append(element).html();//把div标签添加到新克隆出来的element上,并获取现在的值 try { return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) : elemHtml. match(/^(<[^>]+>)/)[1].//正则表达式表示的示例内容如,<div ng-app='myModule'> //正则:/^<([\w\-]+)/,表示的示例内容,如:<div ng-app='myModule'>, // 正则:([\w\-]+),表示的示例内容如,ng-app,由此看来,angular在html里面写的内容必须是:标准的Html文内容 replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });//<ng-app } catch(e) { return lowercase(elemHtml);//如果不是上面的情况,慢把新取出的值直接返回 } } ///////////////////////////////////////////////// /** * Tries to decode the URI component without throwing an exception. *调试解码URI组件,不抛出异常 * @private 为私有方法 * @param str value potential URI component to check.//str是URI组件需要检查的内容 * @returns {boolean} True if `value` can be decoded,如果str被正常的解析,则返回true * with the decodeURIComponent function. */ function tryDecodeURIComponent(value) { try { return decodeURIComponent(value); } catch(e) { // Ignore any invalid uri component//忽略任何无效的URI组件内容 } } /** * Parses an escaped url query string into key-value pairs.// * 解析一个转义的url查询字符串为键值对形式 * @returns {Object.<string,boolean|Array>}//返回Object.字符串/boolean,数组 */ function parseKeyValue(/**string*/keyValue) { var obj = {}, key_value, key; //keyvalue的内容示例如,http://www.baidu.com?search=angular&date=20141215,结果为:search:angular,date:20141215 forEach((keyValue || "").split('&'), function(keyValue) { if ( keyValue ) { key_value = keyValue.split('='); key = tryDecodeURIComponent(key_value[0]); if ( isDefined(key) ) { var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; if (!hasOwnProperty.call(obj, key)) { obj[key] = val; } else if(isArray(obj[key])) { obj[key].push(val); } else { obj[key] = [obj[key],val]; } } } }); return obj; } 查看代码

来源:http://www.cnblogs.com/Niccky/p/4164761.html

/**
 * @license AngularJS v1.3.0-beta.15
 * (c) 2010-2014 Google, Inc. http://angularjs.org
 * License: MIT
 */
(function(window, document, undefined) {'use strict';

    /**
     * @description
     *
     * This object provides a utility for producing rich Error messages within
     * Angular. It can be called as follows:
     *当Angular在发生错误的时候,这个对象提供一个处理错误的工具类,它的调用方式如下:
     * 例如:
     * var exampleMinErr = minErr('example');
     * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
     *
     * The above creates an instance of minErr in the example namespace. The
     * resulting error will have a namespaced error code of example.one.  The
     * resulting error will replace {0} with the value of foo, and {1} with the
     * value of bar. The object is not restricted in the number of arguments it can
     * take.
     *在上面的代码中,在example命名空间中创建了一个minErr的实例。错误的结果会在example,
     *里面生成一个错误码的example.one命名空间。这个错误的结果会用foo的值和bar的值,
     *来进行替换前面的点位符{0},{1}.这个对象不严格必须给定错误参数,因此错误参数可有可无。
     *
     * If fewer arguments are specified than necessary for interpolation, the extra
     * interpolation markers will be preserved in the final string.
     *如果指定的错误对象中的错误参数,则它会保留在最终生成的字符串中。
     *
     * Since data will be parsed statically during a build step, some restrictions
     * are applied with respect to how minErr instances are created and called.
     * Instances should have names of the form namespaceMinErr for a minErr created
     * using minErr('namespace') . Error codes, namespaces and template strings
     * should all be static strings, not variables or general expressions.
     *在编译阶段,错误参数中的数据会自己生成与解析,错误对象中的一些限制将会监视错误对象的
     实例该如何被创建与如何被调用。
     *
     * @param {string} module The namespace to use for the new minErr instance.
     * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
     */

//module:模板名称,将会用于新的错误对象的实例中
    function minErr(module) {
        return function () {//直接进行返回操作
            //获取错误参数中的错误标识符,如,上面示例中的one
            var code = arguments[0],
            //获取错误对象模板的前缀
                prefix = '[' + (module ? module + ':' : '') + code + '] ',
                template = arguments[1],
                templateArgs = arguments,
                //这个属于偏置函数
                stringify = function (obj) {
                    if (typeof obj === 'function') {//如果参数是一个函数
                        //返回的结果,如:{'item in items '}-->''
                        return obj.toString().replace(/ \{[\s\S]*$/, '');
                    } else if (typeof obj === 'undefined') {
                        return 'undefined';
                    } else if (typeof obj !== 'string') {
                        return JSON.stringify(obj);//强制参数转换为Json的字符串形式
                    }
                    return obj;
                },
                message, i;


            message = prefix + template.replace(/\{\d+\}/g, function (match) {
                var index = +match.slice(1, -1), arg;

                if (index + 2 < templateArgs.length) {
                    arg = templateArgs[index + 2];
                    if (typeof arg === 'function') {
                        return arg.toString().replace(/ ?\{[\s\S]*$/, '');
                    } else if (typeof arg === 'undefined') {
                        return 'undefined';
                    } else if (typeof arg !== 'string') {
                        return toJson(arg);
                    }
                    return arg;
                }
                return match;
            });

            message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.15/' +
            (module ? module + '/' : '') + code;
            for (i = 2; i < arguments.length; i++) {
                message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
                encodeURIComponent(stringify(arguments[i]));
            }

            return new Error(message);
        };
    }

    /* We need to tell jshint what variables are being exported */
    /* global angular: true,
     msie: true,
     jqLite: true,
     jQuery: true,
     slice: true,
     push: true,
     toString: true,
     ngMinErr: true,
     angularModule: true,
     nodeName_: true,
     uid: true,
     REGEX_STRING_REGEXP: true,
     VALIDITY_STATE_PROPERTY: true,

     lowercase: true,
     uppercase: true,
     manualLowercase: true,
     manualUppercase: true,
     nodeName_: true,
     isArrayLike: true,
     forEach: true,
     sortedKeys: true,
     forEachSorted: true,
     reverseParams: true,
     nextUid: true,
     setHashKey: true,
     extend: true,
     int: true,
     inherit: true,
     noop: true,
     identity: true,
     valueFn: true,
     isUndefined: true,
     isDefined: true,
     isObject: true,
     isString: true,
     isNumber: true,
     isDate: true,
     isArray: true,
     isFunction: true,
     isRegExp: true,
     isWindow: true,
     isScope: true,
     isFile: true,
     isBlob: true,
     isBoolean: true,
     trim: true,
     isElement: true,
     makeMap: true,
     map: true,
     size: true,
     includes: true,
     indexOf: true,
     arrayRemove: true,
     isLeafNode: true,
     copy: true,
     shallowCopy: true,
     equals: true,
     csp: true,
     concat: true,
     sliceArgs: true,
     bind: true,
     toJsonReplacer: true,
     toJson: true,
     fromJson: true,
     startingTag: true,
     tryDecodeURIComponent: true,
     parseKeyValue: true,
     toKeyValue: true,
     encodeUriSegment: true,
     encodeUriQuery: true,
     angularInit: true,
     bootstrap: true,
     snake_case: true,
     bindJQuery: true,
     assertArg: true,
     assertArgFn: true,
     assertNotHasOwnProperty: true,
     getter: true,
     getBlockElements: true,
     hasOwnProperty: true,
     */

////////////////////////////////////

    /**
     * @ngdoc module
     * @name ng
     * @module ng
     * @description
     *
     * # ng (core module)
     * The ng module is loaded by default when an AngularJS application is started. The module itself
     * contains the essential components for an AngularJS application to function. The table below
     * lists a high level breakdown of each of the services/factories, filters, directives and testing
     * components available within this core module.
     *
     * <div doc-module-components="ng"></div>
     *
     * ng模板默认在Angular应用程序启动的时候会被自动加载。这个模板包含了Angular应用程序运行所必须的组件。
     *  下表列出了在这个核心的模块中所包含的服务/工厂,过滤器,指令和一些测试的组件
     */

    var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;

// The name of a form control's ValidityState property.
// This is used so that it's possible for internal tests to create mock ValidityStates.
    var VALIDITY_STATE_PROPERTY = 'validity';

    /**
     * @ngdoc function
     * @name angular.lowercase
     * @module ng
     * @kind function
     *
     * @description Converts the specified string to lowercase.
     * @param {string} string String to be converted to lowercase.
     * @returns {string} Lowercased string.
     */
        //转换指定的字符串为小写
    var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
    var hasOwnProperty = Object.prototype.hasOwnProperty;

    /**
     * @ngdoc function
     * @name angular.uppercase
     * @module ng
     * @kind function
     *
     * @description Converts the specified string to uppercase.
     * @param {string} string String to be converted to uppercase.
     * @returns {string} Uppercased string.
     */
        //转换指定的字符串为大写
    var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};


    var manualLowercase = function(s) {
        /* jshint bitwise: false */
        return isString(s)
            ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
            : s;
    };
    var manualUppercase = function(s) {
        /* jshint bitwise: false */
        return isString(s)
            ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
            : s;
    };


// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
// with correct but slower alternatives.
    if ('i' !== 'I'.toLowerCase()) {
        lowercase = manualLowercase;
        uppercase = manualUppercase;
    }


    var /** holds major version number for IE or NaN for real browsers */
        msie,
        jqLite,           // delay binding since jQuery could be loaded after us.
        jQuery,           // delay binding
        slice             = [].slice,//取出指定位置的数组数据
        push              = [].push,//把指定的数据放到数据里面
        toString          = Object.prototype.toString,//重写Object原型中的toString方法
        ngMinErr          = minErr('ng'),//定义一个全局的错误对象,对应的错误参数为,ng

        /** @name angular */
            //判断系统是否注册了angular应用程序,如果没有注册则注册angular应用程序的为空对象
        angular           = window.angular || (window.angular = {}),
        angularModule,
        nodeName_,
        uid               = 0;

    /**
     * IE 11 changed the format of the UserAgent string.
     * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
     */
    //判断浏览器的类型
    msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
    if (isNaN(msie)) {
        msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
    }


    /**
     * @private
     * @param {*} obj
     * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
     *                   String ...)
     */
    //判断传入的对象obj是否是数组或有类似数组的行为,它可以是json字符串或数组
    function isArrayLike(obj) {
        if (obj == null || isWindow(obj)) {//为空或window对象,则返回false
            return false;
        }

        var length = obj.length;//获取数组的长度

        if (obj.nodeType === 1 && length) {//判断obj的节点类型,如果为元素,则返回true
            return true;
        }

        return isString(obj) || isArray(obj) || length === 0 ||
            typeof length === 'number' && length > 0 && (length - 1) in obj;
    }

    /**
     * @ngdoc function
     * @name angular.forEach
     * @module ng
     * @kind function
     *
     * @description
     * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
     * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
     * is the value of an object property or an array element and `key` is the object property key or
     * array element index. Specifying a `context` for the function is optional.
     *
     * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
     * using the `hasOwnProperty` method.
     *
     ```js
     var values = {name: 'misko', gender: 'male'};
     var log = [];
     angular.forEach(values, function(value, key) {
       this.push(key + ': ' + value);
     }, log);
     expect(log).toEqual(['name: misko', 'gender: male']);
     ```
     *
     * @param {Object|Array} obj Object to iterate over.//可以是一个对象或一个数组
     * @param {Function} iterator Iterator function.//迭代器是一个函数
     * @param {Object=} context Object to become context (`this`) for the iterator function.//这个对象是一个上下文对象充当this的角色
     * @returns {Object|Array} Reference to `obj`.
     */
    //其中context可选参数,iterator是一个迭代器,它是一个函数
    //它不能获取的继承的属性,因为程序中用hasOwnProperty来过滤了
    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);
                    }
                }
            } else if (isArray(obj) || isArrayLike(obj)) {
                for (key = 0, length = obj.length; key < length; key++) {
                    iterator.call(context, obj[key], key);
                }
            } else if (obj.forEach && obj.forEach !== forEach) {
                obj.forEach(iterator, context);
            } else {
                for (key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        iterator.call(context, obj[key], key);
                    }
                }
            }
        }
        return obj;
    }

    function sortedKeys(obj) {//按照键来排序
        var keys = [];
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                keys.push(key);
            }
        }
        return keys.sort();//采用数组默认的排序方式
    }

    function forEachSorted(obj, iterator, context) {//先按照键排序,然后再遍历|迭代
        var keys = sortedKeys(obj);
        for ( var i = 0; i < keys.length; i++) {
            iterator.call(context, obj[keys[i]], keys[i]);
        }
        return keys;
    }


    /**
     * when using forEach the params are value, key, but it is often useful to have key, value.
     * @param {function(string, *)} iteratorFn
     * @returns {function(*, string)}
     */
    function reverseParams(iteratorFn) {
        return function(value, key) { iteratorFn(key, value); };
    }

    /**
     * A consistent way of creating unique IDs in angular.
     *
     * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
     * we hit number precision issues in JavaScript.
     *
     * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
     *
     * @returns {number} an unique alpha-numeric string
     */
    function nextUid() {//生成一个常量,它在andular里面是唯一的
        return ++uid;
    }


    /**
     * Set or clear the hashkey for an object.
     * @param obj object//参数是一个对象
     * @param h the hashkey (!truthy to delete the hashkey)
     */
    function setHashKey(obj, h) {
        if (h) {//如果存在就设置
            obj.$$hashKey = h;
        }
        else {//如果不存在则删除
            delete obj.$$hashKey;
        }
    }

    /**
     * @ngdoc function
     * @name angular.extend
     * @module ng
     * @kind function
     *
     * @description
     * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
     * to `dst`. You can specify multiple `src` objects.
     *
     * @param {Object} dst Destination object.//最终的对象
     * @param {...Object} src Source object(s).//源对象
     * @returns {Object} Reference to `dst`.//返回最终的对象
     */
    function extend(dst) {//在javascript中实现继承
        var h = dst.$$hashKey;
        forEach(arguments, function(obj) {//这里采用拷贝属性的方式实现继承
            if (obj !== dst) {
                forEach(obj, function(value, key) {
                    dst[key] = value;
                });
            }
        });

        setHashKey(dst,h);
        return dst;
    }

    function int(str) {//转换为整形
        return parseInt(str, 10);
    }


    function inherit(parent, extra) {//继承
        return extend(new (extend(function() {}, {prototype:parent}))(), extra);
    }

    /**
     * @ngdoc function
     * @name angular.noop
     * @module ng
     * @kind function
     *
     * @description
     * A function that performs no operations. This function can be useful when writing code in the
     * functional style.
     ```js
     function foo(callback) {
       var result = calculateResult();
       (callback || angular.noop)(result);
     }
     ```
     */
    function noop() {}//在写样式代码的时候会被用到
    noop.$inject = [];


    /**
     * @ngdoc function
     * @name angular.identity
     * @module ng
     * @kind function
     *
     * @description
     * A function that returns its first argument. This function is useful when writing code in the
     * functional style.
     *
     ```js
     function transformer(transformationFn, value) {
       return (transformationFn || angular.identity)(value);
     };
     ```
     */
    function identity($) {return $;}//在写样式代码的时候会被用到//定义angular的标识
    identity.$inject = [];


    function valueFn(value) {return function() {return value;};}

    /**
     * @ngdoc function
     * @name angular.isUndefined
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is undefined.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is undefined.
     */
    function isUndefined(value){return typeof value === 'undefined';}


    /**
     * @ngdoc function
     * @name angular.isDefined
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is defined.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is defined.
     */
    function isDefined(value){return typeof value !== 'undefined';}


    /**
     * @ngdoc function
     * @name angular.isObject
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
     * considered to be objects. Note that JavaScript arrays are objects.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is an `Object` but not `null`.
     */
    function isObject(value){return value != null && typeof value === 'object';}


    /**
     * @ngdoc function
     * @name angular.isString
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is a `String`.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is a `String`.
     */
    function isString(value){return typeof value === 'string';}


    /**
     * @ngdoc function
     * @name angular.isNumber
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is a `Number`.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is a `Number`.
     */
    function isNumber(value){return typeof value === 'number';}


    /**
     * @ngdoc function
     * @name angular.isDate
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a value is a date.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is a `Date`.
     */
    function isDate(value) {
        return toString.call(value) === '[object Date]';
    }


    /**
     * @ngdoc function
     * @name angular.isArray
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is an `Array`.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is an `Array`.
     */
    var isArray = (function() {
        if (!isFunction(Array.isArray)) {
            return function(value) {
                return toString.call(value) === '[object Array]';
            };
        }
        return Array.isArray;
    })();

    /**
     * @ngdoc function
     * @name angular.isFunction
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is a `Function`.
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is a `Function`.
     */
    function isFunction(value){return typeof value === 'function';}


    /**
     * Determines if a value is a regular expression object.
     *
     * @private
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is a `RegExp`.
     */
    function isRegExp(value) {
        return toString.call(value) === '[object RegExp]';
    }


    /**
     * Checks if `obj` is a window object.
     *
     * @private
     * @param {*} obj Object to check
     * @returns {boolean} True if `obj` is a window obj.
     */
    function isWindow(obj) {
        return obj && obj.window === obj;
    }


    function isScope(obj) {
        return obj && obj.$evalAsync && obj.$watch;
    }


    function isFile(obj) {
        return toString.call(obj) === '[object File]';
    }


    function isBlob(obj) {
        return toString.call(obj) === '[object Blob]';
    }


    function isBoolean(value) {
        return typeof value === 'boolean';
    }


    var trim = (function() {
        // native trim is way faster: http://jsperf.com/angular-trim-test
        // but IE doesn't have it... :-(
        // TODO: we should move this into IE/ES5 polyfill
        if (!String.prototype.trim) {
            return function(value) {
                return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
            };
        }
        return function(value) {
            return isString(value) ? value.trim() : value;
        };
    })();


    /**
     * @ngdoc function
     * @name angular.isElement
     * @module ng
     * @kind function
     *
     * @description
     * Determines if a reference is a DOM element (or wrapped jQuery element).
     *
     * @param {*} value Reference to check.
     * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
     */
    function isElement(node) {
        return !!(node &&
        (node.nodeName  // we are a direct element
        || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
    }

    /**
     * @param str 'key1,key2,...'
     * @returns {object} in the form of {key1:true, key2:true, ...}
     */
    function makeMap(str) {
        var obj = {}, items = str.split(","), i;
        for ( i = 0; i < items.length; i++ )
            obj[ items[i] ] = true;
        return obj;
    }


    if (msie < 9) {
        nodeName_ = function(element) {
            element = element.nodeName ? element : element[0];
            return lowercase(
                (element.scopeName && element.scopeName != 'HTML')
                    ? element.scopeName + ':' + element.nodeName : element.nodeName
            );
        };
    } else {
        nodeName_ = function(element) {
            return lowercase(element.nodeName ? element.nodeName : element[0].nodeName);
        };
    }


    function map(obj, iterator, context) {
        var results = [];
        forEach(obj, function(value, index, list) {
            results.push(iterator.call(context, value, index, list));
        });
        return results;
    }


    /**
     * @description
     * Determines the number of elements in an array, the number of properties an object has, or
     * the length of a string.
     *
     * Note: This function is used to augment the Object type in Angular expressions. See
     * {@link angular.Object} for more information about Angular arrays.
     *
     * @param {Object|Array|string} obj Object, array, or string to inspect.
     * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
     * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
     */
    function size(obj, ownPropsOnly) {
        var count = 0, key;

        if (isArray(obj) || isString(obj)) {
            return obj.length;
        } else if (isObject(obj)) {
            for (key in obj)
                if (!ownPropsOnly || obj.hasOwnProperty(key))
                    count++;
        }

        return count;
    }


    function includes(array, obj) {
        return indexOf(array, obj) != -1;
    }

    function indexOf(array, obj) {
        if (array.indexOf) return array.indexOf(obj);

        for (var i = 0; i < array.length; i++) {
            if (obj === array[i]) return i;
        }
        return -1;
    }

    function arrayRemove(array, value) {
        var index = indexOf(array, value);
        if (index >=0)
            array.splice(index, 1);
        return value;
    }

    function isLeafNode (node) {
        if (node) {
            switch (nodeName_(node)) {
                case "option":
                case "pre":
                case "title":
                    return true;
            }
        }
        return false;
    }

    /**
     * @ngdoc function
     * @name angular.copy
     * @module ng
     * @kind function
     *
     * @description
     * Creates a deep copy of `source`, which should be an object or an array.
     *创建一个深拷贝的源,它可以是一个对象或一个数组
     * * If no destination is supplied, a copy of the object or array is created
     * 如果未指定dest,对象或数组的一个副本会被创建
     * * If a destination is provided, all of its elements (for array) or properties (for objects)
     *   are deleted and then all elements/properties from the source are copied to it.
     *   如果指定了它的dest,则它的所有属性或元素将会被删除,并且它的所有元素或属性将会从源里面拷贝出来。
     * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
     * 如果源不是一个对象或数组,则操作会立即停止执行
     * * If `source` is identical to 'destination' an exception will be thrown.
     *如果源被标识为一个dest,则会抛出一个异常
     * @param {*} source The source that will be used to make a copy.//源,进行拷贝的参照对象,可以是任意类型
     *                   Can be any type, including primitives, `null`, and `undefined`.
     * @param {(Object|Array)=} destination Destination into which the source is copied. If
     *     provided, must be of the same type as `source`.//参数为一个对象或数组,如果被提供,则必须与源的类型相同
     * @returns {*} The copy or updated `destination`, if `destination` was specified.
     * 如果dest被指定的话,则更新dest;如果dest未被指定的话,是返回源的拷贝副本。
     *
     * @example
     <example module="copyExample">
     <file name="index.html">
     <div ng-controller="ExampleController">
     <form novalidate class="simple-form">
     Name: <input type="text" ng-model="user.name" /><br />
     E-mail: <input type="email" ng-model="user.email" /><br />
     Gender: <input type="radio" ng-model="user.gender" value="male" />male
     <input type="radio" ng-model="user.gender" value="female" />female<br />
     <button ng-click="reset()">RESET</button>
     <button ng-click="update(user)">SAVE</button>
     </form>
     <pre>form = {{user | json}}</pre>//user是一个json对象
     <pre>master = {{master | json}}</pre>master是一个json对象
     </div>

     <script>
     angular.module('copyExample')
     .controller('ExampleController', ['$scope', function($scope) {//$scope默认会被注入
      $scope.master= {};

      $scope.update = function(user) {
        // Example with 1 argument
        $scope.master= angular.copy(user);
      };

      $scope.reset = function() {
        // Example with 2 arguments
        angular.copy($scope.master, $scope.user);
      };

      $scope.reset();
    }]);
     </script>
     </file>
     </example>
     */
    function copy(source, destination, stackSource, stackDest) {
        if (isWindow(source) || isScope(source)) {
            throw ngMinErr('cpws',
                "Can't copy! Making copies of Window or Scope instances is not supported.");
        }

        if (!destination) {//如果指定dest
            destination = source;
            if (source) {
                if (isArray(source)) {
                    destination = copy(source, [], stackSource, stackDest);
                } else if (isDate(source)) {
                    destination = new Date(source.getTime());
                } else if (isRegExp(source)) {
                    destination = new RegExp(source.source);
                } else if (isObject(source)) {
                    var emptyObject = Object.create(Object.getPrototypeOf(source));
                    destination = copy(source, emptyObject, stackSource, stackDest);
                }
            }
        } else {//如果不指定dest
            if (source === destination) throw ngMinErr('cpi',
                "Can't copy! Source and destination are identical.");

            stackSource = stackSource || [];
            stackDest = stackDest || [];

            if (isObject(source)) {
                var index = indexOf(stackSource, source);
                if (index !== -1) return stackDest[index];

                stackSource.push(source);
                stackDest.push(destination);
            }

            var result;
            if (isArray(source)) {
                destination.length = 0;
                for ( var i = 0; i < source.length; i++) {
                    result = copy(source[i], null, stackSource, stackDest);
                    if (isObject(source[i])) {
                        stackSource.push(source[i]);
                        stackDest.push(result);
                    }
                    destination.push(result);
                }
            } else {
                var h = destination.$$hashKey;
                forEach(destination, function(value, key) {
                    delete destination[key];
                });
                for ( var key in source) {
                    if(source.hasOwnProperty(key)) {
                        result = copy(source[key], null, stackSource, stackDest);
                        if (isObject(source[key])) {
                            stackSource.push(source[key]);
                            stackDest.push(result);
                        }
                        destination[key] = result;
                    }
                }
                setHashKey(destination,h);
            }

        }
        return destination;
    }

    /**
     * Creates a shallow copy of an object, an array or a primitive
     * 创建一个浅副本,可以是一个数组或一个原始数据
     */
    function shallowCopy(src, dst) {
        var i = 0;
        if (isArray(src)) {
            dst = dst || [];

            for (; i < src.length; i++) {
                dst[i] = src[i];
            }
        } else if (isObject(src)) {
            dst = dst || {};

            var keys = Object.keys(src);

            for (var l = keys.length; i < l; i++) {
                var key = keys[i];

                if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
                    dst[key] = src[key];
                }
            }
        }

        return dst || src;
    }


    /**
     * @ngdoc function
     * @name angular.equals
     * @module ng
     * @kind function
     *
     * @description
     * Determines if two objects or two values are equivalent. Supports value types, regular
     * expressions, arrays and objects.
     *
     * Two objects or values are considered equivalent if at least one of the following is true:
     *
     * * Both objects or values pass `===` comparison.
     * * Both objects or values are of the same type and all of their properties are equal by
     *   comparing them with `angular.equals`.
     * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
     * * Both values represent the same regular expression (In JavaScript,
     *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
     *   representation matches).
     *
     * During a property comparison, properties of `function` type and properties with names
     * that begin with `$` are ignored.
     *
     * Scope and DOMWindow objects are being compared only by identify (`===`).
     *
     * @param {*} o1 Object or value to compare.
     * @param {*} o2 Object or value to compare.
     * @returns {boolean} True if arguments are equal.
     */
    function equals(o1, o2) {
        if (o1 === o2) return true;
        if (o1 === null || o2 === null) return false;
        if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
        var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
        if (t1 == t2) {
            if (t1 == 'object') {
                if (isArray(o1)) {
                    if (!isArray(o2)) return false;
                    if ((length = o1.length) == o2.length) {
                        for(key=0; key<length; key++) {
                            if (!equals(o1[key], o2[key])) return false;
                        }
                        return true;
                    }
                } else if (isDate(o1)) {
                    return isDate(o2) && o1.getTime() == o2.getTime();
                } else if (isRegExp(o1) && isRegExp(o2)) {
                    return o1.toString() == o2.toString();
                } else {
                    if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
                    keySet = {};
                    for(key in o1) {
                        if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
                        if (!equals(o1[key], o2[key])) return false;
                        keySet[key] = true;
                    }
                    for(key in o2) {
                        if (!keySet.hasOwnProperty(key) &&
                            key.charAt(0) !== '$' &&
                            o2[key] !== undefined &&
                            !isFunction(o2[key])) return false;
                    }
                    return true;
                }
            }
        }
        return false;
    }


    function csp() {
        return (document.securityPolicy && document.securityPolicy.isActive) ||
            (document.querySelector &&
            !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
    }


    function concat(array1, array2, index) {
        return array1.concat(slice.call(array2, index));//连接两个数组,call(obj,具体的参数)
    }

    //分割指定位置的数组数据
    function sliceArgs(args, startIndex) {
        return slice.call(args, startIndex || 0);//[].splice
    }


    /* jshint -W101 */
    /**
     * @ngdoc function
     * @name angular.bind
     * @module ng
     * @kind function
     *
     * @description
     * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
     * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
     * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
     * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
     *当调用fn函数时,bn会被绑定到self,其中,self相当于this的作用。可以指定args参数绑定到预先形成的函数中。
     * 返回一个函数的调用
     * @param {Object} self Context which `fn` should be evaluated in.//一个上下文对象
     * @param {function()} fn Function to be bound.//一个函数,它将会被绑定到self对象中
     * @param {...*} args Optional arguments to be prebound to the `fn` function call.//可选参数将会被绑定到fn函数中
     * @returns {function()} Function that wraps the `fn` with all the specified bindings.
     */
    /* jshint +W101 */
    function bind(self, fn) {
        //判断可选参数是否被提供,如果被提供则为sliceArg(argumentts,2),如果未被提供则为空数组,[]
        var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
        if (isFunction(fn) && !(fn instanceof RegExp)) {//如果fn是一个函数
            return curryArgs.length//判断可选参数是否被提供
                ? function() {
                return arguments.length
                    ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))//如果可选参数被提供,则把可选参数绑定到self中
                    : fn.apply(self, curryArgs);//如果可选参数未被提供,则返回self本身
            }
                : function() {
                return arguments.length
                    ? fn.apply(self, arguments)
                    : fn.call(self);
            };
        } else {
            // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
            return fn;//在IE里面没有这些函数,所以绑定不了,直接返回fn函数
        }
    }


    function toJsonReplacer(key, value) {
        var val = value;

        if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
            val = undefined;
        } else if (isWindow(value)) {
            val = '$WINDOW';
        } else if (value &&  document === value) {
            val = '$DOCUMENT';
        } else if (isScope(value)) {
            val = '$SCOPE';
        }
        return val;
    }


    /**
     * @ngdoc function
     * @name angular.toJson
     * @module ng
     * @kind function
     *
     * @description
     * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
     * stripped since angular uses this notation internally.
     *
     * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
     * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
     * @returns {string|undefined} JSON-ified string representing `obj`.
     */
    //把指定的对象转换成json字符串,并把json字符串里面的值 替换成与之相对应的对象,如:$$scope,$widnow,$document
    function toJson(obj, pretty) {
        if (typeof obj === 'undefined') return undefined;
        return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
    }


    /**
     * @ngdoc function
     * @name angular.fromJson
     * @module ng
     * @kind function
     *
     * @description
     * Deserializes a JSON string.
     *
     * @param {string} json JSON string to deserialize.//一个json字符串
     * @returns {Object|Array|string|number} Deserialized thingy.,返回一个数组,对象
     */
    function fromJson(json) {//
        return isString(json)
            ? JSON.parse(json)
            : json;
    }


    /**
     * @returns {string} Returns the string representation of the element.
     */
    function startingTag(element) {//查找angular的ng指令,如ngapp,ngrepeat,ngswitch etc.
        element = jqLite(element).clone();//克隆element元素
        try {
            // turns out IE does not let you set .html() on elements which
            // are not allowed to have children. So we just ignore it.
            element.empty();//IE不允许用设置.html()设置元素,也就是说不允许有子元素,因此置为空
        } catch(e) {}
        // As Per DOM Standards
        var TEXT_NODE = 3;//标准的文节点
        var elemHtml = jqLite('<div>').append(element).html();//把div标签添加到新克隆出来的element上,并获取现在的值
        try {
            return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
                elemHtml.
                    match(/^(<[^>]+>)/)[1].//正则表达式表示的示例内容如,<div ng-app='myModule'>
                    //正则:/^<([\w\-]+)/,表示的示例内容,如:<div ng-app='myModule'>,
                    // 正则:([\w\-]+),表示的示例内容如,ng-app,由此看来,angular在html里面写的内容必须是:标准的Html文内容
                    replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });//<ng-app
        } catch(e) {
            return lowercase(elemHtml);//如果不是上面的情况,慢把新取出的值直接返回
        }

    }


/////////////////////////////////////////////////

    /**
     * Tries to decode the URI component without throwing an exception.
     *调试解码URI组件,不抛出异常
     * @private 为私有方法
     * @param str value potential URI component to check.//str是URI组件需要检查的内容
     * @returns {boolean} True if `value` can be decoded,如果str被正常的解析,则返回true
     * with the decodeURIComponent function.
     */
    function tryDecodeURIComponent(value) {
        try {
            return decodeURIComponent(value);
        } catch(e) {
            // Ignore any invalid uri component//忽略任何无效的URI组件内容
        }
    }


    /**
     * Parses an escaped url query string into key-value pairs.//
     * 解析一个转义的url查询字符串为键值对形式
     * @returns {Object.<string,boolean|Array>}//返回Object.字符串/boolean,数组
     */
    function parseKeyValue(/**string*/keyValue) {
        var obj = {}, key_value, key;
        //keyvalue的内容示例如,http://www.baidu.com?search=angular&date=20141215,结果为:search:angular,date:20141215
        forEach((keyValue || "").split('&'), function(keyValue) {
            if ( keyValue ) {
                key_value = keyValue.split('=');
                key = tryDecodeURIComponent(key_value[0]);
                if ( isDefined(key) ) {
                    var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
                    if (!hasOwnProperty.call(obj, key)) {
                        obj[key] = val;
                    } else if(isArray(obj[key])) {
                        obj[key].push(val);
                    } else {
                        obj[key] = [obj[key],val];
                    }
                }
            }
        });
        return obj;
    }

查看代码

posted @ 2017-03-20 14:20  Lonely,lonelyBurning  阅读(490)  评论(0编辑  收藏  举报