pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

Javascript this 的一些學習總結

1.1.1 摘要 相信有C/C++、C#或Java等編程經(jīng)驗的各位,對于this關鍵字再熟悉不過了。由于Javascript是一種面向對象的編程語言,它和C/C++、C#或Java一樣都包含this關鍵字,接下來我們將向大家介

1.1.1 摘要

相信有C/C++、C#或Java等編程經(jīng)驗的各位,對于this關鍵字再熟悉不過了。由于Javascript是一種面向對象的編程語言,它和C/C++、C#或Java一樣都包含this關鍵字,接下來我們將向大家介紹Javascript中的this關鍵字。
1.1.2 正文

由于許多面向對象的編程語言都包含this關鍵字,我們會很自然地把this和面向對象的編程方式聯(lián)系在一起,this通常指向利用構造器新創(chuàng)建出來的對象。而在ECMAScript中,this不僅僅只用來表示創(chuàng)建出來的對象,也是執(zhí)行上下文的一個屬性:

activeExecutionContext = {
// Variable object.
VO: {...},
this: thisValue
};
全局代碼中的this
// Global scope
// The implicit property of
// the global object
foo1 = "abc";
alert(foo1); // abc

// The explicit property of
// the global object
this.foo2 = "def";
alert(foo2); // def

// The implicit property of
// the global object
var foo3 = "ijk";
alert(foo3); // ijk

前面我們通過顯式和隱式定義了全局屬性foo1、foo2和foo3,由于this在全局上下文中,所以它的值是全局對象本身(在瀏覽器中是window object);接下來我們將介紹函數(shù)中的this
函數(shù)中的this

this在函數(shù)代碼中,情況就復雜多了,并且會引發(fā)很多的問題。
函數(shù)代碼中this值的第一個特性(同時也是最主要的特性)就是:它并非靜態(tài)的綁定在函數(shù)上
正如此前提到的,this的值是在進入執(zhí)行上下文(Excution context)的階段確定的,并且在函數(shù)代碼中的話,其值每次都不盡相同。
然而,一旦進入執(zhí)行代碼階段,其值就不能改變了。如果要想給this賦一個新的值是不可能的,因為在那時this根本就不是變量了。
接下來,我們通過具體的例子說明函數(shù)中的this
首先我們定義兩個對象foo和person,foo包含一個屬性name,而person包含屬性name和方法say(),具體的定義如下:

// Defines foo object.
var foo = {
name: "Foo"
};

// Defines person object.
var person = {
name: "JK_Rush",
say: function() {
alert(this === person);
alert("My name is " + this.name);
}
};

person.say(); // My name is JK_Rush

// foo and person object refer to
// the same function say
foo.say = person.say;

foo.say(); // My name is Foo.
通過上面的代碼,我們發(fā)現(xiàn)調用person的say()方法時,this指向person對象,當通過賦值方式使得foo的say()方法指向peson中的say()方法時。我們調用foo的say()方法,發(fā)現(xiàn)this不是指向person對象,而不是指向foo對象,這究竟是什么原因呢?
首先,我們必須知道this的值在函數(shù)中是非靜態(tài)的,它的值確定在函數(shù)調用時,具體代碼執(zhí)行前,this的值是由激活上下文代碼的調用者決定的,比如說,調用函數(shù)的外層上下文;更重要的是,this的值是由調用表達式的形式?jīng)Q定的,所以說this并非靜態(tài)的綁定在函數(shù)上
由于this并非靜態(tài)地綁定在函數(shù)上,那么我們是否可以在函數(shù)中動態(tài)地修改this的值呢?
// Defines foo object.
var foo = {
name: "Foo"
};

// Defines person object.
var person = {
name: "JK_Rush",
say: function() {
alert(this === person);
this = foo; // ReferenceError
alert("My name is " + this.name);
}
};

person.say(); // My name is JK_Rush

