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