为什么函数看起来是对象?

Why do functions seem to be objects?

我正在努力学习 JS/ES,但对 classes 和对象有点困惑。

下面的两个代码片段做的完全一样,但最后一个显然使用了 class。但是第一个用的是什么?我还以为一个class执行的时候变成了一个对象?

我原以为 clock 是一个函数,但它显然可以用作对象。这是为什么?

为什么有人会想要使用 class 方式,当第一种方式更短时?

var clock = {
  start() {
    setInterval(() => console.log(Date()), 1000) 
  }
}
clock.start()

class Clock {
  start() {
    setInterval(() => console.log(Date()), 1000)
  }
}
const c = new Clock
c.start()

类 是对象的模板。它们描述了一堆对象的行为方式。在 javascript 中,new Clock() 是如何获得 class [=12= 的新 object ].

对象文字语法 ({foo: 'bar'}) 是创建通用对象的快捷方式。因此,以这种方式创建的对象的 classObject。此外,以这种方式创建对象并不能为您提供使 new 对象具有相同行为的方法(这意味着在某种意义上它们将具有相同的 class)。

在某些语言中,例如 C++ 和 Java,classes 是语言的基本构建块。但在 javascript 中,它只是一个概念,基本上(非正式地)表示具有相同指定行为的任何对象。更正式地说,它是一个在其原型链中具有 class 原型的对象。什么是原型和原型链?好吧,每个*对象(甚至是那些使用对象字面量语法制作的对象)都有一个隐藏的原型** 属性。在对象中查找 属性 时,如果在对象本身中找不到它,它会在原型中查找 属性。如果那个原型对象没有那个 属性,它会去 "up the chain" 并检查原型的原型是否有 属性,并尽可能地继续这样做。

当您使用 class 语法时,您是在为 class 创建的每个对象的原型设置属性。因此,在您的示例中,您将函数 start 分配给每个 Clock 对象的原型。但是如果你把它分配给对象本身,那么它就不会使用原型。

有趣的是,classes 也是对象(它们可以有属性和方法)。

有关官方文档,请参见此处:

*:您可以使用 Object.create(null) 创建没有原型的对象,但这种情况很少见。这样做的好处是您不会意外访问原型的属性,因为有 none.

**:您有时可以使用已弃用的 __poto__ 属性 访问原型。首选的新方法是 Object.getPrototypeOf(object)

以下是您可以探索的一些示例:

const clockByLiteral = { start(){/* do something */} }
function startClock () { /* do something */}
class Clock {
  start() { /* do something */}
}

const clock1 = new Clock()
const clock2 = new Clock()

function getClassName(object){
  return object.constructor.name
}
console.log('"class" of clockByLiteral:', getClassName(clockByLiteral))
console.log('"class" of clockByLiteral.start:', getClassName(clockByLiteral.start))
console.log('"class" of startClock:', getClassName(startClock))
console.log('"class" of Clock class:', getClassName(Clock))
console.log('"class" of clock1:', getClassName(clock1))
console.log('"class" of clock2:', getClassName(clock2))
console.log('is the constructor of clock1 Clock?:', clock1.constructor === Clock, "(meaning that classes and constructors are the same objects, and are functions also")
console.log('is the prototype of clock1 Clock.prototype?:', Object.getPrototypeOf(clock1) === Clock.prototype)


console.log('is clock1 the same object as clock2?:', clock1 === clock2)
console.log('is clock1.start the same as clock2.start?:', clock1.start === clock2.start)
console.log('is clock1.start the same as Clock.prototype.start?:', clock1.start === Clock.prototype.start)

console.log('is clock1 an "instance" of Clock?:', clock1 instanceof Clock)
console.log('is clock1 an "instance" of Object?:', clock1 instanceof Object)
console.log('is clock1 an "instance" of Function?:', clock1 instanceof Function)
console.log('is Clock an "instance" of Function?:', Clock instanceof Function)
console.log('is startClock an "instance" of Function?:', Clock instanceof Function)
console.log('is startClock an "instance" of Object?:', Clock instanceof Object)