直接看代码吧:
base: function (me, opt_methodName, var_args) { var caller = arguments.callee.caller; if (caller.superClass_) { // Copying using loop to avoid deop due to passing arguments object to // function. This is faster in many JS engines as of late 2014. var ctorArgs = new Array(arguments.length - 1); for (var i = 1; i < arguments.length; i++) { ctorArgs[i - 1] = arguments[i]; } // This is a constructor. Call the superclass constructor. return caller.superClass_.constructor.apply(me, ctorArgs); } // Copying using loop to avoid deop due to passing arguments object to // function. This is faster in many JS engines as of late 2014. var args = new Array(arguments.length - 2); for (var i = 2; i < arguments.length; i++) { args[i - 2] = arguments[i]; } var foundCaller = false; for (var ctor = me.constructor; ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { if (ctor.prototype[opt_methodName] === caller) { foundCaller = true; } else if (foundCaller) { return ctor.prototype[opt_methodName].apply(me, args); } } // If we did not find the caller in the prototype chain, then one of two // things happened: // 1) The caller is an instance method. // 2) This method was not called by the right caller. if (me[opt_methodName] === caller) { return me.constructor.prototype[opt_methodName].apply(me, args); } else { console.log( 'goog.base called from a method of one name ' + 'to a method of a different name'); } }
goog.base的代码其实并不复杂,
var caller = arguments.callee.caller;
caller是执行goog.base()这个方法的函数名称。通过判断函数是否有superClass_的属性,来区分是否此函数是子构造函数。
(superClass_这个属性就是之前goog.inherit()埋下的伏笔,不仅可以通过这个属性访问父构的原型对象,还可以判断执行goog.base()的函数是否为构造函数)
如果是自构造函数,就把当前子构造函数的this对象和agruments传递给父构造函数,调用父构造函数。通过在自构造函数中调用goog.base(this);
即可以让通过子构造函数创建出来的对象,拥有父构造函数创建出来的一些属性。
这就是为什么之前通过那个只有一个name属性显示“周杰伦”的构造函数A创建出来的新对象,拥有构造函数B,和C创建的一些属性。
(这里需要注意,在调用构造函数必须先用goog.inherit(childCtor,parentCtor)建立起继承关系。)
如果不是子构造函数的话,那么就是另一种可能性就是自构造函数原型对象中的方法。
var args = new Array(arguments.length - 2); for (var i = 2; i < arguments.length; i++) { args[i - 2] = arguments[i]; }
这时候goog.base()的前两个参数一个为作用域对象,一个则是方法名称,剩下的则为传入方法的参数,args即为提取出需要传入方法的参数,
目的是调用继承的父构造函数的原型对象的方法,第二个参数即为调用的方法名称,这个方法名称一般设为调用
goog.base()的子原型对象方法的名称(方法继承)。
for (var ctor = me.constructor; ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { if (ctor.prototype[opt_methodName] === caller) { foundCaller = true; } else if (foundCaller) { return ctor.prototype[opt_methodName].apply(me, args); } }
这一段稍微有点绕,但是目的明确,看起来就不是那么晦涩了,首先ctor为原型对象constructor指向的子构造函数,
if (ctor.prototype[opt_methodName] === caller) { foundCaller = true; }
这段代码是为了检查子构原型对象的方法和调用继承的父构圆形对象的方法是否同名。然后通过
ctor = ctor.superClass_ && ctor.superClass_.constructor
通过superClass_属性,找到父构造函数的原型对象,然后constructor指向的当然是父构造函数,都是存在的。所以
return ctor.prototype[opt_methodName].apply(me, args);