JavaScript类的几种经典写法与原理详解

沈知远
沈知远
发布时间:2026-10-14| 5人浏览过
原创

JavaScript早期并未引入"类"这一原生概念,而是通过构造函数和原型对象来模拟面向对象的特性。本文将深入解析几种经典的类定义写法,包括构造函数法、原型方式、组合模式以及基于对象字面量的替代方案,剖析其在内存占用、方法共享及实例化灵活性上的差异。

核心原理:原型是类的基石

在JavaScript中,类的所有实例对象都从同一个原型对象上继承属性,因此原型对象是构建"类"的核心。类是对对象的抽象,不占用内存;而对象是具体的实例,占用存储空间。早期的JS开发多为面向过程或简单函数编写,随着需求复杂化,逐渐引入了模仿其他语言(如Java)的类式编程思想。

方法一:构造函数法

这是最直观的模拟类的方式,通过在构造函数内部使用 this 关键字定义属性和方法。

<script>
  // Person类:定义一个人,有name属性和getName方法
  function Person(name){
    this.name = name;
    this.getName = function(){
      return this.name;
    }
  }

  // 实例化几个对象
  var p1 = new Person("trigkit4");
  var p2 = new Person("mike");

  console.log(p1 instanceof Person); // true
  console.log(p2 instanceof Person); // true
</script>

分析:

  • 优点: 支持传入参数构造不同的对象实例,灵活性高。
  • 缺点: 每次创建新实例时,都会重新生成一次 getName 方法。对于大量实例而言,这会造成不必要的内存浪费,因为每个实例的方法地址都是独立的。

为了解决方法重复创建的问题,可以将方法提取为外部函数,使所有实例共享同一方法引用:

<script>
  // 外部公共函数
  function getName() {
    return this.name;
  }

  function Person(name){
    this.name = name;
    this.getName = getName;
  }
</script>

方法二:原型方式

这种方式将属性挂在原型对象 prototype 上,利用原型链实现共享。

<script>
  function Person(){};
  
  // 类的属性和方法都放在prototype上
  Person.prototype.name = "trigkit4";
  Person.prototype.getName = function(){
    return " I'm " + this.name;
  }

  var p1 = new Person();
  var p2 = new Person();
  
  console.log(p1.name);       // trigkit4
  console.log(p2.getName());  // I'm trigkit4
</script>

分析:

  • 优点: 所有对象实例共享 getName 方法和属性,极大地节省了内存。
  • 缺点: 无法通过构造函数参数动态初始化属性(例如每个用户有不同的名字),因为属性被固定在了原型上。

方法三:构造函数 + 原型方式(组合模式)

综合上述两种方法的优点:使用构造函数定义实例属性(字段),使用原型定义方法。

<script>
  function Person(name){
    // 实例属性,每个实例拥有独立副本
    this.name = name;
  }

  // 原型方法,所有实例共享
  Person.prototype.getName = function(){
    return " I'm " + this.name;
  }
</script>

这种写法既允许构造不同属性的对象,又实现了方法的内存共享。为了让代码结构更紧凑,有时会将原型赋值写在构造函数内部:

<script>
  function Person(name){
    this.name = name;
    // 注意:这里的写法虽然能运行,但每次new都会重新定义原型方法,失去共享意义,仅用于演示位置紧凑性
    // 实际开发中建议保持分离或使用Object.defineProperty等方式优化
    if (!Person.prototype._init) { 
        Person.prototype.getName = function(){
            // 使用闭包捕获局部变量name,或者直接用this.name
            return this.name; 
        };
        Person.prototype._init = true;
    }
  }

  var p1 = new Person('trigkit4');
  console.log(p1.getName()); // trigkit4
</script>

方法四:Object.create() 映射模式

在ES5中,Object.create() 提供了一种基于原型的对象创建方式。此时,"类"表现为一个普通对象模板。

// 定义对象模板(类)
var Person = {
    name : "trigkit4",
    age : 21,
    run: function(){
      alert("I like running");
    }
};

// 直接创建实例,无需new
var p1 = Object.create(Person);
alert(p1.age);     // 21
p1.run();          // I like running

局限: 这种方法简洁直观,但无法实现私有属性/方法,且实例间若修改原型上的引用类型数据容易产生冲突,对"类"的模拟不如函数方式全面。

方法五:createNew() 工厂模式

通过对象内部定义一个静态方法 createNew 来负责实例化,不涉及 this 和 prototype 的显式操作。

<script>
  var Person = {
    createNew : function () {
      var person = {};
      person.name = "trigkit4";
      person.run = function(){
        alert("I like running");
      };
      return person;
    }
  };
</script>

使用时调用:var p1 = Person.createNew();。这种写法类似于对象字面量,适合简单的对象模拟,但缺乏真正的继承链支持。

总结

JavaScript中的"类"本质上是通过函数和原型链实现的。在现代开发中,ES6引入了 class 关键字,其底层依然遵循上述原型继承逻辑,但语法更为清晰。理解构造函数、原型及 Object.create 等早期写法,有助于深入掌握JS的对象系统。

以上就是JavaScript类的几种经典写法与原理详解的详细内容,更多关于JavaScript类和面向对象编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。