console.log实现原理
Function.toString()进行返回的
Function对象覆盖了从object继承来的Object.prototype.tostring方法,函数的tosting方法会返回一个表示函数源代码的字符串。具体来说,包括 function关键字,形参列表,大括号,以及函数体中的内容。
两个对象,显示出来的属性不一样多,但是点进去之后属性是一样的。这个怎么解释?
console.log只是输出一个对象的引用,鼠标点开的时候,会去内存里取这个引用,取到的是最后的值。
你两次consoel.log的是同一个变量,所以log出来的是同一个对象的引用
解决:
function recurse(node) {
if (node.children) node.children.forEach(recurse);
console.log("处理前",node);
var innerNode=$.extend(innerNode,node,true);
console.log("处理前innerNode",innerNode);
if (!node.id) node.id = ++i;
console.log("处理后",node);
nodes.push(node);
}
在Vue处理
核心逻辑:
1.先生成一个纯净的对象
2.遍历原型上的属性 如果是构造函数就跳过
3.获取它的访问描述符,重新生成挂载到desc(访问描述符上)
4.类似vue 2.x的源码实现,使用下面的API,指定属性读取劫持,例如我使用console.log时候,就会触发 Reflect.defineProperty(globalConsole, prop, desc)
5.真正的原理在后面,constructor的Console上
遍历了一次,将consoleMethods的方法都拷贝到了Console的原型上,这样我们就可以调用console.log了
那么log方法怎么实现的呢?
最终是靠this.kWriteToConsole,也就是Console实现(kWriteToConsole是一个Symbol临时属性)
关键这里kUseStdout也是一个Symbol临时属性,kFormatForStdout有一丢丢绕,我们看看kFormatForStdout
Console.prototype[kGetInspectOptions] = function(stream) {
let color = this[kColorMode];
if (color === 'auto') {
color = stream.isTTY && (
typeof stream.getColorDepth === 'function' ?
stream.getColorDepth() > 2 : true);
}
const options = optionsMap.get(this);
if (options) {
if (options.colors === undefined) {
options.colors = color;
}
return options;
}
return color ? kColorInspectOptions : kNoColorInspectOptions;
};
处理完打印颜色配置,进入最终函数:
Console.prototype[kWriteToConsole] = function(streamSymbol, string) {
const ignoreErrors = this._ignoreErrors;
const groupIndent = this[kGroupIndent];
const useStdout = streamSymbol === kUseStdout;
const stream = useStdout ? this._stdout : this._stderr;
const errorHandler = useStdout ?
this._stdoutErrorHandler : this._stderrErrorHandler;
出现错误的时候
if (ignoreErrors === false) return stream.write(string);
try {
// Add and later remove a noop error handler to catch synchronous errors.
if (stream.listenerCount('error') === 0)
stream.once('error', noop);
stream.write(string, errorHandler);