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 ...
随机推荐
- hdu2066一个人的旅行(多源点多汇点的最短路径问题)
/* 思路:多源点,多会点的最短路径! 将最小号-1的节点但最源点,将最大号+1的点当作汇点! 将问题转变成从一个源点到一个汇点的最短路径的问题! 开始忘记初始化vector了,哇了好多次....坑爹 ...
- 【原创】C#玩高频数字彩快3的一点体会
购彩风险非常高,本人纯属很久以前对数字高频彩的一点研究.目前已经远离数字彩,重点研究足球篮球比赛资料库和赛果预测. 这是一篇在草稿箱保存了1年多的文章,一直没发现,顺便修改修改分享给大家.以后会有更多 ...
- JavaScript之毒瘤
0.导言 JavaScript中有许多难以避免的问题特性.接下来就一一揭示. 1.全局变量 在所有JavaScript的糟糕特性中,最为糟糕的就是全局变量的依赖.全局变量使得在同一个程序中运行独立的子 ...
- [爬虫资源]各大爬虫资源大汇总,做我们自己的awesome系列
大数据的流行一定程序导致的爬虫的流行,有些企业和公司本身不生产数据,那就只能从网上爬取数据,笔者关注相关的内容有一定的时间,也写过很多关于爬虫的系列,现在收集好的框架希望能为对爬虫有兴趣的人,或者 ...
- 跟着官网的例子学Reacjs (一)FilterableProductTable
最近开始学习React,发现最好的方法不是看这个书那个书,而是直接上官网,一步步的跟着学习,真的获益匪浅.许多翻译的书上漏掉的知识点都可以学到. 入门的一些准备工作可以参照官网的步骤,引入依赖的核心包 ...
- Stream Player control
In this article you will find an implementation of a stream player control. Download WPF demo - 11 M ...
- ado.net 用c#与数据库连接实现增删改查
ADO.NET: 数据访问技术 就是将C#和MSSQL连接起来的一个纽带 可以通过ADO.NET将内存中的临时数据写入到数据库中 也可以将数据库中的数据提取到内存中供程序调用 是所有数据访问技术的基础 ...
- LINQ的First与FirstOrDefault方法和Last与LastOrDefault方法。
First与FirstOrDefault的方法,均是返回集合中的第一个元素,区别在于如果没有结果,前者(First)会有抛出异常,后者(FirstOrDefault)会返回默认值.Last与LastO ...
- 基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码
在Web开发的时候,我们很多时候,需要引用很多CSS文件.JS文件,随着使用更多的插件或者独立样式文件,可能我们的Web界面代码会越来越臃肿,看起来也很累赘,在MVC里面提供了一个Bundle的对象, ...
- Chrome 35个开发者工具的小技巧
来源:w3cplus - 南北(@ping4god) 网址:http://www.w3cplus.com/tools/dev-tips.html 谷歌浏览器如今是Web开发者们所使用的最流行的网页浏览 ...