google closure繼承模塊三:goog.base()源碼分析
直接看代碼吧:
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);
浙公網安備 33010602011771號