前言
《本文摘自JavaScript語言精髓》第四章
介紹函數四種調用模式前,我們先來了解一下函數和方法的概念,其實函數和方法本質是一樣,就是稱呼不一樣而已。函數:如果一個函數與任何對象關係,就稱該函數爲函數。方法:如果一個函數作爲一個對象屬性存在,我們就稱之爲方法。接下來就可以開始今天的主體。
JS中參數this在面向對象編程中非常重要,它的值取決於調用的模式。在JS中一共有四種調用模式。方法調用模式、函數調用模式、構造器調用模式和apply調用模式。
接下來就開始進入今天的主題:
方法調用模式
首先是方法調用模式:當一個函數被保存爲對象的一個屬性是,我們稱它爲一個方法,當一個方法被調用時,this被綁定到該對象,如果一個調用表達式包含一個屬性存取表達式(即一個.點表達式或者[subscript]下標表達式),那麼它被當作一個方法調用。
此處方法可以使用this去訪問對象,能在對象中進行取值或者修改對象。通過this可取的它們所屬對象的上下文的方法稱爲公共方法。
函數調用模式
當一個函數並非一個對象的屬性的時候,那麼它被當作一個函數來調用。以此模式調用函數時,this被綁定到全局對象。這是語言設計上的一個錯誤。倘若語言設計正確,那麼當內部函數被調用時,this應該仍然綁定到外部函數的this變量。這個設計錯誤的後果就是方法不能利用內部函數來幫助它工作,因爲內部函數的this被綁定了錯誤的值,所以不能共享改方法對對象的訪問權。
var add = function (a, b) {
return a + b;
};
var myObject = {
value : 0,
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1;
}
};
myObject.increment();
console.log(myObject.value); //1
myObject.increment(2);
console.log(myObject.value); //3
myObject.double = function () {
var that = this;
var helper = function () {
that.value = add(that.value,that.value);
};
helper(); //以函數的形式調用helper,這裏形式被調用時this指向全局對象,瀏覽器中是window,我們這裏提前把this存在that裏面
};
//以方法的形式調用double
myObject.double();
console.log(myObject.value);//6
或者使用bind()方法會創建一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以創建它時傳入 bind()方法的第一個參數作爲 this,傳入 bind() 方法的第二個以及以後的參數加上綁定函數運行時本身的參數按照順序作爲原函數的參數來調用原函數。
myObject.double = function () {
// var that = this;
var helper = function () {
this.value = add(this.value,this.value);
}.bind(this);//bind換綁this
helper();
};
//以方法的形式調用double
myObject.double();
console.log(myObject.value);
構造器調用模式
JS是一門基於原型繼承的語言,這意味着對象可以直接從其他對象繼承屬性。如果在一個函數前面帶上new來調用,那麼將創建一個隱藏連接到該函數的prototype成員的新對象,同時this將綁定到那個新對象上。
function Person(){
this.name = "zhangsan";
this.age = 19;
this.sayHello = function(){
};
}
var p = new Person();
p.sayHello();
構造函數中發this與方法中一樣, 表示對象, 但是構造函數中的對象是剛剛創建出來的對象
關於構造函數中return關鍵字的補充說明
- 構造函數中不需要return, 就會默認的return this
- 如果手動的添加return, 就相當於 return this
- 如果手動的添加return 基本類型; 無效, 還是保留原來 返回this
- 如果手動添加return null; 或return undefiend, 無效
- 如果手動添加return 對象類型; 那麼原來創建的this就會被丟掉, 返回的是 return後面的對象
apply調用模式(上下文調用模式)
上下文模式中this的指向和前三種模式不一樣,它的this指向可以改變,而前三種模式是固定。函數上下文在我理解就是函數作用域。基本語法:apply和call 後面都是跟兩個參數
apply和call第一個參數一樣:表示使用那個對象來調用函數;apply第二個參數是:是一個數組或僞數組,數組的值做爲函數的參數被傳入;call第二個參數是:是基本數據類型(number string boolean);案例如下:
function print(a, b, c, d){
alert(a + b + c + d);
}
function example(a, b , c , d){
//用call方式借用print,參數顯式打散傳遞
print.call(this, a, b, c, d);
//用apply方式借用print, 參數作爲一個數組傳遞,
//這裏直接用JavaScript方法內本身有的arguments數組
print.apply(this, arguments);
//或者封裝成數組
print.apply(this, [a, b, c, d]);
}