I thought I know the Function definition, execution context and the behavior of this in JavaScript. However, I realized that actually I don"t or the knowlege is still not firmly grounded in my mind when I wrote some code similar to below snippet but have no instinct of the error.
var TestObj = { a: function() { console.log("A"); }, b: function() { console.log("B"); this.a(); } }; TestObj.b(); var c = TestObj.b; c();
The result will be as below, right?
B A B A
You might suspiciously answer No but If your instint doesnot tell you that and why, then you don"t know JavasScript well either like me. The result actually is:
B A B TypeError: Object [object global] has no method "a"
It is a little bit awkward or counterintuitive at first glance but it"s JavaScript. It"s the feature and amazing part. Let"s break it down piece by piece and see why.
Function definitionThe TestObj includes two methods. The Function definition there actually creates two anonymous functions and then the references to the functions are assigned to the properties a and b. Those two functions are not owned by TestObj and just referred by the two properties of TestObj. This is the most important part causes the confusion. Hence, above code has not much difference than below except now we assign a name B for one of the function:
function B() { console.log("B"); this.a(); }; var TestObj = { a: function() { console.log("A"); }, b: B };this
In ECMA-262 edition 5.1:
10.4.3 Entering Function Code
The following steps are performed when control enters the execution context for function code contained in
function object F, a caller provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
Else set the ThisBinding to thisArg.
...
this is a special keyword refers to the binding object in the current execution context of the Function.
Once we invoke the Function through Object method, the this inside the Function body actually has been set to the TestObj instance. Hence, TestObj.b() logs B and A consecutively because this.a exists as a property of TestObj.
However, below statements mean differently.
var c = TestObj.b; c();
Actually, variable c is just another reference pointing to Function B. Hence c() is same as B(). When directly invoking Function B, the this is bound to global object. Because there is no a defined in the global object, error occurs.
How to set a particular object as this to functionIt"s commonly known that call and apply method can be called on the Function object providing a specific object as this, say:
var c = TestObj.b; c.call(TestObj);
The result is desirable. However, this approach invokes the Function immediately. This is normally not the case that a Function has to be assigned to a Reference and passed around which is meant to be executed dynamically, like:
function dynamic(fn) { fn(); } dynamic(TestObj.b);
In this case, we should not use fn.call(TestObj) or fn.apply(TestObj) because it"s a generic Function which should have no knowledge on the Function passed in. Hence, above is not working.
There is still another lifesaver though. The bind method of Function. This method can take the passed in Object like what call or apply does, but it returns a new Function whose this binding is set to the Object passed in. So, above code can be revised as:
function dynamic(fn) { fn(); } dynamic(TestObj.b.bind(TestObj));
It"s fun, isn"t it?
[Edited on 2013/06/17]: Today, I saw another case which maybe confusing too.
var length = 3; function logLength() { console.log(this.length); } var TestObj = { length: 2, b: logLength, c: function() { (function(fn) { arguments[0](); })(logLength); } }; TestObj.b(); TestObj.c();
What do you think the console should log? Will it be 2 and 3? Actually, the result is 2 and 1. Because the TestObj.c() actually is calling the function logLength on the arguments Object, and then the this.length is referring to its own length, which is 1.
More fun, right?
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/78002.html
摘要:標(biāo)簽前端作者更多文章個(gè)人網(wǎng)站 Learning Notes - Understanding the Weird Parts of JavaScript 標(biāo)簽 : 前端 JavaScript [TOC] The learning notes of the MOOC JavaScript: Understanding the Weird Parts on Udemy,including...
摘要:說(shuō)明本文主要學(xué)習(xí)容器的實(shí)例化過(guò)程,主要包括等四個(gè)過(guò)程。看下的源碼如果是數(shù)組,抽取別名并且注冊(cè)到中,上文已經(jīng)討論實(shí)際上就是的。 說(shuō)明:本文主要學(xué)習(xí)Laravel容器的實(shí)例化過(guò)程,主要包括Register Base Bindings, Register Base Service Providers , Register Core Container Aliases and Set the ...
摘要:以此類推,不定參數(shù)的方程也就被稱為可變參數(shù)函數(shù)。一般來(lái)說(shuō),函數(shù)式編程中的值都被認(rèn)為是不可變值。實(shí)現(xiàn)了函數(shù)的對(duì)象,即可以與其他對(duì)象進(jìn)行對(duì)比判斷是否屬于同一類型,被稱為。半群一個(gè)擁有,即將另一個(gè)對(duì)象轉(zhuǎn)化為相同類型的函數(shù),函數(shù)的對(duì)象稱為。 原文地址譯者的Github 系列文章地址本文原作者尚未全部完成,有興趣的可以到原文或者譯文地址關(guān)注更新 Functional Programming Ja...
摘要:通過(guò)的合并策略合并添加項(xiàng)到新的構(gòu)造器上緩存父構(gòu)造器處理和相關(guān)響應(yīng)式配置項(xiàng)在新的構(gòu)造器上掛上的工具方法緩存組件構(gòu)造器在上總的來(lái)說(shuō)是返回了一個(gè)帶有附加配置相的新的的構(gòu)造器。在函數(shù)中,構(gòu)造器叫做,等待時(shí)候初始化。 身為原來(lái)的jquery,angular使用者。后面接觸了react和vue。漸漸的喜歡上了vue。抱著學(xué)習(xí)的態(tài)度呀。看看源碼。果然菜要付出代價(jià)。一步步單步調(diào)試。頭好疼。看到哪里記到...
摘要:注意,下面一個(gè)立即執(zhí)行的函數(shù),周圍的括號(hào)不是必須的,因?yàn)楹瘮?shù)已經(jīng)處在表達(dá)式的位置,解析器知道它處理的是在函數(shù)執(zhí)行階段應(yīng)該被創(chuàng)建的,這樣在函數(shù)創(chuàng)建后立即調(diào)用了函數(shù)。 本文是翻譯http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/#introduction 概要In this article we will talk abou...
閱讀 2761·2021-09-24 10:34
閱讀 1862·2021-09-22 10:02
閱讀 2253·2021-09-09 09:33
閱讀 1459·2021-08-13 15:02
閱讀 3271·2020-12-03 17:10
閱讀 1180·2019-08-30 15:44
閱讀 2144·2019-08-30 12:58
閱讀 3229·2019-08-26 13:40