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

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

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


当前回答

这能帮什么忙?(javascript中“this”的大部分混淆是因为它通常不链接到您的对象,而是链接到当前的执行范围——这可能不是它的确切工作方式,但对我来说总是这样——请参阅文章以获得完整的解释)

其他回答

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

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

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

这能帮什么忙?(javascript中“this”的大部分混淆是因为它通常不链接到您的对象,而是链接到当前的执行范围——这可能不是它的确切工作方式,但对我来说总是这样——请参阅文章以获得完整的解释)

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

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

所以如果我做了

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

element.onclick=someKindOfFunction;

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

<element onclick=“someKindOfFunction()”>

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

我对这个问题的看法与我希望有帮助的其他答案不同。

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

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

始终为objectForThis提供一些值。

其他一切都是functionObject.call的语法糖

因此,其他一切都可以通过它如何转换为functionObject.call来描述。

如果你只是调用一个函数,那么这就是“全局对象”,在浏览器中就是窗口

函数foo(){console.log(此);}foo();//这是窗口对象

换句话说,

foo();

被有效地转化为

foo.call(window);

请注意,如果使用严格模式,则这将是未定义的

“使用严格”;函数foo(){console.log(此);}foo();//这是窗口对象

这意味着

换句话说,

foo();

被有效地转化为

foo.call(undefined);

在JavaScript中有+、-和*等运算符。还有点运算符。

这个运算符与右侧的函数和左侧的对象一起使用时,实际上意味着“将对象作为this传递给函数”。

实例

常量bar={name:'bar',foo(){console.log(此);},};bar.foo();//这是酒吧

换句话说,bar.foo()转换为consttemp=bar.foo;临时呼叫(bar);

注意,函数的创建方式并不重要(主要是…)。所有这些都会产生相同的结果

常量bar={name:'bar',fn1(){console.log(this);},fn2:function(){console.log(this);},fn3:其他函数,};函数otherFunction(){console.log(this)};bar.fn1();//这是酒吧bar.fn2();//这是酒吧bar.fn3();//这是酒吧

同样,这些都只是语法糖

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

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

定义对象原型的方法多种多样,2019年最常见的是class关键字。出于这个目的,尽管这并不重要。重要的是,当它在对象a中查找属性b时,如果它在对象上找到属性b,或者在它的原型链中找到属性b(如果b最终是一个函数),那么上述规则同样适用。函数b引用将使用call方法调用,并将a作为objectForThis传递,如该答案顶部所示。

现在让我们想象一下,在调用另一个函数之前,我们创建了一个显式设置此值的函数,然后使用调用它。(点)运算符

函数foo(){console.log(此);}函数栏(){const objectForThis={name:“moo”}foo.call(objectForThis);//显式传递objectForThis}常量对象={酒吧};obj.bar();

在转换为使用调用之后,obj.bar()变为consttemp=obj.bar;临时调用(obj);。当我们进入bar函数时,我们调用foo,但我们显式地为objectForThis传递了另一个对象,所以当我们到达foo时,这是内部对象。

这是bind和=>函数有效的作用。它们是语法糖。他们有效地构建了一个新的不可见函数,就像上面的bar一样,它在调用指定的函数之前显式地设置了这个函数。在绑定的情况下,这将设置为传递给绑定的任何值。

函数foo(){console.log(此);}const bar=foo.bind({name:“moo”});//bind创建了一个新的不可见函数,该函数使用绑定对象调用foo。bar();//我们在这里传递给bar的objectForThis被忽略,因为//绑定创建的不可见函数将使用//我们在上面绑定的对象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不同的是,要绑定的对象是隐式的。当使用=>运算符时,这就是发生的情况。

所以,就像上面的规则一样

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()转换为consttemp=obj.foo;临时调用(obj);这意味着foo中的箭头运算符将obj绑定到一个新的不可见函数,并返回分配给b.b()的新的不可视函数。该不可见函数忽略传递给它的this,并将obj作为objectForThis`传递给箭头函数。

上面的代码翻译为

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是另一个类似于调用的函数

functionName.apply(objectForThis, arrayOfArgs);

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

functionName.call(objectForThis, ...arrayOfArgs);

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

这个值是如何确定的?

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

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