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

When initially invoking a function, the first this within the first function that is called refers to the parent object foo but on a subsequent function called by that first function 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();

If I change the call from getSecondThis() to this.getSecondThis() then the this within getSecondThis() refers to the parent object foo see the code below 如果我将调用从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();

The getSecondThis() is within the scope of the parent object foo but window is returned when this is not specified on the second call. 所述getSecondThis()是父对象的范围内foo但是当返回窗口this在第二呼叫没有被指定。

It's just the way JS binds the calling context: JS binds the context (the this reference) ad-hoc. 这就是JS绑定调用上下文的方式:JS临时绑定上下文( this引用)。 Meaning: depending on how, where and by what means it is invoked, this will reference a different object. 含义:根据调用方式,位置和方式的不同, this将引用不同的对象。
I've explained this in some detail before here, and in the linked answers found on the bottom 在此之前我已经在底部以及链接的答案中进行了详细解释。

Basically, functions are first class objects , meaning that, like any value, you can assign a function to a multitude of variables/properties. 基本上,函数是一流的对象 ,这意味着像任何值一样,您可以将函数分配给多个变量/属性。 Of course, if you assign a function to an object (as a property), that function is often referred to as a method, and you'd expect this to point to the object that owns that method. 当然,如果将功能分配给对象(作为属性),则该功能通常称为方法,并且您希望this指向拥有该方法的对象。
However, as Pointy noted in the comments: An object cannot own another object. 但是,正如Pointy在注释中指出的:一个对象不能拥有另一个对象。 Objects can be referenced by one or more properties of another object. 可以通过另一个对象的一个​​或多个属性来引用对象。

JS will kindly set this to refer to the object that owns the function. JS将this进行设置,以引用拥有该功能的对象。 But if you then assign the object to a variable, it would make no sense to have this point to that same object. 但是,如果您随后将对象分配给变量,则this点指向同一对象将毫无意义。 Think of situations where you're passing functions as function arguments (callbacks in jQuery and so on). 考虑将函数作为函数参数传递的情况(jQuery中的回调等)。 You probably want this to reference the new context (certainly the case in jQ event handlers!). 您可能希望this引用新的上下文(在jQ事件处理程序中肯定是这种情况!)。 If no context is provided, JS sadly defaults the this reference to the global object. 如果没有提供上下文,则JS会遗憾地this引用默认为全局对象。

You can explicitly bind a function to a given context using the Function.prototype.bind call. 您可以使用Function.prototype.bind调用将Function.prototype.bind显式绑定到给定的上下文。
If you want to specify the context for a single call, you can use Function.prototype.call(context, arg1, arg2); 如果要为单个调用指定上下文,则可以使用Function.prototype.call(context, arg1, arg2); or Function.prototype.apply(context, [args]); Function.prototype.apply(context, [args]);

Most larger projects (toolkits like jQ for example) solve this issue by taking advantage of closure scoping. 大多数大型项目(例如jQ之类的工具包)都利用闭包作用域来解决此问题。 Using the module pattern, for example, is a common, and easy way to control the context. 例如,使用模块模式是控制上下文的一种常见且简便的方法。 I've explained this, too , complete with graphs to illustrate what is going on :) 我也已经解释了这一点,并附有图表以说明正在发生的事情:)

Some examples/puzzles to make this easier to follow or more fun: 一些例子/难题,使之更容易理解或更有趣:

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);

You should be able to work that out. 您应该能够解决这个问题。 You know the context in which funcOne is being executed, and you know what the effects are of invoking funcTwo as a method of obj 您知道执行funcOne的上下文,并且知道调用funcTwo作为obj的方法有什么作用

Rule of thumb: 经验法则:
I hesitated to write this, because it's far from accurate, but 8/10 cases. 我犹豫要写这个,因为它远非准确,但只有8/10例。 Assuming no code has been meddling with contexts through bind , call , and apply , you can work out the context using this trick: 假设没有代码通过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