JavaScript 类和“this”

Iva*_*own 4 javascript

class Aa {
    methodA() {
        console.log('welcome to method a')
    }
    methodB() {
        console.log('welcome to method b')
        //   methodA() // Fails!! Uncaught ReferenceError: methodA is not defined
        this.methodA() // Works because of this.
    }
}

let myclass = new Aa()
myclass.methodB()
Run Code Online (Sandbox Code Playgroud)

简洁地解释为什么在调用您已经使用的类的另一个方法时需要使用“this”的最佳方法是什么?

直觉可能会说,好吧,如果 JS 知道我正在使用一个类的方法,那么它就知道那个类......因为我正在使用它的方法......那么为什么它不能找到另一个方法没有我告诉它的同一个类......是的'这个'同一个地方!

相比之下,函数可以毫无问题地做到这一点:

function a() {
    console.log('welcome to function a')
}
function b() {
    console.log('welcome to function b')
    a() // works without any sort of 'scope help'
}
b()
Run Code Online (Sandbox Code Playgroud)

我希望能够解释它,而不会让人们分心,需要知道它的最深层原因。如果可以的话,哈!

我的一部分只是想说,“这就是 JS 类的工作方式。你必须'这个' - 化事情。”

Oli*_*n04 8

为了理解为什么我们需要this在 Javascript 类中显式引用,我们首先需要了解this引用在普通函数中指向什么。

这个

在 Javascript 中,this关键字始终是对调用函数的对象的引用。
考虑以下:

const obj1 = {
  foo() { console.log(this); }
}
obj1.foo(); // "this" will reference "obj1"
Run Code Online (Sandbox Code Playgroud)

这里没什么奇怪的,this就是对定义它的对象的引用obj1


现在想想如果我们获取函数foo并将其从对象中“删除”会发生什么。既然this是对调用该函数的对象的引用,那么this如果该函数不属于某个对象呢?

const obj1 = {
  foo() { console.log(this); }
}
const foo = obj1.foo;
foo(); // "this" will reference "window"
Run Code Online (Sandbox Code Playgroud)

这被人开始变得奇怪了,this实际上是对global对象的引用。这是因为 Javascript 中的一切都是对象,甚至是文件的根级别。在浏览器中,这个全局对象称为window对象。


现在考虑如果我们将方法重新附加到另一个对象会发生什么?

const obj1 = {
  foo() { console.log(this); }
}
const foo = obj1.foo;
const obj2 = {};
obj2.foo = foo;
obj2.foo(); // "this" will reference "obj2"
Run Code Online (Sandbox Code Playgroud)

此处适用相同的规则,因为函数现在再次属于this引用指向的对象obj2

班级

所有 Javascript 中的第一个实际上没有类。js 类只是以不同的方式编写原型。

让我们从编写一个简单的类开始。

class Foo {
  constructor() { console.log("I'm a Class constructor") }
  log() { console.log("I'm a Class method") }
}

const obj1 = new Foo(); // I'm a Class constructor
obj1.log(); // I'm a Class method 
Run Code Online (Sandbox Code Playgroud)

现在让我们编写与原型相同的“类”。

function Bar() {
  console.log("I'm a Prototype constructor")
}
Bar.prototype = { 
  log() {
    console.log("I'm a Prototype method")
  }
}

const obj2 = new Bar(); // I'm a Prototype constructor
obj2.log(); // I'm a Prototype method
Run Code Online (Sandbox Code Playgroud)

这两种编写继承(类和原型)的方式在 Javascript 中是一回事。

因此,我们可以在原型实现中更清楚地看到,“类方法”实际上只是一个分配给函数原型的对象。


现在我们知道了thisclasses / prototypes我们可以看到类方法实际上只是一个对象上的函数,它this指的是调用该函数的对象。所以如果我们想在同一个对象上引用另一个函数,我们应该通过引用来引用它this

class Aa {
    methodA() {
        console.log('welcome to method a')
    }
    methodB() {
        console.log('welcome to method b')
        this.methodA()
    }
}

const myclass = new Aa()
myclass.methodB()
Run Code Online (Sandbox Code Playgroud)

  • 我从来没有真正理解`this`在Javascript中是如何工作的,直到我阅读了你的回答中的第二段:**在Javascript中,`this`关键字总是对调用该函数的对象的引用。**我从来没有想过太简单了。+1! (6认同)

Mar*_*yer 4

之所以令人困惑,主要因为 Javascript 长期以来一直试图将原型的方钉装入类的圆孔中。很多在传统面向对象语言中有意义的事情只会导致 JavaScript 中的混乱。

你的(非常合理的)直觉在这里偏离了轨道:

直觉可能会说,如果 JS 知道我正在使用类的方法,那么它就知道该类......因为我正在使用它的方法

methodA()并且methodA()只是函数。他们不知道自己的定义在哪里。他们所知道的是他们是如何被称呼的。 this是将函数的调用方式与类的其余部分联系起来的关键。考虑这个例子:

class Aa {
  methodA() {console.log('welcome to method a')}
  methodB() {
    console.log('welcome to method b')  
    this.methodA() // Works because of this.
  }
}

let obj = {
  methodA() { console.log("welcome to imposter A")}
}

let myclass = new Aa()

obj.methodB = myclass.methodB // take a reference to methodB and add it a different obj

console.log("Same?",obj.methodB === myclass.methodB) 
// identical function but it has no idea
// it "belongs" to myclass. Called from a different context
// it acts like a normal function (because it is)
obj.methodB() 
Run Code Online (Sandbox Code Playgroud)

该函数obj.methodB知道它属于class Aa. 它与类的唯一联系是它的调用方式,而它的调用方式决定了 的值this。所以this(和原型链)是将整个方案粘合在一起的粘合剂。