繁体   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