搜尋

首頁  >  問答  >  主體

javascript - 關於JS的this和建構子問題

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函數被呼叫? this指向誰?

我想大声告诉你我想大声告诉你2714 天前768

全部回覆(5)我來回復

  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-06-26 10:55:14

    this指向Student{}類,這個你可以在superSay.call(this)上面加一行console.log(this)進行驗證。

    然後,我們看這個程式碼

    Student.prototype = new People();

    為了方便後面解釋,我把這裡的new People()創建的實例稱為實例X
    由於superSay = Student.prototype.say,因為上面的Student.prototype = new People();,所以其中Student.prototype實例X
    所以實際上superSay調用的是實例Xsay,而並非People.prototype.say

    至於你為啥覺得是在呼叫People.prototype.say,主要還是原型鏈的問題。 實例X是People類別的實例,所以實例X的所有方法會從People類別的原型鏈中「繼承」(用繼承這個詞,但是實際上JS的原型鍊和繼承還是有些區別的)。所以實例X.say如果沒有針對實例X重寫say方法,那麼實例Xsay就和People.prototype.say等值。

    另外,superSay.call(this)這個裡面的call,只是改變了this的上下文而已。但由於superSay實例X.say,這個方法裡根本沒有this,所以this上下文的修改並不影響運行的結果。

    回覆
    0
  • 迷茫

    迷茫2017-06-26 10:55:14

    這個問題在js中經常遇見

    回覆
    0
  • 代言

    代言2017-06-26 10:55:14

    個人觀點:先說下查找say方法的查找順序吧:s——student.prototype——people.prototype——Object,找到則就緒,停止查找。結合你的程式碼,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方法所以會執行此段程式碼

        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),所以你只是在呼叫這個函數,而這個變數儲存的是Student.prototype.say。執行到var superSay = Student.prototype.say,其實這裡賦值的是 People.prototype.say。這點在高程的166-167頁有類似的。關於這點你可以再把你的程式碼這2段換成這樣,其他不變。

        var superSay = Student.prototype.say;
        Student.prototype = new People();

    此時呼叫superSay 會報錯,因為此時執行到var superSay = Student.prototype.say時;student.prototype只有一個constructer屬性沒有say方法。然後回到你的程式碼此時People.prototype.say會賦值給superSay

    综上第一句代码会输出hello,而你的call根本没什么用
    第二句就不用说了。
    关于this其实我也不是特别清楚。我原来还认为console.log(this)会输出S,结果输出student,还需继续学习。
    

    回覆
    0
  • 我想大声告诉你

    我想大声告诉你2017-06-26 10:55:14

    把superSay建構子中的this綁定為Student.prototype.

    回覆
    0
  • PHP中文网

    PHP中文网2017-06-26 10:55:14

    樓上扯這麼多不怕樓主蒙圈嗎

    他程式裡面stuSay指向的是function () {alert("hello");} 這個匿名函數對象,只要你不重新賦值stuSay,他一直就是指向這個函數對象,管你在什麼地方調用,永遠就是這麼個結果,至於在函數體內部this指向誰,你看下犀牛書吧....

    樓主把犀牛書函數部分看完就不會有這些問題了,至於樓上扯那麼多,真別把樓主扯暈了

    回覆
    0
  • 取消回覆