• 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(/ {[sS]*$/, ''); } 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(/ ?{[sS]*$/, ''); } else if (typeof arg === 'undefined') { return 'undefined'; } else if (typeof arg !== 'string') { return toJson(arg); } return arg; } return match; }); message = message + ' http://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(/^ss*/, '').replace(/ss*$/, '') : 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(/ {[sS]*$/, '');
                        } 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(/ ?{[sS]*$/, '');
                        } else if (typeof arg === 'undefined') {
                            return 'undefined';
                        } else if (typeof arg !== 'string') {
                            return toJson(arg);
                        }
                        return arg;
                    }
                    return match;
                });

                message = message + ' http://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(/^ss*/, '').replace(/ss*$/, '') : 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;
        }

    查看代码

  • 相关阅读:
    关于Eclipse中Jsp页面打不开并且显示Failed to create the part's controls的解决办法
    FileOutputStream()找不到指定路径
    视频还没剪完室友就喊我去撸串,我直接用python写了个自动关机程序!
    ORM是什么?如何理解ORM
    jquery获取多个相同name的input的value值
    Windows安装OpenSSH的注意点
    小功能~调用QQ进行客服对话功能
    Furion分表分库我也要happy coding
    .Net下你不得不看的分表分库解决方案多字段分片
    分库分表的框架如何设计自动路由
  • 原文地址:https://www.cnblogs.com/sxz2008/p/6588641.html
Copyright © 2020-2023  润新知