function People() {
}
People.prototype.say = function () {
alert("hello");
}
function Student() {
}
Student.prototype = new People();
var superSay = Student.prototype.say;
Student.prototype.say = function () {
superSay.call(this); // 為什么會是"hello"?
alert("stu-hello");
}
var s = new Student();
s.say();
superSay.call(this)
為什么會是People.prototype.say
函數(shù)被調(diào)用?this
? this指向Student{}
類,這個你可以在superSay.call(this)
上面加一行console.log(this)
進行驗證。
然后,我們看這個代碼
Student.prototype = new People();
為了方便后面解釋,我把這里的new People()
創(chuàng)建的實例稱為實例X
。
由于superSay = Student.prototype.say
,因為上面的Student.prototype = new People();
,所以其中Student.prototype
為實例X
。
所以實際上superSay
調(diào)用的是實例X
的say
,而并非People.prototype.say
。
至于你為啥覺得是在調(diào)用People.prototype.say
,主要還是原型鏈的問題。實例X
是People類的一個實例,所以實例X
的所有方法會從People類的原型鏈“繼承”(用繼承這個詞,但是實際上JS的原型鏈和繼承還是有些區(qū)別的)。所以實例X.say
如果沒有針對實例X
重寫say
方法,那么實例X
的say
就和People.prototype.say
等效。
另外,superSay.call(this)
這個里面的call
,只是改變了this
的上下文而已。但是由于superSay
即實例X.say
,這個方法里根本沒有this
,所以this
上下文的修改并不影響運行的結(jié)果。
個人觀點:先說下查找say方法的查找順序吧:s——student.prototype——people.prototype——Object,找到則就緒,停止查找。結(jié)合你的代碼,say只會查找到student.prototype。這里可以先把你的代碼先改成這樣就比較清晰:
People.prototype.say = function () {
console.log(123);
}
People.prototype.jiao = function () {
console.log(456);
}
Student.prototype.say = function () {
console.log(321)
}
其他不變。此時s.say()——輸出321,s.jiao()——輸出456。然后再回到你的代碼,因為你這是重寫了sdudent.prototype.say方法所以會執(zhí)行此段代碼
Student.prototype.say = function () {
superSay.call(this); // 為什么會是"hello"?
alert("stu-hello");
}
第一句superSay.call(this),首先superSay是一個變量,變量類型是function,你可以在 var superSay = Student.prototype.say后面加上一段代碼console.log(typeof supperSay),于是你只是在調(diào)用這個函數(shù),而這個變量儲存的是Student.prototype.say。執(zhí)行到var superSay = Student.prototype.say,其實這里賦值的是 People.prototype.say。這點在高程的166-167頁有類似的。關(guān)于這點你可以再把你的代碼這2段換成這樣,其他不變。
var superSay = Student.prototype.say;
Student.prototype = new People();
此時調(diào)用superSay 會報錯,因為此時執(zhí)行到var superSay = Student.prototype.say時;student.prototype只有一個constructer屬性沒有say方法。然后回到你的代碼此時People.prototype.say會賦值給superSay
綜上第一句代碼會輸出hello,而你的call根本沒什么用
第二句就不用說了。
關(guān)于this其實我也不是特別清楚。我原來還認為console.log(this)會輸出S,結(jié)果輸出student,還需繼續(xù)學(xué)習(xí)。
樓上扯這么多不怕樓主蒙圈嗎
他程序里面stuSay指向的是function () {alert("hello");} 這個匿名函數(shù)對象,只要你不重新賦值stuSay,他一直就是指向這個函數(shù)對象,管你在什么地方調(diào)用,永遠就是這么個結(jié)果,至于在函數(shù)體內(nèi)部this指向誰,你看下犀牛書吧....
樓主把犀牛書函數(shù)部分看完就不會有這些問題了,至于樓上扯那么多,真別把樓主扯暈了