現(xiàn)在我們在方法say()中,動態(tài)地修改this的值,當我們重新執(zhí)行以上代碼,發(fā)現(xiàn)this的值引用錯誤。這是由于一旦進入執(zhí)行代碼階段(函數(shù)調用時,具體代碼執(zhí)行前),this的值就確定了,所以不能改變了。
引用類型

前面我們提到this的值是由激活上下文代碼的調用者決定的,更重要的是,this的值是由調用表達式的形式?jīng)Q定的;那么表達式的形式是如何影響this的值呢?
首先,讓我們介紹一個內部類型——引用類型,它的值可以用偽代碼表示為一個擁有兩個屬性的對象分別是:base屬性(屬性所屬的對象)以及該base對象中的propertyName屬性:

// Reference type.
var valueOfReferenceType = {
base: mybase,
propertyName : 'mybasepropertyName'
};
引用類型的值只有可能是以下兩種情況:

  • 當處理一個標識符的時候
  • 或者進行屬性訪問的時候
標識符其實就是變量名函數(shù)名函數(shù)參數(shù)名以及全局對象的未受限的屬性
// Declares varible.
var foo = 23;

// Declares a function
function say() {
// Your code.
}
中間過程中,對應的引用類型如下:
// Reference type.
var fooReference = {
base: global,
propertyName: 'foo'
};

var sayReference = {
base: global,
propertyName: 'say'
};
我們知道Javascript中屬性訪問有兩種方式:點符號和中括號符號:
// Invokes the say method.
foo.say();
foo['say']();
由于say()方法是標識符,所以它對應于foo對象引用類型如下:
// Reference type.
var fooSayReference = {
base: foo,
propertyName: 'say'
};
我們發(fā)現(xiàn)say()方法的base屬性值為foo對象,那么它對應的this屬性也將指向foo對象。
假設,我們直接調用say()方法,它對應的引用類型如下:
// Reference type.
var sayReference = {
base: global,
propertyName: 'say'
};

由于say()方法的base屬性值為global(通常來說是window object),那么它對應的this屬性也將指向global。
函數(shù)上下文中this的值是函數(shù)調用者提供并且由當前調用表達式的形式而定的。如果在調用括號()的左邊有引用類型的值,那么this的值就會設置為該引用類型值的base對象。 所有其他情況下(非引用類型),this的值總是null。然而,由于null對于this來說沒有任何意義,因此會隱式轉換為全局對象。
函數(shù)調用以及非引用類型

前面我們提到,當調用括號左側為非引用類型的時,this的值會設置為null,并最終隱式轉換為全局對象。
現(xiàn)在我們定義了一個匿名自執(zhí)行函數(shù),具體實現(xiàn)如下:

// Declares anonymous function
(function () {
alert(this); // null => global
})();
由于括號()左邊的匿名函數(shù)是非引用類型對象(它既不是標識符也不屬于屬性訪問),因此,this的值設置為全局對象。
// Declares object.
var foo = {
bar: function () {
alert(this);
}
};

(foo.bar)(); // foo.
(foo.bar = foo.bar)(); // global?
(false || foo.bar)(); // global?
(foo.bar, foo.bar)(); // global

這里注意到四個表達式中,只有第一個表達式this是指向foo對象的,而其他三個表達式則執(zhí)行global。
現(xiàn)在我們又有疑問了:為什么屬性訪問,但是最終this的值不是引用類型對象而是全局對象呢?
我們注意到表達式二是賦值(assignment operator),與表達式一組操作符不同的是,它會觸發(fā)調用GetValue方法(參見11.13.1中的第三步)。 最后返回的時候就是一個函數(shù)對象了(而不是引用類型的值了),這就意味著this的值會設置為null,最終會變成全局對象。
第三和第四種情況也是類似的——逗號操作符和OR邏輯表達式都會觸發(fā)調用GetValue方法,于是相應地就會丟失原先的引用類型值,變成了函數(shù)類型,this的值就變成了全局對象了。
引用類型以及this的null值

