JavaScript中的类是基于原型的继承机制的语法糖。本文将深入探讨类中公共实例字段与传统方法声明在内部机制上的差异。虽然类方法被挂载在构造函数的原型上,但公共实例字段并非如此。它们是直接绑定到每个类实例上的,其行为等同于在构造函数内部使用this关键字进行属性赋值,而非原型链的一部分。
JavaScript类与原型继承的本质
在
java
script中,
es6
的class语法提供了一种更清晰、更面向对象的方式来定义构造函数和它们相关的原型方法。然而,这仅仅是现有原型继承模式之上的一层抽象(或称“语法糖”)。
考虑一个典型的类定义,其中包含一个方法:
当我们创建一个Foo的实例时,barMethod可以通过原型链被访问到:
这表明barMethod是定义在Foo.prototype上的,所有Foo的实例都共享同一个barMethod函数。
公共实例字段的特殊性
然而,当我们在类中声明一个“公共实例字段”(Public Instance Field)时,其行为与原型方法截然不同。公共实例字段允许我们在类定义内部直接声明并初始化实例属性,而无需在constructor中显式使用this。
立即学习
“
Java免费学习笔记(深入)
”;
例如:
初学者可能会误以为barField也会像barMethod一样被添加到FooWithField.prototype上。但实际情况并非如此:
从上述结果可以看出,barField并不存在于FooWithField.prototype上。那么,它究竟在哪里呢?
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
公共实例字段的内部机制
公共实例字段的声明,实际上是JavaScript引擎在实例化类时,将该字段直接添加到每个新创建的实例对象上。其内部机制等价于在类的constructor(构造函数)中,使用this关键字对属性进行赋值。
也就是说,以下两种写法在功能上是等价的:
使用公共实例字段:
使用构造函数显式赋值:
无论哪种方式,barField都是实例自身的属性,而不是原型链上的属性。这意味着每个FooWithField或FooWithConstructor的实例都会拥有自己独立的barField副本。
总结与注意事项
原型方法 vs. 实例字段:
类方法(如 barMethod())
:定义在类的原型 (Foo.prototype) 上,所有实例共享同一个方法引用。
公共实例字段(如 barField = "value")
:直接定义在每个实例对象上,每个实例拥有自己的独立副本。
内部实现:
公共实例字段是构造函数中 this.propertyName = value 的语法糖。
访问方式:
实例字段只能通过实例对象(如 instance.barField)访问,无法通过类构造函数本身或其原型(Foo.barField 或 Foo.prototype.barField)直接访问。
适用场景:
当你需要为每个实例提供独立的、可变的状态时,公共实例字段非常有用。而当功能逻辑或共享行为需要被所有实例共享时,应使用原型方法。
理解公共实例字段与原型方法的这种区别,对于编写高效且可维护的JavaScript类至关至要。它有助于避免对属性查找机制的误解,并能更准确地设计类的结构和行为。
class Foo {
barMethod() {
console.log("This is a prototype method.");
}
}
// 实际上,这大致等同于:
// function Foo() {}
// Foo.prototype.barMethod = function() { console.log("This is a prototype method."); };const instance1 = new Foo();
instance1.barMethod(); // 输出: This is a prototype method.
console.log(Foo.prototype.barMethod === instance1.barMethod); // 输出: trueclass FooWithField {
barField = "Hello World";
}const instance2 = new FooWithField();
console.log(instance2.barField); // 输出: Hello World
console.log(FooWithField.prototype.barField); // 输出: undefinedclass FooWithField {
barField = "Hello World";
}class FooWithConstructor {
constructor() {
this.barField = "Hello World";
}
}const instA = new FooWithField();
const instB = new FooWithField();
console.log(instA.barField); // Hello World
console.log(instB.barField); // Hello World
instA.barField = "Modified A";
console.log(instA.barField); // Modified A
console.log(instB.barField); // Hello World (instB的barField不受影响)