【问题标题】:javascript scope and everything about 'this'javascript 范围和关于 'this' 的一切
【发布时间】:2018-03-11 13:08:01
【问题描述】:

我正在尝试深入了解 'this' 在 javascript 中的工作原理。 到目前为止,我对这个的了解是,

  1. 每个函数都有属性,每当函数执行时,它都会重新定义 this 属性。

  2. this是指调用函数的对象(包括浏览器中的window对象)。

  3. this 指的是对象的范围(定义对象的地方)而不是指对象本身,如果在定义函数时使用箭头语法,因为箭头函数没有新定义自己的this

以下示例有助于理解 this

的行为

class Example {

  constructor() {
    this.name = 'John';
  }

  method1() { //case1 : Closure
    console.log(this.name);

    function method2() {
      console.log(this.name);
    }

    method2();
  }
}

const a = new Example()
a.method1();

function testing(callback) {
  return callback();
}

class Example2 {

  constructor() {
    this.name = 'John';
  }

  method1() { //case2: callback
    console.log(this.name);

    testing(function() {
      console.log(this.name);
    })
  }
}

const b = new Example2()
b.method1();

function testing(callback) {
  return callback();
}

class Example3 {

  constructor() {
    this.name = 'John';
  }

  method1() { //case3: arrow syntax callback
    console.log(this.name);

    testing(() => {
      console.log(this.name);
    })
  }
}

const c = new Example3()
c.method1(); // logs 'John'
// logs 'John'

function testing(callback) {
  return callback();
}

class Example4 {

  constructor() {
    this.name = 'John';
  }

  method1() { // case4: calling method as callback
    console.log(this.name);
  }

  render() {
    testing(this.method1)

  }
}

const d = new Example4()
d.render()

function testing(callback) {
  return callback();
}

class Example5 {

  constructor() {
    this.name = 'John';
    this.method1 = this.method1.bind(this);
  }

  method1() { //case5: bind method && calling method as callback 
    console.log(this.name);
  }

  render() {
    testing(this.method1)

  }
}

const d = new Example5()
d.render()

我想知道上述情况有何不同,以及 this 在每个内部函数和回调中指的是什么。你能解释一下吗?谢谢你:)

【问题讨论】:

标签: callback closures this bind arrow-functions


【解决方案1】:

由于深入的精确解释可能相当冗长而乏味,这里有一个exceptional article by kangax 完美地阐述了它。

为了以防万一,如果你需要一个简短的超浓缩版本,我的简短和大概的版本:

#

当您调用函数时,this 由特定的 base value 确定,它通常指向 . 左侧的任何内容 在MemberExpression 所以在x.y() this === xx.y.z() this === x.y

如果一个简单的CallExpression 没有.,就说x(), 基值被隐式推断为指向undefined,在非严格模式下转换为全局window,在严格模式下保持不变。

这是一个通用的心智模型,它应该涵盖 99% 的所有日常问题,包括正确绘制 this 上下文。

现在,到实际案例:

案例 1:

a.method1(); 调用有一个基值a,所以其主体内部的this 指向a,所以这里没有意外。 method2 具有隐式基值 undefined.method2,因此您拥有明确声明的 TypeError

案例 2:

function testing(callback) {
  return callback();
}

callback() 使用隐式 baseValue undefined 调用,即undefined.callback(), 并且由于传递的函数是在class

中声明的
testing(function() {
  console.log(this.name);
})

触发代码执行的严格模式,这就是为什么undefined不会再次转换为全局window,因此我们会遇到与以前相同的错误。

案例 3:

箭头函数

testing(() => {
   console.log(this.name);
})

从封闭范围内的this 创建一个硬绑定, 基本上在引擎盖下它与写作相同:

var _this = this;
testing((function() {
   console.log(_this.name);
});

这就是为什么你会得到与this相同的对象

案例 4:

好的,这个很有趣,需要更多的机制解释。

所以当你通过this.method in:

render() {
  testing(this.method1)
}
  • 你实际传递的不是引用this.method,而是这个引用指向的实际底层函数对象值,所以 当它被执行时,它的 this 总是指向 undefinedhere look,所以它几乎是“一成不变的”。

当然是的,因为 this.method1 再次在严格的上下文中声明,这要归功于封闭 es6 classundefined 仍然是 undefined 而不转换为全局 window

案例 5:

与箭头功能相同的机制。 Bind 创建一个包装函数,它保存缓存的this 值,不能用.call.apply 覆盖,与=> 函数中相同。

希望这能澄清一点。

【讨论】:

    猜你喜欢
    • 2011-04-16
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多