javascript函數(shù)的4種調(diào)用方式與this的指向
javascript 中作用域鏈和 this(上下文)的指向是很容易混淆的,簡單的說就是:
- 作用域鏈取決于函數(shù)聲明的位置,函數(shù)聲明之后,從函數(shù)內(nèi)部往外,一直到window,這就是它的作用域鏈,與函數(shù)調(diào)用位置無關(guān);
- this 指向函數(shù)調(diào)用時的對象,如果是獨立調(diào)用,那就是指向 window,與函數(shù)聲明的位置無關(guān);
函數(shù)調(diào)用的方式有4種,this 也就有4種指向:
- 獨立調(diào)用:func(),函數(shù)獨立調(diào)用,this指向window,;
- 方法調(diào)用:obj.func(),函數(shù)作為obj的一個方法(屬性)調(diào)用,this指向obj;
- 構(gòu)造函數(shù)調(diào)用:new Func(),如果在一個函數(shù)前面帶上 new 關(guān)鍵字來調(diào)用, 那么背地里將會創(chuàng)建一個連接到該函數(shù)的 prototype 的新對象,this指向這個新的對象;
- call、apply、bind調(diào)用:func.call(obj,value1,value2); func.apply(obj,[value1,value2]); func.bind(obj,value1,value2)(); func.bind(obj)(value1,value2); 動態(tài)改變 this 的指向 obj;
獨立調(diào)用和方法調(diào)用
全局環(huán)境中,this 默認指向到 window;
函數(shù)獨立調(diào)用(不論這個函數(shù)在哪調(diào)用),this 默認指向到 window;
當函數(shù)被作為對象的方法(對象的一個屬性)調(diào)用時,this 指向該對象;
函數(shù)只有調(diào)用了之后才有 this 的概念,不然它只是代碼而已,我們經(jīng)常把函數(shù)傳給一個變量,如果后面沒加括號,就只是傳了個函數(shù),而不是執(zhí)行結(jié)果;
<script type="text/javascript">
console.log(this === window);//true 全局環(huán)境中,this默認指向到window
function abc(){
console.log(this === window);
}
abc();//true 函數(shù)abc獨立調(diào)用(不論這個函數(shù)在哪調(diào)用),this默認指向到window
function outer(){
function inner(){
console.log(this === window);
}
inner();
}
outer();//true 函數(shù)inner獨立調(diào)用(不論這個函數(shù)在哪調(diào)用),this默認指向到window
var o = {
m: function(){
return this;
},
n: function(){
function test(){
return this;
}
return test(); //函數(shù)test獨立調(diào)用(不論這個函數(shù)在哪調(diào)用),this默認指向到window
}
};
console.log(o.m());//Object o{...} 當函數(shù)被作為對象的方法(對象的一個屬性)運行時,this指向該對象
console.log(o.n());//Window{...} 函數(shù)test獨立調(diào)用,this默認指向到window
</script>當函數(shù)被作為對象的方法調(diào)用時,可以使用 this 訪問自己所屬的對象,所以它能從對象中取值或?qū)ο筮M行修改;
this 到對象的指向發(fā)生在調(diào)用的時候,如果函數(shù)沒有被調(diào)用,則不會更改對象的變量;
通過 this 可取得它們所屬對象的上下文的方法稱為公共方法;
<script type="text/javascript">
var o = {
a: 1,
m: function(){
return this;
},
n: function(){
this.a = 2;
//當函數(shù)被作為對象的方法調(diào)用時,可以使用this訪問自己所屬的對象,所以它能從對象中取值或?qū)ο筮M行修改。
//this到對象的綁定發(fā)生在調(diào)用的時候。所以這里的函數(shù) n 如果沒有調(diào)用過,那么外部的 a 是不會被改變的
}
};
console.log(o.m().a);//1
o.n();
console.log(o.m().a);//2
</script>如果想訪問這個外部函數(shù)的 this 值,需要將 this 的值保存在一個變量里,內(nèi)部函數(shù)就可以通過作用域鏈找到這個變量。
<script type="text/javascript">
var o = {
m: function(){
console.log(this); //{} 當函數(shù)被作為對象的方法(對象的一個屬性)運行時,this指向該對象
},
n: function(){
console.log(this);//{}
var that = this;
//如果想訪問這個外部函數(shù)的this值,需要將this的值保存在一個變量里,內(nèi)部函數(shù)就可以通過作用域鏈找到這個變量。
function test(){
console.log(this);//window
console.log(that);//{}
}
return test(); //函數(shù)test獨立調(diào)用(不論這個函數(shù)在哪調(diào)用),this默認指向到window
}
};
o.m();
o.n();
</script>構(gòu)造函數(shù)調(diào)用
如果一個函數(shù)用 new 關(guān)鍵字調(diào)用,那么這個函數(shù)就是構(gòu)造函數(shù),并且背地里會創(chuàng)建一個連接到該函數(shù)的 prototype 的新對象,this 指向這個新對象;
如果構(gòu)造函數(shù)沒有形參,實例化的時候是可以不帶()的;如 var a = Func; 或者 var a = Func(); 兩種都可以;
同時我們在構(gòu)造函數(shù)的時候有個約定(不是規(guī)范),首字母大寫,以避免忘了寫new關(guān)鍵字或者在普通函數(shù)前面加new;
new 關(guān)鍵字的作用就是執(zhí)行一個構(gòu)造函數(shù),并返回一個對象實例。使用 new 命令,它后面的函數(shù)的函數(shù)調(diào)用和普通函數(shù)調(diào)用就不一樣了,步驟如下:
- 創(chuàng)建一個空對象,作為將要返回的對象實例;
- 將空對象的原型 proto 指向構(gòu)造函數(shù)的 prototype 屬性;
- 將構(gòu)造函數(shù)內(nèi)部的this關(guān)鍵字指向空對象;
- 執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼;
就是說 this 指向這個新對象,構(gòu)造函數(shù)內(nèi)所有針對 this 的操作,都會發(fā)生在這個新對象上;
<script type="text/javascript">
// 創(chuàng)建一個名為Person 的構(gòu)造函數(shù),它構(gòu)造一個帶有user 和age 的對象
var Person = function (user,age) {
this.user = user;
this.age = age;
};
// 構(gòu)造一個Person 實例 ,并測試
var shane = new Person ('shane',25);
console.log(shane.user);//shane
console.log(shane.age);//25
</script>javascript 中構(gòu)造函數(shù)是不需要有返回值的,可以認為構(gòu)造函數(shù)和普通函數(shù)之間的區(qū)別就是:構(gòu)造函數(shù)沒有 return 語句,普通函數(shù)可以有 return 語句;
構(gòu)造函數(shù)使用 this 關(guān)鍵字定義變量和方法,當 this 遇到 return 的時候,會發(fā)生指向不明(調(diào)用結(jié)果不明)的問題:
- return 返回的不是一個對象,this 還是指向?qū)嵗ㄐ聦ο螅{(diào)用結(jié)果也還是新對象;
- return 返回的是一個對象,this 就指向這個返回的對象,調(diào)用結(jié)果就是這個返回的對象;
- return 返回的是 null,this 還是指向?qū)嵗?,調(diào)用結(jié)果也還是新對象;
<script type="text/javascript">
var Person = function(){
this.user = 'shane';
return
}
var shane = new Person;
console.log(shane.user);//shane return沒有返回值,this還是指向?qū)嵗ㄐ聦ο螅?,調(diào)用結(jié)果也還是新對象;
var Color = function(){
this.red = 'red';
return 'hello world';
}
var redColor = new Color;
console.log(redColor.red);//red return返回的是一個基本類型的字符串(原始值),this還是指向?qū)嵗ㄐ聦ο螅?,調(diào)用結(jié)果也還是新對象;
var Size = function(){
this.size = 'big';
return {};
}
var sizeBig = new Size;
console.log(sizeBig.size);//undefined return返回的是一個對象,this就指向這個返回的對象,調(diào)用結(jié)果就是這個返回的對象;
</script>間接調(diào)用
通過 call()、apply()、bind() 方法把對象綁定到 this 上,叫做顯式綁定。對于被調(diào)用的函數(shù)來說,叫做間接調(diào)用
- call、apply、bind三者的第一個參數(shù)都是this要指向的對象,
- bind 只是返回函數(shù),還未調(diào)用,所以如果要執(zhí)行還得在后面加個();call、apply 是立即執(zhí)行函數(shù);
- 三者后面都可以帶參數(shù),call 后面的參數(shù)用逗號隔開,apply 后面的參數(shù)以數(shù)組的形式傳入;bind則可以在指定對象的時候傳參,和 call 一樣,以逗號隔開,也可以在執(zhí)行的時候傳參,寫到后面的括號中;func.call(obj,value1,value2); func.apply(obj,[value1,value2]); func.bind(obj,value1,value2)(); func.bind(obj)(value1,value2);
<script type="text/javascript">
var add = function (a,b) {
return a+b;
};
var arr = [2,3];
var sum0 = add.apply(null, arr);//apply后面的參數(shù)以數(shù)組的形式傳入
var sum1 = add.call(null,arr[0],arr[1]);//call后面的參數(shù)用逗號隔開
var sum2 = add.bind(null,arr[0],arr[1]);//bind后面的參數(shù)可以和call一樣,用逗號隔開
var sum3 = add.bind(null); //bind調(diào)用的時候也可以在執(zhí)行的時候傳參
console.log(sum0);//5
console.log(sum1);//5
console.log(sum2);//function (a,b) {return a+b;}; bind只是返回函數(shù),還未調(diào)用,
console.log(sum2());//5 所以bind調(diào)用的時候,如果要執(zhí)行還得在后面加個()
console.log(sum3(arr[0],arr[1]));//5 bind調(diào)用的時候也可以在執(zhí)行的時候傳參
</script>嚴格模式下
- 在嚴格模式下,未指定環(huán)境對象而調(diào)用函數(shù),則 this 值不會轉(zhuǎn)型為 window。 除非明確把函數(shù)添加到某個對象或者調(diào)用 apply() 或 call(),否則 this 值將是 undefined;
- 所以我們可以手動添加 window.函數(shù)(),將 this 指向 window;
<script type="text/javascript">
'use strict' //嚴格模式
function a(){
console.log (this);
}
a();//undefined
//在嚴格模式下,未指定環(huán)境對象而調(diào)用函數(shù),則 this 值不會轉(zhuǎn)型為 window , this 值將是 undefined。
//除非明確把函數(shù)添加到某個對象或者調(diào)用 apply()或 call()使用對象冒充。
window.a();//window
//所以我們可以手動添加 window.函數(shù)(),來改變this指向window
(function(){
console.log(this);//undefined
})();
setTimeout(function(){
console.log(this);//Window
},0);
//setTimeout是window的一個方法(屬性),所以這里可以寫成window.setTimeout
//所以不管是嚴格模式還是非嚴格模式,setTimeout里的this始終指向window
//但是有時候我們會發(fā)現(xiàn)setTimeout中的this也有其他情況,這只是誤導(dǎo),當然如果你不確定的話,直接console.log(this)一下,分分鐘解決
</script>以上就是javascript函數(shù)的4種調(diào)用方式與this的指向的詳細內(nèi)容,更多關(guān)于javascript函數(shù)調(diào)用與this指向的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Bootstrap基本樣式學(xué)習(xí)筆記之表格(2)
Bootstrap提供了一個清晰的創(chuàng)建表格的布局,這篇文章主要介紹了Bootstrap學(xué)習(xí)筆記之表格基本樣式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12
JavaScript接口防止重復(fù)請求的方法總結(jié)
在前端開發(fā)中,防止重復(fù)請求是一個常見的問題,重復(fù)請求不僅會增加服務(wù)器的負載,還可能導(dǎo)致數(shù)據(jù)不一致等問題,本文為大家整理了一些常用的解決方法,需要的可以參考下2024-12-12
微信小程序?qū)崿F(xiàn)倒計時調(diào)用相機自動拍照功能
這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)倒計時調(diào)用相機自動拍照功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06

