/** * @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;
}
查看代码