JavaScript类和“ this”

时间:2018-08-03 14:35:16

标签: 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()

简明解释的最佳方法是什么?为什么在调用类中的另一个方法时需要使用“ 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()

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

我的一部分只是想说:“这就是JS类的工作方式。您必须'this'化事物。”

2 个答案:

答案 0 :(得分:4)

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

这个

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

const obj1 = {
  foo() { console.log(this); }
}
obj1.foo(); // "this" will reference "obj1"

这里没有什么奇怪的,this是对定义了obj1的对象的引用。


现在考虑一下如果我们使用函数foo并将其从对象中“删除”会发生什么。由于this是对调用函数的对象的引用,因此如果函数不属于对象,this应该是什么?

const obj1 = {
  foo() { console.log(this); }
}
const foo = obj1.foo;
foo(); // "this" will reference "window"

这是事情开始变得奇怪的原因,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"

此处应用相同的规则,因为该函数现在再次属于对象,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 

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

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

这两种继承方式(类和原型)在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()

答案 1 :(得分:1)

令人困惑,主要是因为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() 

函数obj.methodB不知道它属于class Aa。与类相关的唯一事情是其调用方式和调用方式确定this的值。因此this(和原型链)是将整个方案结合在一起的粘合剂。