“ this”关键字如何工作?

我注意到,对于Stack Overflow网站上的JavaScriptthis关键字是什么以及如何正确(以及错误地)使用this关键字似乎没有明确的解释。

我目睹了它的一些非常奇怪的行为,并且未能理解为什么会发生它。

怎么this时候它应该被用来工作?


#1楼

丹尼尔,很棒的解释! 在事件处理程序的情况下,在this上下文上下文指针以及this列表中列出了几个单词。

在两个词, this在JavaScript中指出,与人(或将从其执行上下文)当前函数运行对象和它的始终是只读的,你不能设置也无妨(这种尝试将结束“左无效手在作业中的讯息。

对于事件处理程序:内联事件处理程序(例如<element onclick="foo"> )会覆盖之前和之前附加的所有其他处理程序,因此请当心,最好不要使用内联事件委托。 还要感谢Zara Alaverdyan,他通过一次持异议的辩论启发了我列举了以下示例:)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

#2楼

与其他语言相比, this关键字在JavaScript中的行为有所不同。 在面向对象的语言中, this关键字引用该类的当前实例。 在JavaScript中, this值取决于函数的调用上下文( context.function() )及其调用位置。

1.在全球范围内使用

在全局上下文中使用this时,它将绑定到全局对象(浏览器中的window

document.write(this);  //[object Window]

当您在全局上下文中定义的函数中使用this函数时,由于该函数实际上已成为全局上下文的方法, this它仍然绑定到全局对象。

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

f1之上是全局对象的方法。 因此,我们还可以在window对象上调用它,如下所示:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2.当在内部对象方法中使用时

当您使用this关键字的对象方法中, this势必会“立即”包围对象。

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

在上面,我已经将单词立即用双引号引起来。 要指出的是,如果将对象嵌套在另一个对象中,则this对象将绑定到直接父对象。

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

即使你明确的对象添加功能的方法,但它仍然遵循上述规则,那就是this仍然指向直接父对象。

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3.调用无上下文功能时

当您使用this是没有任何上下文中调用(即没有任何物体上)里面的功能,它被绑定到全局对象( window浏览器)(即使该函数的对象中定义)。

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

尝试所有功能

我们也可以使用功能尝试上述几点。 但是有一些区别。

  • 上面我们使用对象文字表示法将成员添加到对象中。 我们可以使用this将成员添加到函数中。 指定它们。
  • 对象文字表示法创建了一个对象实例,我们可以立即使用它。 使用函数,我们可能需要首先使用new运算符创建其实例。
  • 同样在对象文字方法中,我们可以使用点运算符将成员显式添加到已定义的对象中。 这仅添加到特定实例。 但是,我已将变量添加到函数原型中,以使其在函数的所有实例中得到体现。

下面我尝试了所有的事情,我们做了与对象与this之上,但首先创建功能,而不是直接书写的对象。

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4.在构造函数内部使用时

当将该函数用作构造函数时(即使用new关键字调用它时), this内部函数主体指向正在构造的新对象。

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5.在原型链上定义的内部函数中使用时

如果该方法在对象的原型链上,则this方法内部的对象将引用该方法在其上调用的对象,就好像该方法是在对象上定义的一样。

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6.在call(),apply()和bind()函数内部

  • 所有这些方法都在Function.prototype上定义。
  • 这些方法允许一次编写一个函数,然后在不同的上下文中调用它。 换句话说,它们允许指定的值this同时被执行的功能是将被使用。 它们还可以在调用原始函数时采用任何要传递给原始函数的参数。
  • fun.apply(obj1 [, argsArray]) obj1设置为fun()内部的this值,并调用传递给argsArray元素的fun()作为其参数。
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) -将obj1设置this fun()的值,并通过arg1, arg2, arg3, ...调用fun() arg1, arg2, arg3, ...作为其论点。
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) -返回对该函数fun的引用,其中this内部fun绑定到obj1 ,将fun参数绑定到指定的参数arg1, arg2, arg3,...
  • 到目前为止, applycallbind之间的区别必须已经很明显。 apply允许指定参数以充当类似数组的对象,即具有数字length属性和相应的非负整数属性的对象。 而call允许直接指定函数的参数。 applycall立即在指定的上下文中使用指定的参数调用该函数。 另一方面, bind仅返回绑定到指定的this值和参数的函数。 我们可以通过将其分配给变量来捕获对该返回函数的引用,以后我们可以随时调用它。
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. this内部事件处理程序

  • 当直接将函数分配给元素的事件处理程序时,在事件处理函数内部直接使用this函数将引用相应的元素。 可以使用addeventListener方法或通过传统的事件注册方法(如onclick来完成此类直接功能分配。
  • 类似地,当使用this直接事件属性内(如<button onclick="...this..." >的元素,它是指该元素。
  • 但是,通过在事件处理函数或事件属性内部调用的另一个函数间接使用this函数将解析为全局对象window
  • 当我们使用Microsoft的事件注册模型方法attachEvent将函数附加到事件处理程序时,可以实现上述相同的行为。 它没有将功能分配给事件处理程序(因而没有将其分配为元素的功能方法),而是在事件上调用了功能(在全局上下文中有效地调用了该功能)。

我建议最好在JSFiddle中尝试一下

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

8. this在ES6箭头功能

在箭头函数中, this行为类似于普通变量:它将从其词法范围继承。 函数的this ,其中定义了arrow函数,将是arrow函数的this

因此,这与以下行为相同:

(function(){}).bind(this)

请参见以下代码:

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 

#3楼

JavaScript中的this始终是指所执行函数的“所有者”。

如果未定义任何显式所有者,则引用最高的所有者,即窗口对象。

所以如果我做到了

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

element.onclick = someKindOfFunction;

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

<element onclick="someKindOfFunction()">

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


#4楼

this是JavaScript中一个被误解的概念之一,因为它的行为因地而异。 简单来说, this是指我们当前正在执行的函数“所有者”

this有助于获取我们正在使用的当前对象(也称为执行上下文)。 如果您了解当前函数正在哪个对象中执行,则可以轻松了解this是什么当前对象

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

在上方,我们创建了3个具有相同名称“ val”的变量。 一个在全局上下文中,一个在obj内部,另一个在obj的innerMethod内部。 JavaScript通过将范围链从本地扩展到全局来解析特定上下文中的标识符。


很少有地方this可以分化

调用对象的方法

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

当执行行1,JavaScript的建立了函数调用执行上下文(EC),设置this 由之前的最后一次自由随性引用对象“” 。 因此,在最后一行中,您可以了解a()是在作为window的全局上下文中执行的。

与构造函数

this可以用来指代正在创建的对象

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

当执行new Person() ,将创建一个全新的对象。 Person被称为其this设置为参考新对象。

函数调用

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

如果我们错过了new关键字, whatIsThis指的是它可以找到的最全局的上下文( window

使用事件处理程序

如果事件处理程序为内联, this引用全局对象

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

通过JavaScript添加事件处理程序时, this是指生成事件的DOM元素。



#5楼

Javascript的this

简单函数调用

考虑以下功能:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

请注意,我们在正常模式下运行此程序,即未使用严格模式。

当在浏览器中运行,值this将被记录为window 。 这是因为window是Web浏览器范围内的全局变量。

如果你像node.js中的环境中运行该同一段代码, this将涉及到全局变量在你的应用程序。

现在,如果我们在严格模式下通过添加语句"use strict"; 到函数声明的开头, this将不再引用这两种环境中的全局变量。 这样做是为了避免在严格模式下造成混淆。 this会,在这种情况下,只要登录undefined ,因为那是它是什么,没有定义它。

在以下情况下,我们将看到如何操纵this的值。

在对象上调用函数

有不同的方法可以做到这一点。 如果您已经使用诸如forEachslice类的Javascript调用了本机方法,那么您应该已经知道,在this情况下, this变量引用了您在其上调用了该函数的Object (请注意,在javascript中,几乎所有东西都是Object ,包括ArrayFunction )。 以下面的代码为例。

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

如果Object包含一个包含Function的属性,则该属性称为方法。 调用此方法时,将始终this变量设置为与之关联的Object 。 对于严格和非严格模式都是如此。

注意,如果一个方法被存储(或更确切地说,复制)在另一变量中,参照this不再保留在新的变量。 例如:

// continuing with the previous code snippet

var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation

考虑一个更常见的实际情况:

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

new关键字

考虑一下Javascript中的构造函数:

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

这是如何运作的? 好吧,让我们看看使用new关键字时会发生什么。

  1. 使用new关键字调用该函数将立即初始化Person类型的Object
  2. Object的构造函数将其构造函数设置为Person 。 另外,请注意typeof awal将仅返回Object
  3. 将为该新Object分配Person.prototype的原型。 这意味着Person原型中的任何方法或属性都可用于Person所有实例,包括awal
  4. 现在,功能Person本身被调用; this是对新建物体awal

很简单,是吗?

请注意,官方ECMAScript规范无处声明此类函数是实际的constructor函数。 它们只是正常功能,而new可以在任何功能上使用。 只是我们原样使用它们,因此我们仅如此称呼它们。

在函数上调用函数: callapply

是的,因为function也是Objects (实际上是Javascript中的第一类变量),所以即使函数也具有本身就是函数的方法。

所有的功能从全球继承Function ,及其两个多方法callapply ,都可以用来操纵的值this在它们所调用的函数。

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

这是使用call的典型示例。 它基本上采用第一个参数,并在函数foo this参数设置为对thisArg的引用。 传递给call所有其他参数作为参数传递给foo函数。
因此,上面的代码将在控制台中记录{myObj: "is cool"}, [1, 2, 3] 。 相当不错的方法来改变的值this在任何功能。

apply几乎与call accept相同,它只接受两个参数: thisArg和一个包含要传递给函数的参数的数组。 因此,上述call可以转换为如下apply

foo.apply(thisArg, [1,2,3])

注意, callapply可以通过我们在第二个项目符号中讨论的点方法调用来覆盖this设置的值。 很简单:)

呈现.... bind

bindcallapply的兄弟。 它也是所有函数从Javascript的全局Function构造函数继承的方法。 bindcall / apply之间的区别是callapply都将实际调用该函数。 另一方面, bind返回一个带有thisArgarguments预设的新函数。 让我们举个例子来更好地理解这一点:

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

看到两者之间的区别了吗? 它很微妙,但是用法不同。 像callapply一样, bind也将通过点方法调用来覆盖this设置的值。

另请注意,这三个功能均未对原始功能进行任何更改。 callapply将从新构造的函数返回值,而bind将返回新构造的函数本身,随时可以调用。

多余的东西,复制此

有时候,你不喜欢的事实, this改变与范围,尤其是嵌套的范围。 看下面的例子。

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

在上面的代码中,我们看到的价值this与嵌套的范围内改变,但我们想要的值, this从原来的范围。 因此,我们“复制” thisthat和所使用的副本,而不是this 。 聪明吧?

指数:

  1. 默认情况下, this是什么?
  2. 如果我们将该函数作为带有对象点表示法的方法来调用该怎么办?
  3. 如果我们使用new关键字怎么办?
  4. 我们如何通过callapply操作this
  5. 使用bind
  6. 复制this可解决嵌套范围问题。

#6楼

由于该主题的发展,我为刚接触this主题的读者提供了几点建议。

价值如何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);
    }
}

