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

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

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


当前回答

总结此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关键字创建的对象上。

其他回答

JavaScript中的this总是指正在执行的函数的“所有者”。

如果未定义显式所有者,则引用最顶层的所有者窗口对象。

所以如果我做了

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick=someKindOfFunction;

这将引用元素对象。但是要小心,很多人都会犯这个错误。

<element onclick=“someKindOfFunction()”>

在后一种情况下,您只是引用函数,而不是将其交给元素。因此,这将引用窗口对象。

关于这一点,最详细和最全面的文章可能是以下内容:

JavaScript中“this”关键字的温和解释

这背后的想法是理解函数调用类型对设置该值具有重要意义。


当难以识别时,不要问自己:

这是从哪里来的?

但一定要问问自己:

如何调用函数?

对于箭头函数(上下文透明的特殊情况),问问自己:

在定义箭头函数的地方有什么值?

在处理这个问题时,这种心态是正确的,会让你免于头痛。

这是我见过的最好的解释:清晰地理解JavaScripts

此引用总是指(并保持)object-一个单独的对象,通常用于函数或方法,尽管它可以在全局范围请注意,当我们使用strict模式时在全局函数和匿名函数中未定义绑定到任何对象。

有四种情况可能会令人困惑:

当我们传递一个方法(使用此方法)作为参数用作回调函数时。当我们使用内部函数(闭包)时。需要注意的是,闭包不能通过使用this关键字访问外部函数的this变量,因为this变量只能由函数本身访问,而不能由内部函数访问。当依赖于此的方法被分配给跨上下文的变量时,在这种情况下,它引用了另一个对象,而不是最初预期的对象。与bind、apply和call方法一起使用时。

他给出了代码示例、解释和解决方案,我认为这很有帮助。

关于此关键字的一些信息

让我们将此关键字记录到全局范围内的控制台中,无需任何代码

console.log(this)

在客户端/浏览器中,此关键字是一个全局对象,它是窗口

console.log(this === window) // true

and

在Server/Node/Javascript运行时中,此关键字也是一个全局对象,即module.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

请记住,导出只是对module.exports的引用

这里有一个很好的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>