對于前面提及的情形,還有例外的情況,當調用表達式左側是引用類型的值,但是this的值卻是null,最終變?yōu)槿謱ο螅╣lobal object)。 發(fā)生這種情況的條件是當引用類型值的base對象恰好為活躍對象(activation object)。
當內部子函數(shù)在父函數(shù)中被調用的時候就會發(fā)生這種情況,通過下面的示意代碼介紹活躍對象:

// Declares foo function.
function foo() {
function bar() {
alert(this); // global
}
// The same as AO.bar().
bar();
}

由于活躍對象(activation object)總是會返回this值為——null(用偽代碼來表示AO.bar()就相當于null.bar()),然后,this的值最終會由null轉變?yōu)槿謱ο蟆?br>當函數(shù)調用包含在with語句的代碼塊中,并且with對象包含一個函數(shù)屬性的時候,就會出現(xiàn)例外的情況。with語句會將該對象添加到作用域鏈的最前面,在活躍對象的之前。 相應地,在引用類型的值(標識符或者屬性訪問)的情況下,base對象就不再是活躍對象了,而是with語句的對象。另外,值得一提的是,它不僅僅只針對內部函數(shù),全局函數(shù)也是如此, 原因就是with對象掩蓋了作用域鏈中更高層的對象(全局對象或者活躍對象):
函數(shù)作為構造器被調用時this的值

函數(shù)作為構造函數(shù)時,我們通過new操作符創(chuàng)建實例對象是,它會調用Foo()函數(shù)的內部[[Construct]]方法;在對象創(chuàng)建之后,會調用內部的[[Call]]方法,然后所有Foo()函數(shù)中this的值會設置為新創(chuàng)建的對象。

// Declares constructor
function Foo() {
// The new object.
alert(this);
this.x = 10;
}

var foo = new Foo();
foo.x = 23;
alert(foo.x); // 23

手動設置函數(shù)調用時this的值

Function.prototype原型上定義了兩個方法,允許手動指定函數(shù)調用時this的值。這兩個方法分別是:.apply()和.call()。這兩個方法都接受第一個參數(shù)作為調用上下文中this的值,而這兩個方法的區(qū)別是傳遞的參數(shù),對于.apply()方法來說,第二個參數(shù)接受數(shù)組類型(或者是類數(shù)組的對象,比如arguments), 而.call()方法接受任意多的參數(shù)(通過逗號分隔);這兩個方法只有第一個參數(shù)是必要的——this的值。
通過示例代碼介紹call()方法和apply()方法的使用:

var myObject = {};

var myFunction = function(param1, param2) {

//setviacall()'this'points to my Object when function is invoked
this.foo = param1;
this.bar = param2;

//logs Object{foo = 'foo', bar = 'bar'}
console.log(this);
};

// invokes function, set this value to myObject
myFunction.call(myObject, 'foo', 'bar');

// logs Object {foo = 'foo', bar = 'bar'}
console.log(myObject);
call()方法第一個參數(shù)是必要的this值,接著我們可以傳遞任意多個參數(shù),接著介紹apply()方法的使用。
var myObject = {};

var myFunction = function(param1, param2) {

//set via apply(), this points to my Object when function is invoked
this.foo=param1;
this.bar=param2;

// logs Object{foo='foo', bar='bar'}
console.log(this);
};

// invoke function, set this value
myFunction.apply(myObject, ['foo', 'bar']);

// logs Object {foo = 'foo', bar = 'bar'}
console.log(myObject);

通過與call()方法對比,我們發(fā)現(xiàn)apply()方法和call()方法沒有太大的區(qū)別,只是方法簽名不一樣。
1.1.3 總結

本文介紹Javascript中this的使用,更重要的是幫助我們能更好地理解this值在全局、函數(shù)、構造函數(shù)以及一些特例的情況中值的變化。
對于在函數(shù)上下文中this的值是函數(shù)調用者提供并且由當前調用表達式的形式而定的。如果在調用括號()的左邊有引用類型的值,那么this的值就會設置為該引用類型值的base對象。 所有其他情況下(非引用類型),this的值總是null。然而,由于null對于this來說沒有任何意義,因此會隱式轉換為全局對象。
對于特例情況,我們要記住賦值符、逗號操作符以及||邏輯表達式,會使this丟失原先的引用類型值,變成了函數(shù)類型,this的值就變成了全局對象了
參考

