簡體   English   中英

為什么在調用一個函數時首先將其作為父對象,而在隨后的函數調用中卻將此對象稱為窗口對象?

[英]Why when invoking a function is the first this the parent object, but on a subsequent function call this refers to the window object?

當最初調用功能時,第一this被調用第一函數內是指對父對象foo而是由第一函數調用的后續功能this指的是窗口對象?

var foo = (function Obj(){
    var t = this;
    return  {
        getThis: getThis,
        getSecondThis: getSecondThis
    };
    function getThis(){ 
        console.log(this);
        console.log(t);
        getSecondThis()
        return false;
    }
    function getSecondThis(){ 
        console.log(this);
        console.log(t);
        return false;
    }
})();

foo.getThis();

如果我將調用從getSecondThis()更改為this.getSecondThis()getSecondThis()this引用父對象foo請參見下面的代碼

var foo = (function Obj(){
    var t = this;
    return  {
        getThis: getThis,
        getSecondThis: getSecondThis
    };
    function getThis(){ 
        console.log(this);
        console.log(t);
        this.getSecondThis() //line edited
        return false;
    }
    function getSecondThis(){ 
        console.log(this);
        console.log(t);
        return false;
    }
})();

foo.getThis();

所述getSecondThis()是父對象的范圍內foo但是當返回窗口this在第二呼叫沒有被指定。

這就是JS綁定調用上下文的方式:JS臨時綁定上下文( this引用)。 含義:根據調用方式,位置和方式的不同, this將引用不同的對象。
在此之前我已經在底部以及鏈接的答案中進行了詳細解釋。

基本上,函數是一流的對象 ,這意味着像任何值一樣,您可以將函數分配給多個變量/屬性。 當然,如果將功能分配給對象(作為屬性),則該功能通常稱為方法,並且您希望this指向擁有該方法的對象。
但是,正如Pointy在注釋中指出的:一個對象不能擁有另一個對象。 可以通過另一個對象的一個​​或多個屬性來引用對象。

JS將this進行設置,以引用擁有該功能的對象。 但是,如果您隨后將對象分配給變量,則this點指向同一對象將毫無意義。 考慮將函數作為函數參數傳遞的情況(jQuery中的回調等)。 您可能希望this引用新的上下文(在jQ事件處理程序中肯定是這種情況!)。 如果沒有提供上下文,則JS會遺憾地this引用默認為全局對象。

您可以使用Function.prototype.bind調用將Function.prototype.bind顯式綁定到給定的上下文。
如果要為單個調用指定上下文,則可以使用Function.prototype.call(context, arg1, arg2); Function.prototype.apply(context, [args]);

大多數大型項目(例如jQ之類的工具包)都利用閉包作用域來解決此問題。 例如,使用模塊模式是控制上下文的一種常見且簡便的方法。 我也已經解釋了這一點,並附有圖表以說明正在發生的事情:)

一些例子/難題,使之更容易理解或更有趣:

var obj = (function()
{//function scope
    'use strict';//this will be null, instead of global, omit this and this can be window
    var obj = {},
        funcOne = function()
        {
            console.log(this, obj, this === obj);
            funcTwo(this);
            obj.funcTwo();
            obj.funcTwo(this);
            obj.funcTwo(obj);
        },
        funcTwo = function(that)
        {
            console.log(this, obj, this === obj, this === that, that === obj);
        };
        obj.funcOne = funcOne;
        obj.funcTwo = funcTwo;
        return obj;//is assigned to the outer var
}());
obj.funcOne();
//output:
//- first logs itself twice, then true
//then calls made in funcOne:
funcTwo()
console.log(this, obj, this === obj, this === that, that === obj);
//- this: undefined (omit 'use strict' and it'll be window), obj,
//     this === obj => false, this === that => false, that === obj => true
obj.funcTwo();
console.log(this, obj, this === obj, this === that, that === obj);
//logs obj twice, because obj.funcTwo means the context === obj
//this === obj is true (of course)
//that is undefined, so this === that and that === obj are false
//lastly
obj.funcTwo(this);
obj.funcTwo(obj);

您應該能夠解決這個問題。 您知道執行funcOne的上下文,並且知道調用funcTwo作為obj的方法有什么作用

經驗法則:
我猶豫要寫這個,因為它遠非准確,但只有8/10例。 假設沒有代碼通過bindcallapply干預上下文,則可以使用以下技巧來計算上下文:

someObject.someMethod();
    /\        ||
    |===this===|
//another object:
var obj2 = {
    borrowed: someObject.someMethod,
    myOwn: function()
    {
        this.borrowed();
    }
};
obj2.myOwn();//this === obj2 (as explained above),
   \\
    \==> this.borrowed === obj2.borrowed 
            \\
             \==> ~= someObject.someMethod.call(obj2);//function is executed in context of obj2
//simple vars
var alias = someObject.someMethod;//assign to var
alias();//no owner to be seen?
   ||
?<==|
//non-strict mode:
[window.]alias();
 /\ implied ||
 ||         ||
 |==<this>===|
//strict mode
alias.call(undefined);//context is undefined

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM