为什么在通过引用传递后调用函数时对象内部 "this" 不同?

Why is "this" different inside object when function is called after being passed by reference?

简而言之:为什么直接调用的函数和通过引用传递的函数在Javascript时有不同的"this"上下文使用对象?

In long: 我定义了一个对象,和一堆方法作为 prototypes,其中使用关键字“this" 访问对象属性。我实例化了该对象,我能够调用这些方法,一切都按预期进行。问题是这些方法中的任何一个都可能抛出一个异常,我想单独捕获每个异常。为了避免重复代码,我实现了一个 runCatch 函数,我将引用传递给要执行的方法和一个回调,当发生错误。在 runCatch 中,我基本上是在执行引用的方法,并用 try-catch[=71= 包装它],但是像这样,“this”关键字指向“Window”对象而不是 对象 本身。因此,根据我对 Javascript 上下文的了解,如果我使用 new 关键字初始化对象,则“this”上下文原型函数应该始终引用对象本身。

这是一个正在发生的事情的小例子:

https://jsbin.com/gugohubori/edit?html,js,output

HTML:

<div>Object Value (Direct Call): 
<span id="val1"></span>
<div>Object Value (Passed by Reference): 
<span id="val2"></span>

Javascript:

// The Object
function myobject(){
  this.value = "IT WORKS"
}

myobject.prototype.getValue = function(){
  return this.value;
}

var obj = new myobject(); // Instantiate Object

// Direct Call (this is correct)
document.getElementById('val1').innerText = obj.getValue();

// Call by reference funciton
function callbyref(callback){ return callback(); }

// Call by reference (this is correct)
document.getElementById('val2').innerText = callbyref(obj.getValue);

而前面代码的结果是:

对象值(直接调用):有效

对象值(通过引用传递):未定义

谁能解释一下为什么“this”的上下文因调用位置而异?让示例中的 callbyref 函数具有正确的“this 的正确方法是什么? " 指向对象的引用?

编辑: 混淆从何而来?所以对我来说主要的困惑似乎是,当你创建一个常规对象“{}”时,该对象内部的 this 的上下文是它被执行的上下文。但是,当您使用 new 关键字创建对象时,该对象内部方法的上下文将绑定到对象本身,无论它们在什么上下文中被调用。但是无论出于何种原因,当函数作为变量传递并在其他地方调用时,有界上下文会丢失(@Carloluis 对此进行了很好的解释)。


关于重复的编辑谁能澄清为什么这个问题被标记为重复? 我知道 this Javascript 中的变量混淆广为流行,似乎是一个微妙的问题,但我在这里提出问题之前一直在研究。 post 被 link 编辑为重复问题并不能解决我的问题,而是以通用方式解释“this”变量和上下文,但从未解释过为什么使用 new 实例化的对象在作为引用传递时最终会丢失其对象上下文。我认为 @Carloluis 的回答比 link 对另一个标记为重复的不相关问题的回答更清楚。

上下文。

//Creates new instance
var obj = new myobject();
//Calls the method in the instance's context
//When a function is called as a method of an object, this is the object
obj.getValue();

//Grabs the reference to the method
var callback=obj.getValue;
//Calls the referenced method in current context, which is window
callback();

你可以试试,添加一个新的方法returns或者打印this到控制台。

如果您需要this始终是对象,您应该使用callback.call(obj,param)apply(obj,params)

问题是 JavaScript 中的 this 关键字值由调用函数的方式决定。

A function's this keyword behaves a little differently in JavaScript compared to other languages.

MDN 上阅读更多内容。

你可以认为函数调用中的 this 指向 "dot" 之前的对象,如果调用中没有任何 . 它将指向到 windows 对象(当您将 obj.getValue 的引用传递给 callbyref 函数时就是这种情况。

function MyObject(){
  this.value = "IT WORKS"
}

MyObject.prototype.getValue = function(){
  return this.value;
}

const myObject = new MyObject();
console.log(myObject.getValue()); // this -> { value: 'IT WORKS' }

const getValueRef = myObject.getValue;
console.log(getValueRef()); // this -> Windows object

// -- Using the `.bind` function to attach the this context
// In the new function this is permanently bound to the first argument of bind, regardless of how the function is being used.
const getValueRefBound = myObject.getValue.bind(myObject);
console.log(getValueRefBound()); // this -> myObject

在前面的代码片段中添加了一个示例,以展示如何将 this 上下文绑定到以后的函数执行,而不管它是如何使用的。

Function.prototype.bind()

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

你也可以检查这个post Understanding Scope and Context in JavaScript.