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?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78002.html
摘要:標簽前端作者更多文章個人網站 Learning Notes - Understanding the Weird Parts of JavaScript 標簽 : 前端 JavaScript [TOC] The learning notes of the MOOC JavaScript: Understanding the Weird Parts on Udemy,including...
摘要:說明本文主要學習容器的實例化過程,主要包括等四個過程。看下的源碼如果是數組,抽取別名并且注冊到中,上文已經討論實際上就是的。 說明:本文主要學習Laravel容器的實例化過程,主要包括Register Base Bindings, Register Base Service Providers , Register Core Container Aliases and Set the ...
摘要:以此類推,不定參數的方程也就被稱為可變參數函數。一般來說,函數式編程中的值都被認為是不可變值。實現了函數的對象,即可以與其他對象進行對比判斷是否屬于同一類型,被稱為。半群一個擁有,即將另一個對象轉化為相同類型的函數,函數的對象稱為。 原文地址譯者的Github 系列文章地址本文原作者尚未全部完成,有興趣的可以到原文或者譯文地址關注更新 Functional Programming Ja...
摘要:通過的合并策略合并添加項到新的構造器上緩存父構造器處理和相關響應式配置項在新的構造器上掛上的工具方法緩存組件構造器在上總的來說是返回了一個帶有附加配置相的新的的構造器。在函數中,構造器叫做,等待時候初始化。 身為原來的jquery,angular使用者。后面接觸了react和vue。漸漸的喜歡上了vue。抱著學習的態度呀。看看源碼。果然菜要付出代價。一步步單步調試。頭好疼。看到哪里記到...
摘要:注意,下面一個立即執行的函數,周圍的括號不是必須的,因為函數已經處在表達式的位置,解析器知道它處理的是在函數執行階段應該被創建的,這樣在函數創建后立即調用了函數。 本文是翻譯http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/#introduction 概要In this article we will talk abou...
閱讀 2777·2021-09-24 10:34
閱讀 1879·2021-09-22 10:02
閱讀 2268·2021-09-09 09:33
閱讀 1471·2021-08-13 15:02
閱讀 3281·2020-12-03 17:10
閱讀 1196·2019-08-30 15:44
閱讀 2157·2019-08-30 12:58
閱讀 3239·2019-08-26 13:40