javascript - 为什么在调用一个函数时,第一个 this 是父对象,但在随后的函数调用中,this 指的是 window 对象?

标签 javascript

当最初调用一个函数时,第一个 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()然后是 thisgetSecondThis() 内引用父对象 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 绑定(bind)调用上下文的方式:JS 临时绑定(bind)上下文(this 引用)。含义:根据调用的方式、位置和方式,this 将引用不同的对象。
我在 here, and in the linked answers found on the bottom 之前已经对此进行了一些详细的解释

基本上,函数是第一类对象,这意味着,与任何值一样,您可以将函数分配给多个变量/属性。当然,如果您将一个函数分配给一个对象(作为属性),该函数通常称为方法,并且您希望 this 指向拥有该方法的对象。
然而,正如 Pointy 在评论中指出的那样:一个对象不能拥有另一个对象。对象可以被另一个对象的一个​​或多个属性引用。

JS 会友好地设置this 来引用拥有该函数的对象。但是,如果您随后将该对象分配给一个变量,那么让 this 指向同一个对象就没有意义了。考虑将函数作为函数参数传递的情况(jQuery 中的回调等)。您可能希望 this 引用新上下文(在 jQ 事件处理程序中肯定是这种情况!)。 如果没有提供上下文,JS 会遗憾地将 this 引用默认为全局对象。

您可以使用 Function.prototype.bind 调用将函数显式绑定(bind)到给定上下文。
如果要为单个调用指定上下文,可以使用 Function.prototype.call(context, arg1, arg2);Function.prototype.apply(context, [args] );

大多数较大的项目(例如 jQ 等工具包)通过利用闭包范围来解决这个问题。例如,使用模块模式是控制上下文的一种常见且简单的方法。 I've explained this, too ,用图表来说明正在发生的事情:)

一些例子/谜题使这更容易理解或更有趣:

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

关于javascript - 为什么在调用一个函数时,第一个 this 是父对象,但在随后的函数调用中,this 指的是 window 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24912821/

相关文章:

javascript - 在 CodeIgniter 中高效压缩 CSS 和 JS

javascript - jQuery/JavaScript : Change onclick of an achor tag

javascript - 使用 zIndex 样式和 React-Native 将 View 置于 Modal 之上

javascript - Mongoose + Node.js : Async issue

javascript - Jquery Ui 可排序 : how to detect each fired event?

javascript - 使用javascript为css规则添加前缀

JavaScript if() 语句未按预期评估

javascript - jquery搜索框和按钮

php - 如何在不刷新页面的情况下显示错误?

javascript - 这是做私有(private)功能的好方法吗?