我希望找到一个“this”关键字的明确解释,以及如何正确使用它。

它的行为似乎很奇怪,我不完全明白为什么。

这是如何工作的,何时使用?


当前回答

关于如何在JavaScript中解释“this”关键字,存在很多困惑。希望这篇文章能让所有这些人一劳永逸。还有更多。请仔细阅读整篇文章。预先警告,这篇文章很长。

无论使用的上下文如何,“this”总是引用Javascript中的“当前对象”。然而,“当前对象”是什么根据上下文而不同。上下文可能正好是以下6项中的1项:

全局(即在所有功能之外)内部直接“非绑定函数”调用(即尚未通过调用functionName.bind绑定的函数)内部间接“非绑定函数”通过functionName.Call和functionName.apply调用在“绑定函数”内部调用(即通过调用functionName.bind绑定的函数)通过“新建”创建对象内联DOM事件处理程序内部

以下逐一介绍了每种情况:

全局上下文(即所有功能外部):在所有功能之外(即在全局上下文中)对象”(因此“this”的值)始终是浏览器的“窗口”对象。内部直接“非绑定函数”调用:在直接“非绑定函数”调用中调用的函数调用变为“当前对象”(因此“this”的值)。如果在没有显式当前对象的情况下调用函数,则当前对象要么是“窗口”对象(对于非严格模式),要么是未定义的(对于严格模式)。中定义的任何函数(或变量)全局上下文自动成为“窗口”对象的属性。例如,假设函数在全局上下文中定义为函数UserDefinedFunction(){警报(this)}它成为窗口对象的属性,就像您定义了它作为window.UserDefinedFunction=函数(){警报(this)} 在“非严格模式”下,直接通过“UserDefinedFunction()”调用/调用此函数将自动调用/调用它作为“window.UserDefinedFunction()”,将“window”作为“UserDefinedFunction”中的“当前对象”(以及“this”的值)。在“非严格模式”中调用此函数将导致以下结果UserDefinedFunction()//显示[object Window],因为它自动被调用为窗口。UserDefined Function()在“严格模式”下,通过“UserDefinedFunction()”将“NOT”自动将其调用为“window.UserDefinedFunctions()”。因此,“当前对象”(以及“this”的值)“UserDefinedFunction”应未定义。在“严格模式”下调用此函数将导致以下结果UserDefinedFunction()//显示未定义然而,使用窗口对象显式调用它将导致以下内容window.UserDefinedFunction()//“无论模式如何,始终显示[object window]。”让我们看看另一个例子。请查看以下代码函数UserDefinedFunction(){警报(this.a+“,”+this.b+“,“+this.c+”,“+this.d”)}变量o1={a: 1中,b: 2,f: 用户定义函数}无功氧气={c: 3中,d: 4中,f: 用户定义函数}o1.f()//应显示1,2,未定义,未定义o2.f()//应显示未定义、未定义、3,4在上面的示例中,我们看到当“UserDefinedFunction”通过o1调用,“this”取值为o1显示其财产“a”和“b”的值。价值“c”和“d”的定义与o1相同没有定义这些财产类似地,当通过o2调用“UserDefinedFunction”时,“this”取o2的值,并显示其财产“c”和“d”的值。“a”和“b”的值显示为未定义,因为o2未定义这些财产。间接“非绑定函数”内部通过functionName.Call和functionName.apply调用:当通过调用“非绑定函数”时functionName.call或functionName.apply,“当前对象”(因此“this”的值)设置为传递给调用/应用的“this”参数(第一个参数)。下面的代码也演示了这一点。函数UserDefinedFunction(){警报(this.a+“,”+this.b+“,“+this.c+”,“+this.d”)}变量o1={a: 1中,b: 2,f: 用户定义函数}无功氧气={c: 3中,d: 4中,f: 用户定义函数}UserDefinedFunction.call(o1)//应显示1,2,未定义,未定义UserDefinedFunction.apply(o1)//应显示1,2,未定义,未定义UserDefinedFunction.call(o2)//应显示未定义、未定义、3、4UserDefinedFunction.apply(o2)//应显示未定义、未定义、3、4o1.f.call(o2)//应显示未定义、未定义、3、4o1.f.apply(o2)//应显示未定义、未定义、3、4o2.f.call(o1)//应显示1,2,未定义,未定义o2.f.apply(o1)//应显示1,2,未定义,未定义上述代码清楚地表明,任何“NON”的“this”值绑定函数”可以通过调用/应用来更改。此外,如果“this”参数未显式传递给调用/应用,“current object”(因此“this”的值)在非严格模式下设置为“window”,在严格模式下为“undefined”。在“绑定函数”调用(即通过调用functionName.bind绑定的函数)内部:绑定函数是其“this”值为固定的下面的代码演示了“this”在有界函数的函数UserDefinedFunction(){警报(this.a+“,”+this.b+“,“+this.c+”,“+this.d”)}变量o1={a: 1中,b: 2,f: 用户定义函数,bf:空}无功氧气={c: 3中,d: 4中,f: 用户定义函数,bf:空}var bound1=用户定义函数.bind(o1);//将函数“bound1”的“this”值永久固定到对象o1bound1()//应显示1,2,未定义,未定义var bound2=UserDefinedFunction.bind(o2);//将函数“bound2”的“this”值永久固定到对象o2bound2()//应显示undefined,undefineed,3,4var边界3=o1.f.bind(o2);//将函数“bound3”的“this”值永久固定到对象o2bound3()//应显示undefined,undefineed,3,4var绑定4=o2.f.bind(o1);//永久地将函数“bound4”的“this”值固定到对象o1bound4()//应显示1,2,undefined,undefineo1.bf=UserDefinedFunction.bind(o2)//将函数“o1.bf”的“this”值永久固定到对象o2o1.bf()//应显示未定义、未定义、3,4o2.bf=UserDefinedFunction.bind(o1)//将函数“o2.bf”的“this”值永久固定到对象o1o2.bf()//应显示1,2,未定义,未定义bound1.call(o2)//仍应显示1,2,undefined,undefine。“call”不能更改绑定函数的“this”值bound1.apply(o2)//仍应显示1,2,undefined,undefine。“apply”不能更改绑定函数的“this”值o2.bf。

