`this` 的绑定和调用站点

`this` binding and call-site of `this`

函数是否可以访问其调用站点中的所有信息?

我认为也许某个函数可以访问其调用站点范围,否则我可能会弄错,因此非常感谢您的反馈和解释。

function bar() {
    // call-stack is: `bar`
    // so, our call-site is in the global scope
    let a = “heyo”;
    console.log( “bar” );
    foo(); // ← call-site for `foo`
}

function foo() {
    // call-stack is: `bar` -> `foo`
    // so, our call-site is in `bar`
    console.log( “foo “ + this.a );
}
bar(); // ← call-site for `bar`

这里,this.a returns没有定义,但是如果它的调用点是声明a的地方,它不应该可以访问变量a吗?

foo()中的this指的是调用它的上下文,在片段中它是在没有定义变量a的全局上下文中调用的所以你得到 undefined

您还使用 let 声明了 a,这会创建一个块作用域变量。如果您使用 var 在函数外部声明 a,它将在全局范围内创建一个变量。

在我的代码片段中,我创建了一个具有两个属性 afoo 方法的对象。现在,如果您在 obj 的上下文中调用 obj.foo() 方法,this 将指向 obj 对象,因为我使用 [=18= 声明了 a ] 在全局调用 foo() 时将从全局范围打印 a 的值:

var a = "from global";

function bar() {
   //lexical context is global
   //let defines a variable in the enclosing scope
   let a = "heyo";
   console.log( "bar" );
   //foo is called within the global context, so this points to global object.
   foo(); 
   let obj = {a : "from obj", foo};
   // or foo.bind(obj); which sets the this context
   //now foo is called in the context of object "obj" so this points to obj
   obj.foo(); 
}
function foo() {
   console.log( "foo " + this.a );
}
bar(); 

首先,提出的问题根本不包含 this,这很有趣,因为它是所提供问题的一个神奇例外。

JavaScript 是词法范围的。也就是说,函数可以访问它们 定义的范围 ,但不能访问当前堆栈任意位置的值。

const rememberX = (x) => () => x;
// a function that takes a value and returns a function
// when the inner function is called, it returns the value

let x = 5;
let x42 = rememberX(42);
let x10 = rememberX(10);
x = 20;

x42(); // 42
x10(); // 10

词法作用域提供了闭包的概念,这就是上述工作的原因。这使得它在传统情况下不太像其他语言,而更像是一种函数式编程语言。

有趣的是,this 是打破这种模式的唯一价值。它是异常延迟绑定的,并且在执行的那一刻就确定了。

class Person {
  constructor (name) {
    this.type = "person";
    this.name = name;
  }

  sayHi () {
    console.log(`${this.name}, the ${this.type}, says “Hi”.`);
  }
}


const bob = new Person("Bob");
bob.sayHi(); // "Bob, the person, says “Hi”."

const spot = {
  type: "dog",
  name: "Spot",
  sayHi: bob.sayHi
};

spot.sayHi(); // "Spot, the dog, says “Hi”."

bob.sayHi.apply({
  type: "ape",
  name: "Grape"
}); // "Grape, the ape, says “Hi”."
// apply is a method that all functions have,
// which sets `this` for this invocation


const bind = function (method, overriddenThis) {
  return function (...args) {
    return method.apply(overriddenThis, args);
  };
};
// bind also exists as a method on functions,
// to prevent `this` from being overwritten, using closure

const sayHi = bind(bob.sayHi, bob);
sayHi.apply(spot); // "Bob, the person, says “Hi”."

这就是您的基于堆栈的调用无法按预期工作的原因,为什么 this 与您的预期不同,以及如何处理它。