最近出了一些事情,好久沒有寫博客了,再次拿起也不知道要寫什麼,偶然閱讀到一篇文章。本篇短文大部份內容出自《JavaScript語言精粹》一書,有興趣的同窗能夠去購買閱讀,很棒的一本書,是js大師 道格拉斯·克羅克福德 的做品,不適合初學者。javascript
調用一個函數時,會暫停當前函數的執行,傳遞控制權和參數給新函數(被調用的函數)。除了被調用的函數聲明時的形參,每一個函數還接收兩個附加的參數:this和arguments。參數this在面向對象編程中很是重要,它的值取決於調用的模式。在JavaScript中函數有4種調用模式:方法調用模式、函數調用模式、構造器調用模式和apply(call)調用模式。這些調用模式在如何初始化this上存在差別。java
方法調用模式編程
當一個函數被保存爲對象的一個屬性時,咱們稱它爲一個方法。當一個對象的方法被調用時,this被綁定到調用方法的對象。數組
var myObj = { name : "MT", setName : function(name){ this.name = name; } }; myObj.setName("哀木涕"); console.log(myObj.name); //"哀木涕" myObj.setName("小德"); console.log(myObj.name); //小德
方法可使用this訪問本身所屬的對象,因此它能從對象中取值或對對象進行修改。this和對象的綁定發生在方法調用的時候。這個「超級」延遲綁定(vary late binding)使得函數能夠對this高度複用。經過this能夠取得它們所屬對象的上下文方法稱爲公共方法(public method)。app
函數調用模式編程語言
當一函數並不是一個對象的屬性時,那麼它就是被當作一個函數來調用的:函數
var sum = add(1,2); //sum的值爲3。
以此模式調用函數時,this被綁定到全局對象。這是語言設計上的一個錯誤。假若語言設計正確,那麼當內部函數被調用時,this應該仍然綁定到外部函數的this變量。這個設計錯誤的後果就是方法不能利用內部函數來幫助它工做,由於內部函數的this被綁定了錯誤的值(全局對象),因此不能共享該方法對對象的訪問權。幸運的是,有一個很容易的解決方案:若是一個對象的方法定義了一個變量並將this賦值給它,那麼內部函數就能夠經過那個變量訪問到外部方法調用的對象。按照約定,咱們把那個變量命名爲that:this
myObj.changeName = function(){ var that = this; //解決方法 var change = function(){ that.name = "change" + that.name; } change(); //以函數的方式調用change; } //以方法的形式調用changeName。 myObj.changeName(); console.log(myObj.name);
構造器調用模式spa
JavaScript是一門基於原型繼承的語言。這意味着對象能夠直接從其餘對象繼承屬性。該語言是無類型的。prototype
若是在一個函數前面帶上 new 關鍵字來調用,那麼背地裏將會建立一個鏈接到該函數的prototype成員的新對象,同時this會被綁定到那個新對象上。
new 前綴也會改變return 語句的行爲,若是return 的值是對象,那麼將會將這個對象返回,不然將返回默認建立的新對象。
//建立一個名爲Person的構造器函數。它構造一個帶有name屬性的對象。 function Person(howName){ this.name = howName; } Person.prototype.getName = function(){ return this.name; } var person = new Person("MT"); console.log(person.getName());
一個函數,若是建立的目的就是但願結合new前綴來調用,那它就被稱爲構造器函數。按照約定,它們保存在以大寫格式命名的變量裏。若是調用構造函數時沒有在前面加上new ,可能會發生很是糟糕的事情,(這時將會以函數的方式調用,因爲函數的方式調用this是全局對象,這時不會返回新對象,而是在全局對象上添加屬性。)既沒有編譯時警告,,也沒有運行時警告,因此大寫約定很是重要。
apply/call調用模式
由於JavaScript是一門函數式的面向對象編程語言,因此函數能夠擁有方法。
apply/call方法容許咱們選擇this的值。apply方法接受兩個參數,第一個是要綁定的this的值,第二個參數是參數數組。call方法第一個參數是要綁定的this的值,後面緊跟的是相關的參數。
function setAge(age){ this.age = age; } setAge.call(myObj, 23); console.log(myObj.age); //23 setAge.apply(myObj, [24]); console.log(myObj.age); //24