[1] http://dmitrysoshnikov.com/ecmascript/chapter-3-this/ 英文版
[2] http://blog.goddyzhao.me/post/11218727474/this       譯文
[3] https://net.tutsplus.com/tutorials/javascript-ajax/fully-understanding-the-this-keyword/

【網(wǎng)站聲明】本站除付費源碼經(jīng)過測試外,其他素材未做測試,不保證完整性,網(wǎng)站上部分源碼僅限學習交流,請勿用于商業(yè)用途。如損害你的權益請聯(lián)系客服QQ:2655101040 給予處理,謝謝支持。

相關文檔推薦

由于實際運行環(huán)境是在瀏覽器中,因此性能還取決于JavaScript解釋器的效率,指定的FPS幀速在低性能解釋器中可能不會達到,所以這部分不是開發(fā)者能夠決定的,開發(fā)者能作的是盡可能通
本文將使用HTML5提供的VideoAPI做一個自定義的視頻播放器,需要用到HTML5提供的video標簽、以及HTML5提供的對JavascriptAPI的擴展。,HTML5中國,中國最大的HTML5中文門戶。
隨著 Hybrid 應用的豐富,HTML5 工程師們已經(jīng)不滿足于把桌面端體驗簡單移植到移動端,他們覬覦移動原生應用人性化的操作體驗,特別是原生應用與生俱來的豐富的手勢系統(tǒng)。HTML5 沒有提
你想要在自己網(wǎng)站上分享一個產(chǎn)品,或者是一個作品集,又或者僅僅只是一個靈感。在你發(fā)布到網(wǎng)上之前,你想讓它看起來有吸引力,專業(yè),或者至少得看起來像那么回事。那么你接下
H5廣告,包括H5廣告的設計流程,究竟有什么講究,和階段。為了能幫助更多的人了解H5廣告,我專門做了一個講義。同時,也讓我意外的收到了非常好反饋和認!這是對我的極大鼓勵!我的
本文主要內容有:框架與組件、構建生態(tài)、開發(fā)技巧與調試、html、css與重構、native/hybrid/桌面開發(fā)、前端/H5優(yōu)化、全棧/全端開發(fā)、研究實驗、數(shù)據(jù)分析與監(jiān)控、其它軟技能、前端技術網(wǎng)
主站蜘蛛池模板: 防火门|抗爆门|超大门|医疗门|隔声门-上海加汇门业生产厂家 | 铝合金重力铸造_铝合金翻砂铸造_铝铸件厂家-东莞市铝得旺五金制品有限公司 | 浩方智通 - 防关联浏览器 - 跨境电商浏览器 - 云雀浏览器 | 济南ISO9000认证咨询代理公司,ISO9001认证,CMA实验室认证,ISO/TS16949认证,服务体系认证,资产管理体系认证,SC食品生产许可证- 济南创远企业管理咨询有限公司 郑州电线电缆厂家-防火|低压|低烟无卤电缆-河南明星电缆 | 飞扬动力官网-广告公司管理软件,广告公司管理系统,喷绘写真条幅制作管理软件,广告公司ERP系统 | 培训中心-翰香原香酥板栗饼加盟店总部-正宗板栗酥饼技术 | 砂磨机_立式纳米砂磨机_实验室砂磨机-广州儒佳化工设备厂家 | 京马网,京马建站,网站定制,营销型网站建设,东莞建站,东莞网站建设-首页-京马网 | 阁楼货架_阁楼平台_仓库仓储设备_重型货架_广州金铁牛货架厂 | 锂电池砂磨机|石墨烯砂磨机|碳纳米管砂磨机-常州市奥能达机械设备有限公司 | 房在线-免费房产管理系统软件-二手房中介房屋房源管理系统软件 | 聚合甘油__盐城市飞龙油脂有限公司 | 电缆隧道在线监测-智慧配电站房-升压站在线监测-江苏久创电气科技有限公司 | 北京银联移动POS机办理_收银POS机_智能pos机_刷卡机_收银系统_个人POS机-谷骐科技【官网】 | LNG鹤管_内浮盘价格,上装鹤管,装车撬厂家-连云港赛威特机械 | 青岛空压机,青岛空压机维修/保养,青岛空压机销售/出租公司,青岛空压机厂家电话 | 污水处理设备维修_污水处理工程改造_机械格栅_过滤设备_气浮设备_刮吸泥机_污泥浓缩罐_污水处理设备_污水处理工程-北京龙泉新禹科技有限公司 | 1000帧高速摄像机|工业高速相机厂家|科天健光电技术 | 运动木地板_体育木地板_篮球馆木地板_舞台木地板-实木运动地板厂家 | 发电机组|柴油发电机组-批发,上柴,玉柴,潍柴,康明斯柴油发电机厂家直销 | 泰来华顿液氮罐,美国MVE液氮罐,自增压液氮罐,定制液氮生物容器,进口杜瓦瓶-上海京灿精密机械有限公司 | 嘉兴泰东园林景观工程有限公司_花箱护栏 | 光环国际-新三板公司_股票代码:838504 | 清洁设备_洗地机/扫地机厂家_全自动洗地机_橙犀清洁设备官网 | 除湿机|工业除湿机|抽湿器|大型地下室车间仓库吊顶防爆除湿机|抽湿烘干房|新风除湿机|调温/降温除湿机|恒温恒湿机|加湿机-杭州川田电器有限公司 | 广州中央空调回收,二手中央空调回收,旧空调回收,制冷设备回收,冷气机组回收公司-广州益夫制冷设备回收公司 | 车间除尘设备,VOCs废气处理,工业涂装流水线,伸缩式喷漆房,自动喷砂房,沸石转轮浓缩吸附,机器人喷粉线-山东创杰智慧 | 北京工业设计公司-产品外观设计-产品设计公司-千策良品工业设计 北京翻译公司-专业合同翻译-医学标书翻译收费标准-慕迪灵 | 成都茶楼装修公司 - 会所设计/KTV装修 - 成都朗煜装饰公司 | 箱式破碎机_移动方箱式破碎机/价格/厂家_【华盛铭重工】 | 意大利Frascold/富士豪压缩机_富士豪半封闭压缩机_富士豪活塞压缩机_富士豪螺杆压缩机 | 「安徽双凯」自动售货机-无人售货机-成人用品-自动饮料食品零食售货机 | 内窥镜-工业内窥镜厂家【上海修远仪器仪表有限公司】 | 德州网站开发定制-小程序开发制作-APP软件开发-「两山开发」 | 手持式浮游菌采样器-全排二级生物安全柜-浙江孚夏医疗科技有限公司 | 【孔氏陶粒】建筑回填陶粒-南京/合肥/武汉/郑州/重庆/成都/杭州陶粒厂家 | 铝扣板-铝方通-铝格栅-铝条扣板-铝单板幕墙-佳得利吊顶天花厂家 elisa试剂盒价格-酶联免疫试剂盒-猪elisa试剂盒-上海恒远生物科技有限公司 | 气动球阀_衬氟蝶阀_调节阀_电动截止阀_上海沃托阀门有限公司 | 飞扬动力官网-广告公司管理软件,广告公司管理系统,喷绘写真条幅制作管理软件,广告公司ERP系统 | 电动不锈钢套筒阀-球面偏置气动钟阀-三通换向阀止回阀-永嘉鸿宇阀门有限公司 | 北京银联移动POS机办理_收银POS机_智能pos机_刷卡机_收银系统_个人POS机-谷骐科技【官网】 |