之前做项目的时候,有个bug需要在ie8调试,所以加了console.log,但是这个方法好像在ie8上用不了,后来在网上找了个封装了console对象的代码,用于调试,这个代码应该是从源码抄过来的,值得研究下,代码如下:
window._console = window.console;//将原始console对象缓存
window.console = (function (orgConsole) {
return {//构造的新console对象
log: getConsoleFn("log"),
debug: getConsoleFn("debug"),
info: getConsoleFn("info"),
warn: getConsoleFn("warn"),
exception: getConsoleFn("exception"),
assert: getConsoleFn("assert"),
dir: getConsoleFn("dir"),
dirxml: getConsoleFn("dirxml"),
trace: getConsoleFn("trace"),
group: getConsoleFn("group"),
groupCollapsed: getConsoleFn("groupCollapsed"),
groupEnd: getConsoleFn("groupEnd"),
profile: getConsoleFn("profile"),
profileEnd: getConsoleFn("profileEnd"),
count: getConsoleFn("count"),
clear: getConsoleFn("clear"),
time: getConsoleFn("time"),
timeEnd: getConsoleFn("timeEnd"),
timeStamp: getConsoleFn("timeStamp"),
table: getConsoleFn("table"),
error: getConsoleFn("error"),
memory: getConsoleFn("memory"),
markTimeline: getConsoleFn("markTimeline"),
timeline: getConsoleFn("timeline"),
timelineEnd: getConsoleFn("timelineEnd")
};
function getConsoleFn(name) {
return function actionConsole() {
if (typeof (orgConsole) !== "object") return;
if (typeof (orgConsole[name]) !== "function") return;//判断原始console对象中是否含有此方法,若没有则直接返回
return orgConsole[name].apply(orgConsole, Array.prototype.slice.call(arguments));//调用原始函数
};
}
}(window._console));
这里面比较有意思的是getConsoleFn方法,这个方法通过apply和call方法,调用了console对象的原始函数,下面分析这个方法里用到的其他方法。
首先引入三个方法的介绍:
1、slice方法:英文意为截取,类似subString,具体用法很简单,这里不做介绍,如果忘了的同学可百度。
这个方法有两个,一个是String对象的slice,截取字符串用的,第二个是Array对象的slice方法,截取数组用的。这两个方法的作用是一样,只是作用的对象不一样,所以分别定义在两个对象下面;
2、call方法,总结地来说,这个方法的作用是转换this引用的对象。
具体的介绍是:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.functionX.call(A,args1,args2...);即A对象调用B对象的方法functionX。
这里做了一个this引用的转换,把functionX原先的this对象B转换成了A,所以等价于((B)A).functionX(args1,args2...)。其中call方法还多做了一件事,把A对象转化成B对象, 因为functionX是B对象里的,A对象里不一定有该方法。args1,args2代表多个参数列表,类似于java里的String...
3、apply方法,和call方法作用一致,而不同之处在于传递的参数,apply最多只能有两个参数——新this对象和一个数组argArray,如果arg不是数组则会报错TypeError
下面开始分析getConsoleFn方法做了什么事:
return orgConsole[name].apply(orgConsole, Array.prototype.slice.call(arguments));//调用原始函数
抛开方法第1、2行不痛不痒的判断,直接看上面这行代码,orgConsole[name]是console对象的某个方法,例如:console.log。arguments是调此方法的入参,例如:console.log("123")。
那么这行代码可以理解为:
return console.log.apply(orgConsole, Array.prototype.slice.call("123"));//调用原始函数
这个代码的第一步是执行Array.prototype.slice.call("123"),等价于:toArray ("123").slice()。此处将字符串"123"转Array的过程如下:
var toArray = function(s){
var args = [];
for (var i = 1; i < s.length; i++) { //必须带有length属性才能转Array,字符串带length属性,所以能转
args.push(s[i]);
}
}
slice方法没有参数,所以返回了Array对象本身,我感觉slice方法啥事没干,相当于是个工具人,只是为了配合call方法把参数转成Array。
经过上面的分析,此时这行代码可以理解为:
return console.log.apply(orgConsole, toArray("123"));//调用原始函数
最后把apply方法转换成:
return orgConsole.log(toArray("123"));//调用原始函数
回到最初的代码,可以看到orgConsole变量值为window.console,所以getConsoleFn最终形态为:
return window.console.log(toArray("123"));//调用原始函数
这样是不是就很容易理解了。