this和執(zhí)行上下文實(shí)現(xiàn)代碼
更新時(shí)間:2010年07月01日 23:08:23 作者:
Javascript中this關(guān)鍵字通常指向當(dāng)前函數(shù)的擁有者。在javascript中通常把這個(gè)擁有者叫做執(zhí)行上下文。
函數(shù)的執(zhí)行上下文由當(dāng)前的運(yùn)行環(huán)境而定:
1. 全局變量和全局函數(shù)附屬于全局對(duì)象(window),因此使用”var”或”this”兩種方法定義全局變量是等效的。
2. 執(zhí)行上下文和作用域不同。執(zhí)行上下文在運(yùn)行時(shí)確定,隨時(shí)可能改變,而作用域則在定義時(shí)確定,永遠(yuǎn)不會(huì)變。
3. 如果當(dāng)前執(zhí)行的是一個(gè)對(duì)象的方法,則執(zhí)行上下文就是這個(gè)方法所附屬的對(duì)象。
4. 如果當(dāng)前是一個(gè)創(chuàng)建對(duì)象的過(guò)程或者執(zhí)行一個(gè)對(duì)象的方法,則執(zhí)行上下文就是這個(gè)正在被創(chuàng)建的對(duì)象。
5. 如果一個(gè)方法在執(zhí)行時(shí)沒(méi)有明確指定附屬對(duì)象,則這個(gè)方法的上下文為全局對(duì)象。
6. 使用call和apply可以改變對(duì)象的執(zhí)行上下文。
看下面的例子:
var v1 = "global variable"; //全局變量附屬于對(duì)象
//this.v1 = "global variable with this"; //全局變量定義時(shí)使用var v1和this.v1兩種方法等效。
function func1(){
var v1 = "part variable";
writeHtml(v1);
writeHtml(this.v1);
}
func1(); //part variable
//global variable
因?yàn)閒unc1中有和全局對(duì)象同名的v1變量,所以在func1中直接引用v1引用的是func1中定義的變量。javascript同樣有局部變量隱藏全局變量的特性。但func1沒(méi)有明確的指定附屬對(duì)象,因此他的執(zhí)行上下文是全局對(duì)象,使用this引用變量的是全局變量。
再看一個(gè)稍微復(fù)雜一點(diǎn)的例子:
function ftest(){
var v = "v1v1v1";
this.this_v = "this_v";
return function(){
writeHtml(v);
writeHtml(this.this_v);
}
}
var a = ftest();
var v = "v2v2v2";
writeHtml(this_v); // this_v
a(); //v1v1v1
//this_v
當(dāng)ftest當(dāng)做函數(shù)來(lái)執(zhí)行時(shí),上下文為全局對(duì)象。所以在ftest中使用this定義的變量成為了全局變量。所以我們?cè)趂test外面直接使用變量名訪問(wèn)this_v的值。但是,由于ftest中返回的匿名函數(shù)是定義在ftest內(nèi)部的,所以這個(gè)匿名函數(shù)的作用域就是在ftest內(nèi)部。因此當(dāng)有全局變量v和局部變量v同名時(shí),這個(gè)匿名函數(shù)訪問(wèn)到的是ftest內(nèi)部定義的變量v。
接下來(lái)把ftest當(dāng)做類,使用new關(guān)鍵字來(lái)實(shí)例化:
function ftest(){
var v = "v1v1v1";
this.this_v = "this_v";
return function(){
writeHtml(v);
writeHtml(this.this_v);
}
}
var a = new ftest();
var v = "v2v2v2";
//writeHtml(this_v); // 錯(cuò)誤:this_v未定義
a(); //v1v1v1
//undefined
把ftest當(dāng)做對(duì)象來(lái)實(shí)例化時(shí),在對(duì)象的創(chuàng)建過(guò)程中,上下文為被創(chuàng)建的對(duì)象本身。注意,這個(gè)時(shí)候創(chuàng)建的對(duì)象是ftest的實(shí)例,而創(chuàng)建完成以后又返回了一個(gè)函數(shù),這導(dǎo)致了new ftest()實(shí)例化后返回的是一個(gè)函數(shù),而不是ftest()實(shí)例化后對(duì)象的引用。因此,這個(gè)已經(jīng)實(shí)例化的對(duì)象無(wú)法被引用。當(dāng)我們定義這個(gè)被返回的函數(shù)時(shí),因?yàn)闆](méi)有用this指定這個(gè)函數(shù)的上下文,因此這個(gè)被返回的函數(shù)上下文為全局對(duì)象,作用域?yàn)閒test()函數(shù)內(nèi)部。所以函數(shù)a()執(zhí)行時(shí)的由于上下文中沒(méi)有定義this_v變量,導(dǎo)致了訪問(wèn)錯(cuò)誤。
注意,上面的代碼:
function ftest(){
return function(){
}
}
這樣的形式并不是一個(gè)靜態(tài)封裝環(huán)境,靜態(tài)封裝環(huán)境應(yīng)該是:在一個(gè)函數(shù)定義完成后立即執(zhí)行,并且執(zhí)行完成后返回函數(shù)中的某一個(gè)內(nèi)部函數(shù)。
我們看下面一個(gè)例子,觀察作用域和上下文對(duì)變量引用的影響。
var v = "global variable";
function method(){
writeHtml(v);
writeHtml(this.v);
}
var Class1 = function(){
var v = "private variable";
this.v = "object variable";
var method2 = method;
this.method2 = method;
var method3 = function(){
writeHtml(v);
writeHtml(this.v);
}
this.method3 = function(){
writeHtml(v);
writeHtml(this.v);
}
method2(); //global variable
//global variable
this.method2(); //global variable
//object variable
method3(); //private variable
//global variable
this.method3();//private variable
//object variable
}
var obj = new Class1();
由于method在全局中定義,所以method的作用域在定義的時(shí)候就被確定為全局的。所以method2在Class1內(nèi)部被調(diào)用時(shí),其作用域與是全局,上下文是全局對(duì)象。因此,在函數(shù)中訪問(wèn)到的變量都是全局變量。
同理,this.method2在被調(diào)用時(shí),其作用域是全局,但是由于該函數(shù)在定義時(shí)使用this關(guān)鍵字指明了其上下文為Class1的對(duì)象,所以在該函數(shù)訪問(wèn)沒(méi)有上下文限定的變量時(shí)訪問(wèn)到的是全局變量,訪問(wèn)有上下文限定的變量時(shí)為訪問(wèn)到的是當(dāng)前上下文中對(duì)應(yīng)的變量。
在調(diào)用method3和this.method3時(shí),在訪問(wèn)沒(méi)有上下文限定的變量時(shí)訪問(wèn)到的是局部變量,因?yàn)榫植孔兞侩[藏了全局變量。有上下文限定時(shí)和method2相同,訪問(wèn)到的是當(dāng)前上下問(wèn)文中的變量。
使用call和apply可以改變執(zhí)行上下文,由于call和apply只是參數(shù)類型不一樣,因此例子下面都用call來(lái)演示。
var v = "global variable";
var method = function(){
writeHtml(this.v);
}
var Class2 = function(){
this.v = "object variable in instance of Class2";
this.method = function(){
writeHtml(this.v);
}
}
var Class3 = function(){
this.v = "object variable in instance of Class3";
this.method = function(){
writeHtml(this.v);
}
}
var obj2 = new Class2();
var obj3 = new Class3();
method(); //global variable
obj2.method(); //object variable in instance of Class2
obj3.method(); //object variable in instance of Class3
method.call(obj2); //object variable in instance of Class2
method.call(obj3); //object variable in instance of Class3
obj2.method.call(obj3); //object variable in instance of Class3
obj2.method.call(this); //global variable
obj3.method.call(obj2); //object variable in instance of Class2
obj3.method.call(this); //global variable
可以看到,使用call或apply可以將方法綁定到指定的上下文中。在全局環(huán)境中this指向的上下文為全局對(duì)象。
1. 全局變量和全局函數(shù)附屬于全局對(duì)象(window),因此使用”var”或”this”兩種方法定義全局變量是等效的。
2. 執(zhí)行上下文和作用域不同。執(zhí)行上下文在運(yùn)行時(shí)確定,隨時(shí)可能改變,而作用域則在定義時(shí)確定,永遠(yuǎn)不會(huì)變。
3. 如果當(dāng)前執(zhí)行的是一個(gè)對(duì)象的方法,則執(zhí)行上下文就是這個(gè)方法所附屬的對(duì)象。
4. 如果當(dāng)前是一個(gè)創(chuàng)建對(duì)象的過(guò)程或者執(zhí)行一個(gè)對(duì)象的方法,則執(zhí)行上下文就是這個(gè)正在被創(chuàng)建的對(duì)象。
5. 如果一個(gè)方法在執(zhí)行時(shí)沒(méi)有明確指定附屬對(duì)象,則這個(gè)方法的上下文為全局對(duì)象。
6. 使用call和apply可以改變對(duì)象的執(zhí)行上下文。
看下面的例子:
復(fù)制代碼 代碼如下:
var v1 = "global variable"; //全局變量附屬于對(duì)象
//this.v1 = "global variable with this"; //全局變量定義時(shí)使用var v1和this.v1兩種方法等效。
function func1(){
var v1 = "part variable";
writeHtml(v1);
writeHtml(this.v1);
}
func1(); //part variable
//global variable
因?yàn)閒unc1中有和全局對(duì)象同名的v1變量,所以在func1中直接引用v1引用的是func1中定義的變量。javascript同樣有局部變量隱藏全局變量的特性。但func1沒(méi)有明確的指定附屬對(duì)象,因此他的執(zhí)行上下文是全局對(duì)象,使用this引用變量的是全局變量。
再看一個(gè)稍微復(fù)雜一點(diǎn)的例子:
復(fù)制代碼 代碼如下:
function ftest(){
var v = "v1v1v1";
this.this_v = "this_v";
return function(){
writeHtml(v);
writeHtml(this.this_v);
}
}
var a = ftest();
var v = "v2v2v2";
writeHtml(this_v); // this_v
a(); //v1v1v1
//this_v
當(dāng)ftest當(dāng)做函數(shù)來(lái)執(zhí)行時(shí),上下文為全局對(duì)象。所以在ftest中使用this定義的變量成為了全局變量。所以我們?cè)趂test外面直接使用變量名訪問(wèn)this_v的值。但是,由于ftest中返回的匿名函數(shù)是定義在ftest內(nèi)部的,所以這個(gè)匿名函數(shù)的作用域就是在ftest內(nèi)部。因此當(dāng)有全局變量v和局部變量v同名時(shí),這個(gè)匿名函數(shù)訪問(wèn)到的是ftest內(nèi)部定義的變量v。
接下來(lái)把ftest當(dāng)做類,使用new關(guān)鍵字來(lái)實(shí)例化:
復(fù)制代碼 代碼如下:
function ftest(){
var v = "v1v1v1";
this.this_v = "this_v";
return function(){
writeHtml(v);
writeHtml(this.this_v);
}
}
var a = new ftest();
var v = "v2v2v2";
//writeHtml(this_v); // 錯(cuò)誤:this_v未定義
a(); //v1v1v1
//undefined
把ftest當(dāng)做對(duì)象來(lái)實(shí)例化時(shí),在對(duì)象的創(chuàng)建過(guò)程中,上下文為被創(chuàng)建的對(duì)象本身。注意,這個(gè)時(shí)候創(chuàng)建的對(duì)象是ftest的實(shí)例,而創(chuàng)建完成以后又返回了一個(gè)函數(shù),這導(dǎo)致了new ftest()實(shí)例化后返回的是一個(gè)函數(shù),而不是ftest()實(shí)例化后對(duì)象的引用。因此,這個(gè)已經(jīng)實(shí)例化的對(duì)象無(wú)法被引用。當(dāng)我們定義這個(gè)被返回的函數(shù)時(shí),因?yàn)闆](méi)有用this指定這個(gè)函數(shù)的上下文,因此這個(gè)被返回的函數(shù)上下文為全局對(duì)象,作用域?yàn)閒test()函數(shù)內(nèi)部。所以函數(shù)a()執(zhí)行時(shí)的由于上下文中沒(méi)有定義this_v變量,導(dǎo)致了訪問(wèn)錯(cuò)誤。
注意,上面的代碼:
復(fù)制代碼 代碼如下:
function ftest(){
return function(){
}
}
這樣的形式并不是一個(gè)靜態(tài)封裝環(huán)境,靜態(tài)封裝環(huán)境應(yīng)該是:在一個(gè)函數(shù)定義完成后立即執(zhí)行,并且執(zhí)行完成后返回函數(shù)中的某一個(gè)內(nèi)部函數(shù)。
我們看下面一個(gè)例子,觀察作用域和上下文對(duì)變量引用的影響。
復(fù)制代碼 代碼如下:
var v = "global variable";
function method(){
writeHtml(v);
writeHtml(this.v);
}
var Class1 = function(){
var v = "private variable";
this.v = "object variable";
var method2 = method;
this.method2 = method;
var method3 = function(){
writeHtml(v);
writeHtml(this.v);
}
this.method3 = function(){
writeHtml(v);
writeHtml(this.v);
}
method2(); //global variable
//global variable
this.method2(); //global variable
//object variable
method3(); //private variable
//global variable
this.method3();//private variable
//object variable
}
var obj = new Class1();
由于method在全局中定義,所以method的作用域在定義的時(shí)候就被確定為全局的。所以method2在Class1內(nèi)部被調(diào)用時(shí),其作用域與是全局,上下文是全局對(duì)象。因此,在函數(shù)中訪問(wèn)到的變量都是全局變量。
同理,this.method2在被調(diào)用時(shí),其作用域是全局,但是由于該函數(shù)在定義時(shí)使用this關(guān)鍵字指明了其上下文為Class1的對(duì)象,所以在該函數(shù)訪問(wèn)沒(méi)有上下文限定的變量時(shí)訪問(wèn)到的是全局變量,訪問(wèn)有上下文限定的變量時(shí)為訪問(wèn)到的是當(dāng)前上下文中對(duì)應(yīng)的變量。
在調(diào)用method3和this.method3時(shí),在訪問(wèn)沒(méi)有上下文限定的變量時(shí)訪問(wèn)到的是局部變量,因?yàn)榫植孔兞侩[藏了全局變量。有上下文限定時(shí)和method2相同,訪問(wèn)到的是當(dāng)前上下問(wèn)文中的變量。
使用call和apply可以改變執(zhí)行上下文,由于call和apply只是參數(shù)類型不一樣,因此例子下面都用call來(lái)演示。
復(fù)制代碼 代碼如下:
var v = "global variable";
var method = function(){
writeHtml(this.v);
}
var Class2 = function(){
this.v = "object variable in instance of Class2";
this.method = function(){
writeHtml(this.v);
}
}
var Class3 = function(){
this.v = "object variable in instance of Class3";
this.method = function(){
writeHtml(this.v);
}
}
var obj2 = new Class2();
var obj3 = new Class3();
method(); //global variable
obj2.method(); //object variable in instance of Class2
obj3.method(); //object variable in instance of Class3
method.call(obj2); //object variable in instance of Class2
method.call(obj3); //object variable in instance of Class3
obj2.method.call(obj3); //object variable in instance of Class3
obj2.method.call(this); //global variable
obj3.method.call(obj2); //object variable in instance of Class2
obj3.method.call(this); //global variable
可以看到,使用call或apply可以將方法綁定到指定的上下文中。在全局環(huán)境中this指向的上下文為全局對(duì)象。
相關(guān)文章
詳解webpack引入第三方庫(kù)的方式以及注意事項(xiàng)
這篇文章主要介紹了詳解webpack引入第三方庫(kù)的方式以及注意事項(xiàng),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01JavaScript實(shí)現(xiàn)Base64編碼轉(zhuǎn)換
這篇文章主要介紹了JavaScript實(shí)現(xiàn)Base64編碼轉(zhuǎn)換的相關(guān)資料,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2016-04-04微信小程序中使用自定義字體的實(shí)現(xiàn)與體驗(yàn)優(yōu)化
由于微信支持的字體非常有限,不能滿足個(gè)性化的需求,因此在開發(fā)的過(guò)程中可能會(huì)需要使用自定義字體,下面這篇文章主要給大家介紹了關(guān)于微信小程序中使用自定義字體的實(shí)現(xiàn)與體驗(yàn)優(yōu)化的相關(guān)資料,需要的朋友可以參考下2022-02-02基于js中的存儲(chǔ)鍵值對(duì)以及注意事項(xiàng)介紹
下面小編就為大家介紹一下基于js中的存儲(chǔ)鍵值對(duì)以及注意事項(xiàng)。希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03Bootstrap treeview實(shí)現(xiàn)動(dòng)態(tài)加載數(shù)據(jù)并添加快捷搜索功能
本文實(shí)現(xiàn)了運(yùn)用bootstrap treeview實(shí)現(xiàn)動(dòng)態(tài)加載數(shù)據(jù),并且添加快捷搜索功能,需要的朋友參考下2018-01-01用js實(shí)現(xiàn)的自定義的對(duì)話框的實(shí)現(xiàn)代碼
javascript alert函數(shù)的替代方案,一個(gè)自定義的對(duì)話框的方法2010-03-03