以下总结了整篇文章

在全局上下文中,“this”总是指“window”对象每当调用函数时,都会在对象(“当前对象”)。如果未明确提供当前对象,当前对象是NON Strict中的“窗口对象”默认情况下,模式和严格模式中的“未定义”。非绑定函数中“this”的值是对调用该函数的上下文中的对象(“当前对象”)的引用非绑定函数中“this”的值可以由调用和应用函数的方法。“this”的值对于Bound函数是固定的,不能被函数的调用和应用方法覆盖。绑定和已绑定函数不会更改“this”的值。它保持设置为第一个绑定函数设置的值。构造函数中“this”的值是已创建并初始化内联DOM事件处理程序中“this”的值是引用指定事件处理程序的元素。

其他回答

由于这篇文章的篇幅有所增加,我为读者整理了一些新的观点。

这个值是如何确定的?

我们使用这个词的方式与我们在英语等自然语言中使用代词的方式类似:“约翰跑得很快,因为他正在赶火车。”相反,我们可以写“……约翰正在赶火车”。

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

在对象调用定义它的函数之前,不会为其赋值。在全局范围中,所有全局变量和函数都在窗口对象上定义。因此,这在全局函数中引用(并且具有的值)全局窗口对象。

当使用strict时,在未绑定到任何对象的全局函数和匿名函数中,它的值为undefined。

this关键字在以下情况下最容易被误解:1)我们借用了一个使用this的方法,2)我们将一个使用它的方法分配给一个变量,3)使用this的函数作为回调函数传递,4)这在闭包内部使用-一个内部函数。(2)

未来是什么

在ECMA脚本6中定义,箭头函数采用来自封闭(函数或全局)范围。

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

虽然箭头函数提供了使用bind()的替代方法,但需要注意的是,它们实际上是在禁用传统的this机制,以支持更广泛理解的词汇范围。(1)


参考文献:

凯尔·辛普森(Kyle Simpson)的《this&Object Prototypes》。©2014 Getify解决方案。javascriptissxy.com-http://goo.gl/pvl0GX 安格斯·克罗尔http://goo.gl/Z2RacU

要正确理解“这”,就必须理解上下文和范围以及它们之间的区别。

作用域:在javascript中,作用域与变量的可见性有关,作用域通过使用函数实现。(阅读有关范围的更多信息)

上下文:上下文与对象相关。它指函数所属的对象。当您使用JavaScript“this”关键字时,它指的是函数所属的对象。例如,在函数内部,当你说:“this.accoutNumber”时,你指的是属性“accoutNumber”,该属性属于该函数所属的对象。

如果对象“myObj”有一个名为“getMyName”的方法,当JavaScript关键字“this”在“getMyName”中使用时,它将引用“myObj”。如果函数“getMyName”是在全局范围内执行的,那么“this”是指窗口对象(严格模式除外)。

现在让我们看看一些示例:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>

在浏览器输出中运行abobve代码将:

根据窗口对象上下文中的输出,也可以看到窗口原型引用了对象。

现在让我们尝试函数内部:

    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>

输出:

输出是相同的,因为我们将“this”变量记录在全局范围中,并将其记录在函数范围中,我们没有更改上下文。在这两种情况下,上下文都是相同的,与寡妇对象相关。

现在让我们创建自己的对象。在javascript中,可以通过多种方式创建对象。

 <script>
        var firstName = "Nora";
        var lastName = "Zaman";
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printNameGetContext:function(){
                console.log(firstName + " "+lastName);
                console.log(this.firstName +" "+this.lastName);
                return this;
            }
        }

      var context = myObj.printNameGetContext();
      console.log(context);
    </script>

输出:

因此,从上面的示例中,我们发现“this”关键字引用的是与myObj相关的新上下文,而myObject也具有到Object的原型链。

让我们再举一个例子:

<body>
    <button class="btn">Click Me</button>
    <script>
        function printMe(){
            //Terminal2: this function declared inside window context so this function belongs to the window object.
            console.log(this);
        }
        document.querySelector('.btn').addEventListener('click', function(){
            //Terminal1: button context, this callback function belongs to DOM element 
            console.log(this);
            printMe();
        })
    </script>
