为什么函数看起来是对象?
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'}
) 是创建通用对象的快捷方式。因此,以这种方式创建的对象的 class 是 Object
。此外,以这种方式创建对象并不能为您提供使 new
对象具有相同行为的方法(这意味着在某种意义上它们将具有相同的 class)。
在某些语言中,例如 C++ 和 Java,classes 是语言的基本构建块。但在 javascript 中,它只是一个概念,基本上(非正式地)表示具有相同指定行为的任何对象。更正式地说,它是一个在其原型链中具有 class 原型的对象。什么是原型和原型链?好吧,每个*对象(甚至是那些使用对象字面量语法制作的对象)都有一个隐藏的原型** 属性。在对象中查找 属性 时,如果在对象本身中找不到它,它会在原型中查找 属性。如果那个原型对象没有那个 属性,它会去 "up the chain" 并检查原型的原型是否有 属性,并尽可能地继续这样做。
当您使用 class
语法时,您是在为 class 创建的每个对象的原型设置属性。因此,在您的示例中,您将函数 start
分配给每个 Clock
对象的原型。但是如果你把它分配给对象本身,那么它就不会使用原型。
有趣的是,classes 也是对象(它们可以有属性和方法)。
有关官方文档,请参见此处:
- https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS
- https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
*:您可以使用 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)
我正在努力学习 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'}
) 是创建通用对象的快捷方式。因此,以这种方式创建的对象的 class 是 Object
。此外,以这种方式创建对象并不能为您提供使 new
对象具有相同行为的方法(这意味着在某种意义上它们将具有相同的 class)。
在某些语言中,例如 C++ 和 Java,classes 是语言的基本构建块。但在 javascript 中,它只是一个概念,基本上(非正式地)表示具有相同指定行为的任何对象。更正式地说,它是一个在其原型链中具有 class 原型的对象。什么是原型和原型链?好吧,每个*对象(甚至是那些使用对象字面量语法制作的对象)都有一个隐藏的原型** 属性。在对象中查找 属性 时,如果在对象本身中找不到它,它会在原型中查找 属性。如果那个原型对象没有那个 属性,它会去 "up the chain" 并检查原型的原型是否有 属性,并尽可能地继续这样做。
当您使用 class
语法时,您是在为 class 创建的每个对象的原型设置属性。因此,在您的示例中,您将函数 start
分配给每个 Clock
对象的原型。但是如果你把它分配给对象本身,那么它就不会使用原型。
有趣的是,classes 也是对象(它们可以有属性和方法)。
有关官方文档,请参见此处:
- https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS
- https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
*:您可以使用 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)