我们先学习一下ng一些内置的工具方法:
angular.equals:
(1)两个参数满足===比较返回true;(2)两个参数是同一种类型,同时他们的每一个属性通过angular.equals都是返回true;(3)两个都是NAN(在js中虽然NAN==NAN为false,但是这里为true);(4)两个对象代表同一个正则表达式,如/abc/==/abc/(虽然在js中返回false)
function equals(o1, o2) {
if (o1 === o2) return true;
//两个恒等返回true
if (o1 === null || o2 === null) return false;
//只要有一个参数为null,那么结果就是false
if (o1 !== o1 && o2 !== o2) return true;
// NaN === NaN,也就是如果两个参数都是NaN,那么就会返回true
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
if (t1 == t2) {
//两者类型相同
if (t1 == 'object') {
if (isArray(o1)) {
//如果第一个参数为Array类型,但是第二个不是Array类型就返回false
if (!isArray(o2)) return false;
//如果第一个参数为Array类型,而且两个参数也是Array类型,同时length相同,那么逐个进行比较
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类型那么比较getTime值
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;
}
angular.copy:
创建来源source的一个深度克隆对象,可以是一个对象或者数组。如果没有指定destination那么就会返回一个object或者array的副本;如果destination为一个对象,那么首先会删除这个对象上面所有的属性然后把来源source的属性拷贝到上面;如果来源source不是一个对象或者数组那么返回来源source本身(如null/undefined)
angular.bind:
var obj = {
name: 'xxx',
print: function (country) {
console.log(this.name + ' is form ' + country);
}
};
var self = {
name: 'yyy'
};
//var bindFn = angular.bind(self, obj.print, 'China');
var bindFn = angular.bind(self, obj.print, ['China']);
bindFn(); //$ yyy is form China
其实这个函数内部实现机制不用说肯定是如下的方式:
function bind(fn,context){
var outerArgs=Array.prototype.slice.call(arguments,2);
return function(){
var innerArgs=Array.prototype.slice.call(arguments);
var finalArgs=outerArgs.concat(innerArgs);
return fn.apply(context,finalArgs);
}
}
不过,这个函数有一点不同的是,其
bind如果传入多于两个参数其第三个参数可以传入一个数组或者逐个参数传递,下面展示的是ng内部提供的bind函数源码:
function bind(self, fn) {
var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
if (isFunction(fn) && !(fn instanceof RegExp)) {
return curryArgs.length
? function() {
return arguments.length
? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
: fn.apply(self, curryArgs);//如果传入的第三个参数为数组那么同时返回的绑定后函数调用时候没有传入参数就会走这里的逻辑逐个封装
}
: 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;
}
}
而我们自己的bind函数只会只有apply来调用,所以就会出现如下的情况:
function bind(fn,context){
var outerArgs=Array.prototype.slice.call(arguments,2);
return function(){
var innerArgs=Array.prototype.slice.call(arguments);
var finalArgs=outerArgs.concat(innerArgs);
return fn.apply(context,finalArgs);
}
}
function test(name,sex){
console.log(name);
//这里打印的是['name','sex']
console.log(sex);
//这里打印的为undefined
}
var obj={name:'qinliang'};
var func=bind(test,obj,['name','sex']);
//这时候outerArgs的值为[['name','sex']]
func();
angular.extend(dst, src):
用于扩展dst对象,把src中可以枚举的属性全部封装到dst对象上面。你可以指定多个src对象用于扩展dst对象,当然你也可以指定目标对象为一个空对象,var object = angular.extend({}, object1, object2)。注意: 这个方法不支持深度克隆
<em> </em> var dst = {name: 'xxx', country: 'China',school:{name:'DLUT',location:'DL'}};
var src = {name: 'yyy', age: 10,school:{name:'zhejiang',location:'HZ'}};
angular.extend(dst, src);
console.log(src); //$ Object {name: "yyy", age: 10}
console.log(dst); //$ Object {name: "yyy", country: "China", age: 10}
从这个例子中,我们可以清楚的看到,对于school属性来说都是一个对象,而后面的对象会直接覆盖前面的对象,而
jQuery.extend是可以实现深度克隆的。我们看看其中的源码:
function extend(dst) {
var h = dst.$$hashKey;
forEach(arguments, function(obj) {
if (obj !== dst) {
forEach(obj, function(value, key) {
dst[key] = value;
});
}
});
setHashKey(dst,h);
return dst;
}
angular.forEach:
var obj = {name: 'xxx', country: 'China'};
angular.forEach(obj, function (value, key) {
console.log(key + ':' + value);
});
//$ name:xxx
//$ country:China
var array = ['xxx', 'yyy'];
angular.forEach(array, function (item, index) {
console.log(index + ':' + item + ' form ' + this.country);
}, obj);
这个方法和jQuery的$.each方法具有相似的签名,这个方法如果传入了第三个参数就是绑定了函数中的this指向
angular.fromJson(string):
var json = angular.fromJson('{"name":"xxx","age":34}');
console.log(json); //$ Object {name: "xxx", age: 34}
其内部还是使用的JSON.parse来完成的:
function fromJson(json) {
return isString(json)
? JSON.parse(json)
: json;
}
angular.toJson(json,pretty):
用于把一个json对象转化为JSON字符串,其内部还是使用了JSON.Stringify完成的,第二个参数表示是否美化输出字符串
function toJson(obj, pretty) {
if (typeof obj === 'undefined') return undefined;
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
}
用法如下:
angular.toJson({name:'xxx'});
//$"{"name":"xxx"}"
angular.toJson({name:'xxx'},true);
//$ "{
//$ "name": "xxx"
//$ }"
angular.toJson({name:'xxx'},10);
//$ "{
//$ "name": "xxx"
//$ }"
angular.identity(value)
返回这个函数的第一个参数
function identity($) {return $;}
使用方式如下:
console.log(angular.identity('xxx','yyy')); //$ xxx
angular.isArray:
var isArray = (function() {
if (!isFunction(Array.isArray)) {
return function(value) {
return toString.call(value) === '[object Array]';
};
}
return Array.isArray;
})();
用于判断参数是否为一个数组
angular.isDate:
function isDate(value) {
return toString.call(value) === '[object Date]';
}
angualr.isDefined:
function isDefined(value){return typeof value !== 'undefined';}//是否被声明过
angular.isUndefined:
function isUndefined(value){return typeof value === 'undefined';}
angular.isFunction:
function isFunction(value){return typeof value === 'function';}
angular.isNumber
function isNumber(value){return typeof value === 'number';}
注意:这时候isNumber(Number(2))返回true,因为Number相当于转化,而isNumber(new Number(3))返回false,因为后者返回object
angular.isOject
function isObject(value){return value != null && typeof value === 'object';}
注意:这时候null不再是返回'object'类型了,同时isObject(function(){})也是返回false,因为其typeof返回'function'
angular.isString:
function isString(value){return typeof value === 'string';}
这个方法只能用于判断是否是基本数据类型
angular.lowerCase:
var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
注意:这个方法只能处理string类型,其它类型原样返回
angular.upperCase:
var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
注意:这个方法也是只会处理string类型的
angular.loop:
function noop() {}
就是返回一个空函数
angular.element:
如果jQuery对象存在,那么angular.element就是jQuery函数的别名,如果jQuery不存在那么angular.element就会使用angular内置的jQuery子集‘jQuery lite’或者'jqLite'