2、彻底搞懂 JavaScript 对象:面向对象 vs. 基于对象的真相

132 阅读3分钟

在前端世界里,关于 JavaScript 的一个老生常谈的问题是:
👉 它究竟是 面向对象语言,还是 基于对象语言

有人说 JS 不算正统 OOP,因为直到 ES6 才有 class
有人说 JS 是“基于对象”的,因为它允许运行时随意加属性。
可真相是:这两种说法都不完全对

今天我就带你揭开 JavaScript 对象系统的底层秘密。


1. 面向对象 vs. 基于对象

JavaScript 标准本身其实用了两个词:

  • 基于对象:语言和宿主的基础设施由对象来提供,JS 程序本质上就是一堆对象的集合。
  • 面向对象:对象是抽象世界的一种自然映射,JS 也提供了面向对象编程的能力。

换句话说:
JavaScript 既是基于对象的运行时系统,又是支持面向对象编程范式的语言。


2. 对象的三大特征

不论哪种语言,对象都绕不开三大特征:

  1. 唯一标识性
    即使两个对象长得一模一样,也绝不相等。

    var o1 = { a: 1 };
    var o2 = { a: 1 };
    console.log(o1 == o2); // false
    
  2. 状态
    对象在不同时间有不同状态,比如属性值会变化。

  3. 行为
    对象的状态能因行为(方法调用)而改变。

    var o = { 
      d: 1, 
      f() { console.log(this.d); } 
    };
    o.f(); // 1
    

3. JavaScript 对象的“独门秘籍”:动态性

和 Java、C++ 不同,JS 对象是 高度动态的
你可以在运行时随时给对象加属性:

var o = { a: 1 };
o.b = 2;
console.log(o.a, o.b); // 1 2

这让 JS 的对象系统极度灵活,同时也意味着:
👉 JS 可以在运行时模拟多数面向对象范式,而不仅仅是“类继承”。


4. 属性的两种形态

JS 属性远比你想象得复杂。分为两类:

  • 数据属性(有 valuewritableenumerableconfigurable

    var o = { a: 1 };
    Object.getOwnPropertyDescriptor(o, "a");
    // { value: 1, writable: true, enumerable: true, configurable: true }
    
  • 访问器属性(通过 getter/setter 实现)

    var o = { 
      get a() { return 1; } 
    };
    console.log(o.a); // 1
    

这种设计让 JS 对象既能像字典,又能像函数工厂,抽象力直接拉满。


5. 为什么有人说 JS 不是 OOP?

原因在于:JS 的对象系统与主流基于类的 OOP 差异太大。

  • Java 必须先定义类,再造对象;
  • JS 可以直接定义对象,并在运行时扩展它。

但正是这种“反常规”的设计,让 JS 更加灵活。ES6 的 class 只是语法糖,本质上依旧是动态对象+原型链。

所以:
JavaScript 绝对是 OOP 语言,只不过它的 OOP 更自由、更动态。


写在最后

理解 JS 对象的关键是放下对“类”的执念。

  • 对象 = 属性集合(键是字符串或 Symbol,值是数据属性或访问器属性)。
  • JS 对象的运行时模型,足以模拟任意 OOP 范式。
  • 灵活到爆炸,但也意味着容易“写出一坨屎山”。

互动问题
👉 你更喜欢 严格的基于类 OOP(如 Java),还是 动态灵活的 JS OOP
欢迎留言聊聊你的感受!