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'化事物。”
答案 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中是相同的。
因此,我们可以在原型实现中更清楚地看到,“类方法”实际上只是分配给函数原型的对象。
现在我们知道this
和classes / 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
(和原型链)是将整个方案结合在一起的粘合剂。