this直到对象调用定义它的功能不被分配的值 。 在全局范围内,所有全局变量和函数都在window对象上定义。 因此,全局函数中的this引用全局window对象(并具有其值)。

use strict ,在未绑定到任何对象的全局函数和匿名函数中, this函数的值均为undefined

this关键字是最容易被误解时:1)我们借用一个使用方法this ,2)我们分配方法,该方法使用this到一个变量,3)的函数,它使用this作为一个回调函数传递,和4) this是在闭包内部使用-内部函数。 (2)

表

是什么把握未来

ECMA脚本6中定义,箭头功能从封闭的(功能或全局)范围采用this绑定。

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)


参考文献:

  1. this&Object Prototypes ,作者:凯尔·辛普森(Kyle Simpson)。 ©2014 Getify解决方案。
  2. javascriptissexy.com- http://goo.gl/pvl0GX
  3. 安格斯卡罗尔-http: //goo.gl/Z2RacU

#7楼

javascript中的每个 函数 执行上下文都有一个 范围 上下文, 范围 以下参数设置:

  1. 函数的调用方式(包括作为对象方法,使用callapply ,使用new
  2. 绑定的使用
  3. 用词法表示箭头函数(它们采用外部执行上下文的this

无论范围上下文是什么,均由“ this”引用。

您可以使用func.callfunc.applyfunc.bind 更改 设置 范围 上下文 值的值。

默认情况下,什么迷惑大多数初学者,当事件被一个DOM元素上引发后 回调 监听器被调用, 范围方面 功能的这个值是的DOM元素。

jQuery使用jQuery.proxy可以轻松地进行更改。


#8楼

我建议先阅读Mike West的文章Scope in JavaScript镜像 )。 这是一个很好的,友好的介绍的概念, this在JavaScript和范围链。

一旦你开始习惯this的规则实际上是相当简单的。 ECMAScript 5.1标准 this定义:

§11.1.1this关键字

this关键字的值为当前执行上下文的ThisBinding的值

JavaScript解释器在评估JavaScript代码时会维护ThisBinding,例如特殊的CPU寄存器,其中包含对对象的引用。 每当仅在以下三种情况之一中建立执行上下文时,解释器就会更新ThisBinding:

1.初始全局执行上下文

在顶级代码中评估的JavaScript代码就是这种情况,例如,直接在<script>内部时:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

在初始的全局执行上下文中评估代码时,ThisBinding设置为全局对象window (第10.0.4.1.1节 )。

输入评估码

  • …直接调用eval() Binding保持不变; 它与调用执行上下文的ThisBinding (第10.4.2 (2)(a)节)的值相同。

  • …如果不是通过直接调用eval()
    将这个Binding设置为全局对象,就像在初始全局执行上下文中执行一样(第10.4.2 (1)节)。

§15.1.2.1.1定义了对eval()的直接调用。 基本上, eval(...)是直接调用,而类似(0, eval)(...)var indirectEval = eval; indirectEval(...); var indirectEval = eval; indirectEval(...); 是对eval()的间接调用。 请参阅chuckj对JavaScript中的 (1,eval)('this')vs eval('this') 的回答 Dmitry Soshnikov的ECMA-262-5详细信息。 第2章严格模式。 当您可能使用间接eval()调用时。

输入功能码

调用函数时会发生这种情况。 如果在对象上调用了函数,例如obj.myMethod()或等效的obj["myMethod"]() ,则ThisBinding设置为对象(示例中为obj ;第13.2.1节 )。 在大多数其他情况下,ThisBinding设置为全局对象(第10.4.3节 )。

之所以写“在大多数情况下”,是因为有八个ECMAScript 5内置函数可以在参数列表中指定ThisBinding。 这些特殊功能采用了一个所谓的thisArg ,当调用该函数时,它会成为ThisBinding(第10.4.3节 )。

这些特殊的内置函数是:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

对于Function.prototype函数,它们是在函数对象上调用的,而不是将ThisBinding设置为函数对象,而是将ThisBinding设置为thisArg

对于Array.prototype函数,将在执行上下文中调用给定的callbackfn ,其中,如果提供,则将ThisBinding设置为thisArg 。 否则,转到全局对象。

这些是纯JavaScript的规则。 当您开始使用JavaScript库(例如jQuery)时,您可能会发现某些库函数会操纵this的值。 这些JavaScript库的开发人员之所以这样做是因为它倾向于支持最常见的用例,并且该库的用户通常会发现此行为更加方便。 将引用this回调函数传递给库函数时,应确保参考该文档,以确保有关在调用函数时this的值的任何保证。

如果您想知道JavaScript库如何处理this的值,则该库仅使用接受thisArg的内置JavaScript函数thisArg 。 您也可以使用回调函数和thisArg编写自己的函数:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

我还没有提到一个特殊情况。 通过new运算符构造新对象时,JavaScript解释器会创建一个新的空对象,设置一些内部属性,然后在新对象上调用构造函数。 因此,当一个函数被调用在构造方面,的值this是解释创建的新对象:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

箭头功能

箭头功能 (在ECMA6引入)改变的范围this 。 参见现有规范问题, 箭头函数与函数声明/表达式:它们是否等效/可互换? 想要查询更多的信息。 简而言之:

箭自己的职能没有this ....结合。 相反,这些标识符像任何其他变量一样在词法范围内解析。 这意味着,一个箭头函数内部, this ...参照(一个或多个),以的值this在箭头函数是在定义的环境。

只是为了好玩,请通过一些例子测试您的理解

要显示答案,请将鼠标悬停在浅黄色框上。

  1. 什么是值this在标线? 为什么?

    window —在初始全局执行上下文中评估标记的行。

     if (true) { // What is `this` here? } 
  2. 什么是价值this当标线obj.staticFunction()执行? 为什么?

    obj —在对象上调用函数时,ThisBinding设置为该对象。

     var obj = { someData: "a string" }; function myFun() { return this // What is `this` here? } obj.staticFunction = myFun; console.log("this is window:", obj.staticFunction() == window); console.log("this is obj:", obj.staticFunction() == obj); 

  3. 什么是值this在标线? 为什么?

    window

    在此示例中,JavaScript解释器输入函数代码,但是由于未在对象上调用myFun / obj.myMethod ,因此ThisBinding设置为window

    这与Python不同,在Python中,访问方法( obj.myMethod )创建绑定的方法对象

     var obj = { myMethod: function () { return this; // What is `this` here? } }; var myFun = obj.myMethod; console.log("this is window:", myFun() == window); console.log("this is obj:", myFun() == obj); 

  4. 什么是值this在标线? 为什么?

    window

    这个很棘手。 在评估评估代码时, thisobj 。 然而,在EVAL代码, myFun不是在对象上调用,所以ThisBinding设置为window的呼叫。

     function myFun() { return this; // What is `this` here? } var obj = { myMethod: function () { eval("myFun()"); } }; 
  5. 什么是值this在标线? 为什么?

    obj

    myFun.call(obj); 正在调用特殊的内置函数Function.prototype.call() ,该Function.prototype.call()接受thisArg作为第一个参数。

     function myFun() { return this; // What is `this` here? } var obj = { someData: "a string" }; console.log("this is window:", myFun.call(obj) == window); console.log("this is obj:", myFun.call(obj) == obj); 


#9楼

对子级帮助? (JavaScript中的“ this”最令人困惑的原因是,它通常不链接到您的对象,而是链接到当前的执行范围-可能不完全是它的工作方式,但在我看来总是这样-请参阅文章以获取完整说明)


#10楼

“这”是关于范围的。 每个函数都有自己的作用域,并且由于JS中的所有对象都是对象,所以即使一个函数也可以使用“此”将一些值存储到自身中。 OOP 101教导“此”仅适用于对象的实例 。 因此,每次执行一个功能时,该功能的新“实例”具有新的含义“ this”。

大多数人在匿名闭包函数中尝试使用“ this”时会感到困惑:

(function(value) {
    this.value = value;
    $('.some-elements').each(function(elt){
        elt.innerHTML = this.value;        // uh oh!! possibly undefined
    });
})(2);

所以在这里,在each()中,“ this”不包含您期望它(从

this.value = value;
它上面)。 因此,要解决此问题(无双关语),开发人员可以:

\n (函数(值){\n     var self = this;  // 小变化\n     self.value =值;\n     $('。some-elements')。each(function(elt){\n         elt.innerHTML = self.value;  // phe!  == 2 \n     });\n })(2);\n

试试看; 您将开始喜欢这种编程模式


#11楼

如果您不完全了解JS,那么很难很好地掌握JS或编写比它更琐碎的东西。 您不能只是快速浏览一下:)我认为入门JS的最佳方法是先观看Douglas Crockford的这些视频讲座-http: //yuiblog.com/crockford/ ,其中涵盖了所有内容,以及关于JS的其他一切。


#12楼

这里是一个很好的来源thisJavaScript

这是摘要:

  • 全球这个

    在浏览器中,在全局范围内, thiswindow对象

     <script type="text/javascript"> console.log(this === window); // true var foo = "bar"; console.log(this.foo); // "bar" console.log(window.foo); // "bar" 

    在使用repl的nodethis是顶级名称空间。 您可以将其称为global

     >this { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... >global === this true 

    在通过脚本执行的nodethis在全局范围内从一个空对象开始。 它与global

     \\\\test.js console.log(this); \\\\ {} console.log(this === global); \\\\ fasle 
  • 发挥这个作用

除了在DOM事件处理程序中或在提供thisArg时(参见下文),在节点和浏览器中都使用this函数,而该函数未使用new引用调用全局范围…

<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; ,在这种情况下this将是undefined

<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将是一个新的上下文,它将不会引用全局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>
  • 原型

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

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

Thing.prototype.foo = "bar";

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

prototype上分配数组对象通常是一个错误。 如果您希望实例各自具有自己的数组,请在函数(而不是原型)中创建它们。

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 []
  • 反对这个

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

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

obj.logFoo(); //logs "bar"
  • DOM事件

在HTML DOM事件处理程序中, this始终是对事件附加到的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();

除非您bind上下文

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属性内, this是对该元素的引用。

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

您可以使用eval来访问this

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

var thing = new Thing();
thing.logFoo();
  • 有了这个

您可以使用with添加this到目前的范围,读取和写入值在this没有提到this明确。

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的这个

jQuery在许多地方都this引用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>

#13楼

像这样用于Scope

  <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')是相同的


#14楼

这是我见过的最好的解释: 了解清晰的JavaScript

引用始终引用(并保持其值)一个对象(单个对象),并且通常在函数或方法内部使用,尽管可以在全局范围内在函数外部使用。 请注意,当我们使用严格模式时,它在全局函数和未绑定到任何对象的匿名函数中都具有未定义的值。

有四个场景中会引起混乱:

  1. 当我们传递一个方法(使用this )作为参数用作回调函数时。
  2. 当我们使用内部函数(闭包)时。 请务必注意,闭包无法使用this关键字访问外部函数的this变量,因为this变量只能由函数本身访问,而不能由内部函数访问。
  3. 当其依赖于方法被分配给跨过上下文的变量,在这种情况下, 引用另一个目的比最初预期。
  4. 当使用这种与绑定一起,应用和调用方法。

他提供了代码示例,解释和解决方案,我认为这非常有帮助。


#15楼

可能有关this内容的最详细,最全面的文章如下:

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

背后的想法this是了解函数调用类型对设置显著重视this值。


在遇到问题时识别this问自己:

this从哪里来的

不要问自己:

该函数如何调用

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

定义箭头功能的情况下, this值有什么值?

在处理this问题时, this心态是正确的,可以使您免于头痛。


#16楼

关于如何在JavaScript中解释“ this”关键字存在很多困惑。 希望本文能使所有这些东西一劳永逸。 还有更多。 请仔细阅读整篇文章。 请注意,本文篇幅较长。

无论使用哪种上下文, “ this”始终引用Javascript中的“当前对象” 。 但是, “当前对象”的含义根据上下文而有所不同。 上下文可能恰好是以下6个中的1个

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

下面逐一描述每种情况:

  1. 全局上下文 (即在所有功能之外):

    在所有函数之外(即,在全局上下文中), “当前对象” (以及因此“ this”的值)始终是浏览器的“窗口”对象。

  2. 内部直接“无界函数”调用

    在直接的“非绑定函数”调用中, 调用该函数调用的对象将成为“当前对象” (并因此成为“ this”的值)。 如果在没有显式当前对象的情况下调用函数,则当前对象“窗口”对象(对于非严格模式)或未定义 (对于严格模式)。 全局上下文中定义的任何函数(或变量)都会自动成为“窗口”对象的属性。例如,假设函数在全局上下文中定义为

     function UserDefinedFunction(){ alert(this) } 

    它成为窗口对象的属性,就像您已将其定义为

     window.UserDefinedFunction=function(){ alert(this) } 

    在“非严格模式”下,直接通过“ UserDefinedFunction()”调用/调用此函数会自动将其作为“ window.UserDefinedFunction()”进行调用/调用,从而使“ window”成为“当前对象” (因此, “ “”“ UserDefinedFunction ”中 )。在“非严格模式”下调用此函数将导致以下情况

     UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction() 

    在“严格模式”下,直接通过“ UserDefinedFunction()”调用/调用该函数将“不”自动将其作为“ window.UserDefinedFunction()”调用/调用。因此, “当前对象” (以及“ this”的值) ) “ UserDefinedFunction”中的)应为undefined 。 在“严格模式”下调用此功能将导致以下情况

     UserDefinedFunction() // displays undefined 

    但是,使用window对象显式调用它会导致以下结果

     window.UserDefinedFunction() // "always displays [object Window] irrespective of mode." 

    让我们看另一个例子。 请看下面的代码

      function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } o1.f() // Shall display 1,2,undefined,undefined o2.f() // Shall display undefined,undefined,3,4 

    在上面的示例中,我们看到当通过o1调用“ UserDefinedFunction”时, “ this”的值为o1,并且显示其属性“ a”“ b”的值。 “ c”“ d”的值显示为未定义,因为o1 未定义这些属性

    类似地,当通过o2调用“ UserDefinedFunction”时, “ this”取值为o2并显示其属性“ c”“ d”的值。与o2一样, “ a”“ b”的值显示为未定义没有定义这些属性。

  3. 内部间接“非绑定函数”通过functionName.callfunctionName.apply调用

    通过functionName.callfunctionName.apply调用“非绑定函数”时“当前对象” (因此是“ this”的值)被设置为传递给call“ this”参数(第一个参数)的值/应用 。 以下代码演示了相同的内容。

     function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4 UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4 o1.f.call(o2) // Shall display undefined,undefined,3,4 o1.f.apply(o2) // Shall display undefined,undefined,3,4 o2.f.call(o1) // Shall display 1,2,undefined,undefined o2.f.apply(o1) // Shall display 1,2,undefined,undefined 

    上面的代码清楚地表明,可以通过call / apply更改任何“ NON Bound Function”的“ this”值。 同样,如果未将“ this”参数显式传递给call / apply ,则在非严格”模式下, “当前对象” (因此,“ this”的值)将设置为“窗口”,在严格模式下将设置为“未定义”

  4. 在“绑定函数”内部调用 (即,已通过调用functionName.bind绑定的函数 ):

    绑定函数是其“ this”值已固定的函数。 以下代码演示了在绑定函数的情况下“ this”如何工作

     function UserDefinedFunction() { alert(this.a + "," + this.b + "," + this.c + "," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction, bf:null } var o2={ c:3, d:4, f:UserDefinedFunction, bf:null } var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1 bound1() // Shall display 1,2,undefined,undefined var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2 bound2() // Shall display undefined,undefined,3,4 var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2 bound3() // Shall display undefined,undefined,3,4 var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1 bound4() // Shall display 1,2,undefined,undefined o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2 o1.bf() // Shall display undefined,undefined,3,4 o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1 o2.bf() // Shall display 1,2,undefined,undefined bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function 

    如以上代码中所给, 任何“绑定函数”的“ this”值都不能通过call / apply进行更改 。 另外,如果未明确传递“ this”参数进行绑定,则在非严格”模式下将“当前对象” (因此将“ this”的值)设置为“ window”,在严格模式下将设置为“ undefined” 。 还有一件事。 绑定已经绑定的函数不会更改“ this”的值。 它仍然设置为第一个绑定函数设置的值。

  5. 通过“ new”创建对象时

    在构造函数中, “当前对象” (因此是“ this”的值)引用当前通过“ new”创建的对象,而与函数的绑定状态无关。 但是,如果构造函数是绑定函数,则应使用为绑定函数设置的预定义参数集来调用它。

  6. 内部内联DOM事件处理程序

    请查看以下HTML代码段

     <button onclick='this.style.color=white'>Hello World</button> <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div> 

    上面示例中的“ this”分别表示“ button”元素和“ div”元素。

    在第一个示例中,单击按钮时,其字体颜色应设置为白色。

    在第二个示例中,当单击“ div”元素时,它将使用其第二个参数引用被单击的div元素来调用OnDivClick函数。 但是,OnDivClick中的“ this”不应引用所单击的div元素。 应分别在 严格模式严格模式下将其设置为“窗口对象”“未定义” (如果OnDivClick未绑定函数 ),或者设置为预定义的Bound值(如果OnDivClick绑定函数

以下总结了整篇文章

  1. 在全局上下文中, “ this”始终引用“ window”对象

  2. 每当调用函数时,都会在对象( “当前对象” )的上下文中调用该函数。 如果没有明确提供当前对象当前对象“窗口对象” 非严格模式 ,并在默认情况下,严格模式“不确定”。

  3. Non Bound函数中的“ this”的值是对调用该函数的对象的引用( “当前对象”

  4. Non Bound函数中的“ this”值可以通过调用应用函数的方法来覆盖。

  5. 对于绑定函数, “ this”的值是固定的,不能被该函数的调用应用方法覆盖。

  6. 绑定和已经绑定的函数不会更改“ this”的值。 它仍然设置为第一个绑定函数设置的值。

  7. 构造函数中“ this”的值是正在创建和初始化的对象

  8. 内联DOM事件处理程序中的“ this”的值引用为其提供事件处理程序的元素。


#17楼

“ this”的值取决于在其中执行功能的“上下文”。 上下文可以是任何对象或全局对象,即窗口。

因此,“ this”的语义不同于传统的OOP语言。 这会导致问题:1.将函数传递给另一个变量(最有可能是回调)时; 2.从类的成员方法调用闭包时。

在两种情况下,都将其设置为window。


#18楼

用伪古典术语来说,许多课程讲授“ this”关键字的方式是作为由类或对象构造函数实例化的对象。 每次从类构造一个新对象时,请想象在幕后创建并返回“ this”对象的本地实例。 我记得它的教导是这样的:

function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;

#19楼

有关关键字的一点信息

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

console.log(this)

客户端/浏览器中, this关键字是一个全局对象,即window

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

服务器/节点/ Javascript运行时中, this关键字也是一个全局对象,它是module.exports

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

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


#20楼

总结this JavaScript:

  • this怎样的功能不会被调用,在创建它确定
  • 通常的值this是由留在点的对象来确定。 (全球空间window
  • 在事件侦听器中, this值表示在其上调用事件的DOM元素。
  • 当使用new关键字调用in函数时, this值引用新创建的对象
  • 您可以使用以下函数来操纵this的值: callapplybind

例:

 let object = { prop1: function () {console.log(this);} } object.prop1(); // object is left of the dot, thus this is object const myFunction = object.prop1 // We store the function in the variable myFunction myFunction(); // Here we are in the global space // myFunction is a property on the global object // Therefore it logs the window object 

示例事件侦听器:

 document.querySelector('.foo').addEventListener('click', function () { console.log(this); // This refers to the DOM element the eventListener was invoked from }) document.querySelector('.foo').addEventListener('click', () => { console.log(this); // Tip, es6 arrow function don't have their own binding to the this v }) // Therefore this will log the global object 
 .foo:hover { color: red; cursor: pointer; } 
 <div class="foo">click me</div> 

构造函数示例:

 function Person (name) { this.name = name; } const me = new Person('Willem'); // When using the new keyword the this in the constructor function will refer to the newly created object console.log(me.name); // Therefore, the name property was placed on the object created with new keyword. 


#21楼

简单答案:

“ this”关键字始终取决于调用的上下文。 它们在下面提到。

  1. 使用新关键字调用功能

    如果使用NEW关键字调用该函数,则THIS将绑定到新创建的对象。

     function Car(){ this.name="BMW"; } const myCar=new Car(); myCar.name; // output "BMW" 

    在上面,这将绑定到“ myCar”对象

  2. 使用呼叫和应用方法明确调用功能。

    在这种情况下,THIS将绑定到显式传递给函数的对象。

     var obj1={"name":"bond"}; function printMessage(msg){ return msg+" "+this.name; } const message=printMessage.call(obj1,"my name is "); console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO. 
  3. 如果隐式调用了功能,则将其绑定到该对象

     var obj1={ "name":"bond", getName: function () { return this.name; } }; const newname=obj1.getName(); console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT) 
  4. 在没有任何上下文的情况下调用功能时,它将被绑定到全局对象中

     const util = { name: 'Utility', getName: function () { return this.name; }; const getName=util.getName; const newName=getName(); console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT 
  5. 在严格模式下,这将是不确定的

     function setName(name){ "use strict" return this.name; } setName(); //WILL BE ERROR SAYING name IS UNDEFINED. 

#22楼

我有不同的看法上this从其他的答案,我希望是有帮助的。

查看JavaScript的一种方法是看到只有一种方法可以调用函数1 。 它是

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

始终为objectForThis提供一些值。

其他所有内容都是functionObject.call语法糖

因此,其他所有内容都可以通过将其转换为functionObject.call来描述。

如果只调用一个函数,则this是“全局对象”,在浏览器中是窗口

 function foo() { console.log(this); } foo(); // this is the window object 

换一种说法,

foo();

被有效地翻译成

foo.call(window);

请注意,如果您使用严格模式,那么this将是undefined

 'use strict'; function foo() { console.log(this); } foo(); // this is the window object 

意思是

换一种说法,

foo();

被有效地翻译成

foo.call(undefined);

在JavaScript中,有+-*类的运算符。 还有点运算符.

. 运算符与右侧的功能和左侧的对象一起使用时,实际上表示“将对象作为this函数传递。

 const bar = { name: 'bar', foo() { console.log(this); }, }; bar.foo(); // this is bar 

换句话说, bar.foo()转换为const temp = bar.foo; temp.call(bar); const temp = bar.foo; temp.call(bar);

请注意,函数的创建方式无关紧要(主要是...)。 所有这些都会产生相同的结果

 const bar = { name: 'bar', fn1() { console.log(this); }, fn2: function() { console.log(this); }, fn3: otherFunction, }; function otherFunction() { console.log(this) }; bar.fn1(); // this is bar bar.fn2(); // this is bar bar.fn3(); // this is bar 

同样,这些都是语法糖

{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }

原型链是另一个难题。 当您使用ab的JavaScript首先查找直接引用的对象上a的属性b 。 如果在对象上未找到b ,则JavaScript将在对象的原型中查找b

有多种定义对象原型的方法,2019年最常见的是class关键字。 出于此目的, this并不重要。 重要的是,因为它看起来在对象a物业b ,如果它发现性能b物体上或它的原型链中,如果b结束是一个函数,则相同的规则,上述申请。 函数b引用将使用被称为call方法并传递a作为objectForThis如图此答案的顶部。

现在。 假设我们创建了一个函数,该函数在调用另一个函数之前显式设置this函数,然后使用调用它. (点)运算符

 function foo() { console.log(this); } function bar() { const objectForThis = {name: 'moo'} foo.call(objectForThis); // explicitly passing objectForThis } const obj = { bar, }; obj.bar(); 

经过翻译后可以使用callobj.bar()变为const temp = obj.bar; temp.call(obj); const temp = obj.bar; temp.call(obj); 。 当我们进入bar函数时,我们将调用foo但我们为objectForThis显式传递了另一个对象,因此,当我们到达foo时, this就是该内部对象。

这是bind=>函数都有效执行的操作。 它们是语法更多的糖。 他们有效地建立一个新的隐形功能酷似bar上面明确设置this调用指定的任何功能之前。 在bind的情况下, this值设置为您传递给bind

 function foo() { console.log(this); } const bar = foo.bind({name: 'moo'}); // bind created a new invisible function that calls foo with the bound object. bar(); // the objectForThis we are passing to bar here is ignored because // the invisible function that bind created will call foo with with // the object we bound above bar.call({name: 'other'}); 

请注意,如果不存在functionObject.bind我们可以像这样制作自己的

function bind(fn, objectForThis) {
  return function(...args) {
    return fn.call(objectForthis, ...args);
  };
}

然后我们可以这样称呼它

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

const bar = bind(foo, {name:'abc'});

箭头函数, =>运算符是绑定的语法糖

const a = () => {console.log(this)};

是相同的

const tempFn = function() {console.log(this)}; 
const a = tempFn.bind(this);

就像bind一样,创建了一个新的不可见函数,该函数使用给定的objectForThis绑定值调用给定函数,但与bind不同,要bind的对象是隐式的。 这是无论this情况发生的时候是=>使用运营商。

所以,就像上面的规则

const a = () => { console.log(this); }  // this is the global object
'use strict';
const a = () => { console.log(this); }  // this is undefined
function foo() {
  return () => { console.log(this); }
}

const obj = {
  foo,
};
const b = obj.foo();
b();

obj.foo()转换为const temp = obj.foo; temp.call(obj); const temp = obj.foo; temp.call(obj); 这意味着foo的箭头运算符会将obj绑定到新的不可见函数,并返回分配给b新不可见函数。 b()将像b.call(window)b.call(undefined)调用foo创建的新的不可见函数。 这个不可见的函数会忽略传递给它的this并将obj作为objectForThis`传递给arrow函数。

上面的代码转换为

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply是另一个类似于call功能

functionName.apply(objectForThis, arrayOfArgs);

但从ES6概念上讲,您甚至可以将其转换为

functionName.call(objectForThis, ...arrayOfArgs);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值