angular源码分析:angular中各种常用函数,比较省代码的各种小技巧
angular的工具函数
在angular的API文档中,在最前面就是讲的就是angular的工具函数,下面列出来
angular.bind //用户将函数和对象绑定在一起,返回一个新的函数
angular.bootstrap //angular启动函数,一般不用,除了e2e测试
angular.copy //对象拷贝
angular.element //jQlite,作用类似于jQuery
angular.equals //对象比较。用 == 对两个对象进行比较,除非他们是同一个对象的引用,否则都不会相等。
angular.extend //对象扩展,将两个对象的属性求并集
angular.forEach //功能类似于jQuery中each函数,
angular.noop //额,一个空函数
angular.identity //额,这个函数可以返回它的第一个函数
angular.injector //用来创建一个注入器,可以用来给其他函数注入所依赖的对象
angular.module //两个参数,注册模块;一个参数,返回模块。太常用了。
angular.fromJson //将json转成对象
angular.toJson //将对象转成json
angular.uppercase //小写转大写
angular.lowercase //大写转小写
//类型检查
angular.isArray
angular.isDate
angular.isDefined
angular.isElement
angular.isFunction
angular.isNumber
angular.isObject
angular.isString
angular.isUndefined
他们都是怎么实现的,并且怎么用
1.类型检查函数
function isUndefined(value) {return typeof value === 'undefined';}
function isDefined(value) {return typeof value !== 'undefined';}
function isObject(value) {
return value !== null && typeof value === 'object'; //需要判断null的情况,在js中null是一个object,但是又不是我们理解的object
}
function isString(value) {return typeof value === 'string';}
function isNumber(value) {return typeof value === 'number';}
function isDate(value) {
return toString.call(value) === '[object Date]'; //前面有定义:toString = Object.prototype.toString, //技巧1
}
var isArray = Array.isArray;
function isFunction(value) {return typeof value === 'function';}
function isElement(node) {
return !!(node && //技巧2
(node.nodeName // we are a direct element
|| (node.prop && node.attr && node.find))); // we have an on and find method part of jQuery API
}
技巧1:通过短引用的定义来减少代码书写
技巧2:使用双叹号(!!),将表达式的值限制在true/false间。作用类似于C语言中的 bool(expression),将表达式的值强制转换为布尔值。
2.下面分析大小写转换
//方案1:大小写都是利用字符串对象本身的大小写转换函数来完成的
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
//方案2:自定义大小写转换函数
var manualLowercase = function(s) {
/* jshint bitwise: false */
return isString(s)
? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) //技巧3
: 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.
//土耳其环境,浏览器的默认提供大小写转换函数会出问题,所以采用方案2
if ('i' !== 'I'.toLowerCase()) {
lowercase = manualLowercase;
uppercase = manualUppercase;
}
技巧3:字符串对象的replace函数妙用
stringObject.replace(regexp/substr,replacement)
三种使用境界:
1.两个参数都是字符或者字符串。函数会在stringObject中查找第一个字符或字符串,并且替换成第二个字符或字符串
2.第一参数使用正则表达式,第二参数使用字符或字符串。函数会用正则表达式的方式进行查找并替换
3.第一参数是字符串或正则表达式,第二个参数是一个回掉函数。replace函数会按第一个参数查找,然后将值传到第二参数指定的函数中得到反馈值替换被查找到的字符串。
例子:写一个函数处理下面字符串,给下面代码中的a标签中的内容都添加一个括号
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<a name="dapeng">我是大鹏</a>
<a href="#dapeng">点击,链接到大鹏</a>
</body>
</html>
js函数:
function add_brackets(inputStr){
return typeof inputStr == 'string' && inputStr.replace(/(<a.+?>)(.+)(<\/a>)/im,function(){
return arguments[1] + '(' + arguments[2] + ')' + arguments[3];
});
}
3.关于angular.noop和angular.identity
下面是angular注释中给出的angular.noop和angular.identity的使用例子。
function foo(callback) {
var result = calculateResult();
(callback || angular.noop)(result); //技巧4:不用再去判断callback是否定义
}
function transformer(transformationFn, value) {
return (transformationFn || angular.identity)(value);
};
技巧4:定义一些默认的对象,在函数中,将参数与默认对象求或,可以省去参数是否定义的判断。
拷贝,angular.copy
var TYPED_ARRAY_REGEXP = /^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/;
function isTypedArray(value) {
return TYPED_ARRAY_REGEXP.test(toString.call(value));
}
/**
* 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;
}
}
function copy(source, destination, stackSource, stackDest) { //技巧5
if (isWindow(source) || isScope(source)) {
throw ngMinErr('cpws',
"Can't copy! Making copies of Window or Scope instances is not supported.");
}
if (isTypedArray(destination)) {
throw ngMinErr('cpta',
"Can't copy! TypedArray destination cannot be mutated.");
}
if (!destination) {
destination = source;
if (isObject(source)) {
var index;
if (stackSource && (index = stackSource.indexOf(source)) !== -1) {
return stackDest[index];
}
// TypedArray, Date and RegExp have specific copy functionality and must be
// pushed onto the stack before returning.
// Array and other objects create the base object and recurse to copy child
// objects. The array/object will be pushed onto the stack when recursed.
if (isArray(source)) {
return copy(source, [], stackSource, stackDest);
} else if (isTypedArray(source)) {
destination = new source.constructor(source);
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
destination.lastIndex = source.lastIndex;
} else if (isFunction(source.cloneNode)) {
destination = source.cloneNode(true);
} else {
var emptyObject = Object.create(getPrototypeOf(source)); //getPrototypeOf = Object.getPrototypeOf, 这里用原型对象创建了一个空对象
return copy(source, emptyObject, stackSource, stackDest); //将其转化为destination有定义的调用
}
if (stackDest) {
stackSource.push(source);
stackDest.push(destination);
}
}
} else {
if (source === destination) throw ngMinErr('cpi',
"Can't copy! Source and destination are identical.");
stackSource = stackSource || [];
stackDest = stackDest || [];
if (isObject(source)) {
stackSource.push(source);
stackDest.push(destination);
}
var result, key;
if (isArray(source)) { //如果源对象是一个数组,循环拷贝数组
destination.length = 0;
for (var i = 0; i < source.length; i++) {
destination.push(copy(source[i], null, stackSource, stackDest));
}
} else {
var h = destination.$$hashKey;
if (isArray(destination)) {
destination.length = 0;
} else {
forEach(destination, function(value, key) {
delete destination[key];
});
}
if (isBlankObject(source)) {
// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
for (key in source) {
destination[key] = copy(source[key], null, stackSource, stackDest);
}
} else if (source && typeof source.hasOwnProperty === 'function') { //挨个拷贝键值,形成递归拷贝
// Slow path, which must rely on hasOwnProperty
// 慢路径,必须依赖于对象拥有hasOwnProperty方法
for (key in source) {
if (source.hasOwnProperty(key)) {
destination[key] = copy(source[key], null, stackSource, stackDest);
}
}
} else {
// Slowest path --- hasOwnProperty can't be called as a method
// 更慢的路径,hasOwnProperty不能被当成对象的方法调用的时候
for (key in source) {
if (hasOwnProperty.call(source, key)) { //var hasOwnProperty = Object.prototype.hasOwnProperty;
destination[key] = copy(source[key], null, stackSource, stackDest);
}
}
}
setHashKey(destination,h);
}
}
return destination;
}
技巧5:构造递归函数。用递归的方式处理问题的条件在于,能把问题转化为规模缩小了的同类问题的子问题。缺点,效率较低。理论上任何递归问题,都可以用循环来完成。
对象是否相等,angular.equals
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)) { //Date,转成时间戳比较
if (!isDate(o2)) return false;
return equals(o1.getTime(), o2.getTime());
} else if (isRegExp(o1)) { //正则式,转成字符串比较
return isRegExp(o2) ? o1.toString() == o2.toString() : false;
} else {
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
keySet = createMap();
for (key in o1) { //对象属性的比较,也是递归调用,遍历第一个对象所有的属性,发现有不等的地方,立即返回false
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
if (!equals(o1[key], o2[key])) return false;
keySet[key] = true;
}
for (key in o2) { //遍历第二对象,继续检查,发现两个对象有不等的地方,立即返回false
if (!(key in keySet) &&
key.charAt(0) !== '$' &&
isDefined(o2[key]) &&
!isFunction(o2[key])) return false;
}
return true;
}
}
}
return false;
}
上一期:angular源码分析:angular中的依赖注入式如何实现的
下一期:angular源码分析:angular的源代码目录结构
ps:也许这个该先讲,可能有同学看到一堆文件,不知从何看起。
angular源码分析:angular中各种常用函数,比较省代码的各种小技巧的更多相关文章
- angular源码分析:angular中脏活累活承担者之$parse
我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...
- angular源码分析:angular中入境检察官$sce
一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...
- angular源码分析:angular中$rootscope的实现——scope的一生
在angular中,$scope是一个关键的服务,可以被注入到controller中,注入其他服务却只能是$rootscope.scope是一个概念,是一个类,而$rootscope和被注入到cont ...
- angular源码分析:angular中的依赖注入式如何实现的
一.准备 angular的源码一份,我这里使用的是v1.4.7.源码的获取,请参考我另一篇博文:angular源码分析:angular源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...
- angular源码分析:angular中脏活累活的承担者之$interpolate
一.首先抛出两个问题 问题一:在angular中我们绑定数据最基本的方式是用两个大括号将$scope的变量包裹起来,那么如果想将大括号换成其他什么符号,比如换成[{与}],可不可以呢,如果可以在哪里配 ...
- angular源码分析:injector.js文件分析——angular中的依赖注入式如何实现的(续)
昨天晚上写完angular源码分析:angular中jqLite的实现--你可以丢掉jQuery了,给今天定了一个题angular源码分析:injector.js文件,以及angular的加载流程,但 ...
- angular源码分析:angular中jqLite的实现——你可以丢掉jQuery了
一.从function JQLite(element)函数开始. function JQLite(element) { if (element instanceof JQLite) { //情况1 r ...
- angular源码分析:angular的源代码目录结构说明
一.读源码,是选择"编译合并后"的呢还是"编译前的"呢? 有朋友说,读angular源码,直接看编译后的,多好,不用管模块间的关系,从上往下读就好了.但是在我看 ...
- angular源码分析:$compile服务——directive他妈
一.directive的注册 1.我们知道,我们可以通过类似下面的代码定义一个指令(directive). var myModule = angular.module(...); myModule.d ...
随机推荐
- H5游戏开发之多边形碰撞检测
2D多边形碰撞检测介绍这是一篇论证如何在2D动作游戏中执行碰撞检测的文章(Mario,宇宙入侵者等),为了保证它的高效性和精确性,碰撞检测是以多边形为基础的,而不是以sprite为基础.这是两种不同的 ...
- mysql管理知识点
mysql是完全开原的关系型数据库,在web后端用的比较多,经典的架构有LAMP,LNMP,其中的M就指mysql. 一:安装 新版的linux里默认的已经不是mysql,而是他的一个分支mariad ...
- Windows Azure Web Site (15) 取消Azure Web Site默认的IIS ARR
<Windows Azure Platform 系列文章目录> 我们知道,Azure Web Site (改名为Azure Web App)默认是可以保留Session的.Azure We ...
- ssl证书生成:cer&jks文件生成摘录
一.生成.jks文件 1.keystore的生成: 分阶段生成: keytool -genkey -alias yushan(别名) -keypass yushan(别名密码) -keyalg ...
- Moon.Orm 5.0(MQL版)分页功能的设计(求指教,邀请您的加入)
一.分页的分类及分析 1)分页的前置条件: 查询的目标条件.第几页.总页数(本质上由查询条件决定).每页条数.请求地址.按照什么字段怎样排序 2)目标结果: 数据列表,List<T>返回 ...
- 在Visual Studio中使用正则表达式匹配换行和批量替换
系统环境:Windows 8.1 Enterprise Update 2 x64 开发环境:Mircosoft Visual Studio Ultimate 2013 Update 2 RC 问题:如 ...
- ASP.NET发送电子邮件
代码: using System; using System.Collections.Generic; using System.Configuration; using System.Linq; u ...
- c#单例模式的实现
单例模式定义:一个类有且仅有一个实例,并且自行实例化向整个系统提供. 实现要点: 1.是单例模式的类只提供私有的构造函数. 2.是类定义中含有一个该类的静态私有对象. 3.是该类提供了一个静态的共 ...
- 算法实例-C#-快速排序-QuickSort
算法实例 ##排序算法Sort## ### 快速排序QuickSort ### bing搜索结果 http://www.bing.com/knows/search?q=%E5%BF%AB%E9%80% ...
- JNDI解读(转)
NDI 是什么 JNDI是 Java 命名与目录接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之一,不少专家认为,没有透彻理解JNDI的意 ...