</body>

输出:有道理吧?(阅读评论)

如果您无法理解上面的示例,让我们尝试使用自己的回调;

<script>
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printName:function(callback1, callback2){
                //Attaching callback1 with this myObj context
                this.callback1 = callback1;
                this.callback1(this.firstName +" "+this.lastName)
                //We did not attached callback2 with myObj so, it's reamin with window context by default
                callback2();
                /*
                 //test bellow codes
                 this.callback2 = callback2;
                 this.callback2();
                */
            }
        }
        var callback2 = function (){
            console.log(this);
        }
        myObj.printName(function(data){
            console.log(data);
            console.log(this);
        }, callback2);
    </script>

输出:

现在,让我们了解范围、自我、IIFE和THIS的行为

       var color = 'red'; // property of window
       var obj = {
           color:'blue', // property of window
           printColor: function(){ // property of obj, attached with obj
               var self = this;
               console.log('In printColor -- this.color: '+this.color);
               console.log('In printColor -- self.color: '+self.color);
               (function(){ // decleard inside of printColor but not property of object, it will executed on window context.
                    console.log(this)
                    console.log('In IIFE -- this.color: '+this.color);
                    console.log('In IIFE -- self.color: '+self.color); 
               })();

               function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
                    console.log('nested fun -- this.color: '+this.color);
                    console.log('nested fun -- self.color: '+self.color);
               }

               nestedFunc(); // executed on window context
               return nestedFunc;
           }
       };

       obj.printColor()(); // returned function executed on window context
   </script> 

输出非常棒,对吧?

这里有一个很好的JavaScript源代码。

以下是总结:

全局this在浏览器中,在全局范围内,这是windowobject<script type=“text/javascript”>console.log(此==窗口);//真的var foo=“bar”;console.log(this.foo);//“条形图”console.log(window.foo);//“条形图”在使用repl的节点中,这是顶级命名空间。您可以将其称为全局。>这个{ArrayBuffer:[Function:ArrayBuffer],Int8Array:{[Function:Int8Array]BYTES_PER_ELEMENT:1},Uint8Array:{[Function:Uint8Array]BYTES_PER_ELEMENT:1},...>全局==此真的在从脚本执行的节点中,全局范围中的这个对象以空对象开始。它与全球不同\\测试.jsconsole.log(此);\\{}console.log(this==全局);\\时尚函数this

除了在DOM事件处理程序的情况下,或者当提供了thisArg时(请参见下文),在节点和浏览器中都会在不使用新引用调用全局范围的函数中使用此函数…

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

如果使用use strict;,在这种情况下,这将是未定义的

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

若使用new调用函数,这将是一个新上下文,它将不会引用全局this。

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>

原型

您创建的函数将成为函数对象。它们会自动获得一个特殊的原型属性,这是您可以为其赋值的属性。当您使用new调用函数来创建实例时,您可以访问分配给原型属性的值。您可以使用此访问这些值。

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

在原型上分配数组或对象通常是错误的。如果希望每个实例都有自己的数组,请在函数中创建它们,而不是在原型中创建它们。

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []

反对这个

您可以在对象的任何函数中使用它来引用该对象的其他财产。这与使用new创建的实例不同。

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"

DOM事件this

在HTML DOM事件处理程序中,这始终是对事件附加到的DOM元素的引用

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

除非您绑定上下文

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();

HTML此

在可以放入JavaScript的HTML属性中,这是对元素的引用。

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>

评估此

您可以使用eval访问此。

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();

用这个

您可以使用with将其添加到当前范围中,以读取和写入其值,而无需显式引用它。

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"

jQuery this

jQuery在很多地方都会引用DOM元素。

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

作用域的用法如下

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>

txt1和txt的值相同在上面的示例中$(this)=$('#tbleName tbody-tr')相同

总结此Javascript:

它的值取决于函数的调用方式,而不是创建位置!通常,该值由点左侧的对象确定。(全球空间中的窗口)在事件侦听器中,this的值引用调用事件的DOM元素。当使用new关键字调用函数时,this的值引用新创建的对象您可以使用以下函数操纵此值:call、apply、bind

例子:

let对象={prop1:function(){console.log(this);}}object.prop1();//对象位于点的左侧,因此这是对象constmyFunction=object.prop1//我们将函数存储在变量myFunction中myFunction();//我们在全球空间//myFunction是全局对象的属性//因此,它记录窗口对象

事件侦听器示例:

document.querySelector('.foo').addEventListener('click',函数(){console.log(this);//这是指调用eventListener的DOM元素})document.querySelector('.foo').addEventListener('click',()=>{console.log(this);//提示,es6箭头函数没有自己的绑定到此v})//因此,这将记录全局对象.foo:悬停{颜色:红色;光标:指针;}<div class=“foo”>单击我</div>

示例构造函数:

职能人员(姓名){this.name=名称;}const me=新人('Willem');//当使用new关键字时,构造函数中的this将引用新创建的对象console.log(me.name);//因此,name属性被放置在使用new关键字创建的对象上。