js中的4種函數調用模式 javascript一共有4種調用模式:函數調用模式、方法調用模式、構造器調用模式和間接調用模式。 【1】函數調用模式 當一個函數並非一個對象的屬性時,那麼它就是被當做一個函數來調用的。對於普通的函數調用來說,函數的返回值就是調用表達式的值 使用函數調用模式調用函數時,非嚴 ...
js中的4種函數調用模式
javascript一共有4種調用模式:函數調用模式、方法調用模式、構造器調用模式和間接調用模式。
【1】函數調用模式
當一個函數並非一個對象的屬性時,那麼它就是被當做一個函數來調用的。對於普通的函數調用來說,函數的返回值就是調用表達式的值
function add(x,y){
return x+y;
}
var sum = add(3,4);
console.log(sum)//7
使用函數調用模式調用函數時,非嚴格模式下,this被綁定到全局對象;在嚴格模式下,this是undefined
function add(x,y){
console.log(this);//window
}
add();
function add(x,y){
'use strict';
console.log(this);//undefined
}
add();//window
因此,’this’可以用來判斷當前是否是嚴格模式
var strict = (function(){return !this;}());
重寫
因為函數調用模式的函數中的this綁定到全局對象,所以會發生全局屬性被重寫的現象
var a = 0;
function fn(){
this.a = 1;
}
fn();
console.log(this,this.a,a);//window 1 1
【2】方法調用模式
當一個函數被保存為對象的一個屬性時,我們稱它為一個方法。當一個方法被調用時,this被綁定到該對象。如果調用表達式包含一個提取屬性的動作,那麼它就是被當做一個方法來調用
var o = {
m: function(){
console.log(1);
}
};
o.m();//1
方法可以使用this訪問自己所屬的對象,所以它能從對象中取值或對對象進行修改。this到對象的綁定發生在調用的時候。通過this可取得它們所屬對象的上下文的方法稱為公共方法。
var o = {
a: 1,
m: function(){
return this;
},
n: function(){
this.a = 2;
}
};
console.log(o.m().a);//1
o.n();
console.log(o.m().a);//2
任何函數只要作為方法調用實際上都會傳入一個隱式的實參——這個實參是一個對象,方法調用的母體就是這個對象,通常來講,基於那個對象的方法可以執行多種操作,方法調用的語法已經很清晰地表明瞭函數將基於一個對象進行操作
rect.setSize(width,height);
setRectSize(rect,width,height);
假設上面兩行代碼的功能完全一樣,它們都作用於一個假定的對象rect。可以看出,第一行的方法調用語法非常清晰地表明這個函數執行的載體是rect對象,函數中的所有操作都將基於這個對象
和變數不同,關鍵字this沒有作用域的限制,嵌套的函數不會從調用它的函數中繼承this。如果嵌套函數作為方法調用,其this的值指向調用它的對象。如果嵌套函數作為函數調用,其this值不是全局對象(非嚴格模式下)就是undefined(嚴格模式下)
var o = {
m: function(){
function n(){
return this;
}
return n();
}
}
console.log(o.m());//window
var o = {
m: function(){
function n(){
'use strict';
return this;
}
return n();
}
}
console.log(o.m());//undefined
如果想訪問這個外部函數的this值,需要將this的值保存在一個變數里,這個變數和內部函數都同在一個作用域內。通常使用變數self或that來保存this
var o = {
m: function(){
var self = this;
console.log(this === o);//true
function n(){
console.log(this === o);//false
console.log(self === o);//true
return self;
}
return n();
}
}
console.log(o.m() === o);//true
【3】構造函數調用模式
如果函數或者方法調用之前帶有關鍵字new,它就構成構造函數調用
function fn(){
this.a = 1;
};
var obj = new fn();
console.log(obj.a);//1
如果構造函數調用在圓括弧內包含一組實參列表,先計算這些實參表達式,然後傳入函數內
function fn(x){
this.a = x;
};
var obj = new fn(2);
console.log(obj.a);//2
如果構造函數沒有形參,javascript構造函數調用的語法是允許省略實參列表和圓括弧的。凡是沒有形參的構造函數調用都可以省略圓括弧
var o = new Object();
//等價於
var o = new Object;
[註意]儘管構造函數看起來像一個方法調用,它依然會使用這個新對象作為調用上下文。也就是說,在表達式new o.m()中,調用上下文並不是o
var o = {
m: function(){
return this;
}
}
var obj = new o.m();
console.log(obj,obj === o);//{} false
console.log(obj.constructor === o.m);//true
構造函數通常不使用return關鍵字,它們通常初始化新對象,當構造函數的函數體執行完畢時,它會顯式返回。在這種情況下,構造函數調用表達式的計算結果就是這個新對象的值
function fn(){
this.a = 2;
}
var test = new fn();
console.log(test);//{a:2}
如果構造函數使用return語句但沒有指定返回值,或者返回一個原始值,那麼這時將忽略返回值,同時使用這個新對象作為調用結果
function fn(){
this.a = 2;
return;
}
var test = new fn();
console.log(test);//{a:2}
如果構造函數顯式地使用return語句返回一個對象,那麼調用表達式的值就是這個對象
var obj = {a:1};
function fn(){
this.a = 2;
return obj;
}
var test = new fn();
console.log(test);//{a:1}
【4】間接調用模式
javascript中函數也是對象,函數對象也可以包含方法。call()和apply()方法可以用來間接地調用函數
這兩個方法都允許顯式指定調用所需的this值,也就是說,任何函數可以作為任何對象的方法來調用,哪怕這個函數不是那個對象的方法。兩個方法都可以指定調用的實參。call()方法使用它自有的實參列表作為函數的實參,apply()方法則要求以數組的形式傳入參數
var obj = {};
function sum(x,y){
return x+y;
}
console.log(sum.call(obj,1,2));//3
console.log(sum.apply(obj,[1,2]));//3