🧩 第十章 面向对象设计:拟人化和职责分配
📄 一句话概括

专栏说 JS【执行时不受类约束】——实测给实例挂 3 个属性、给类挂 1 个方法,兄弟实例只能拿到类上那个;类是模板,但不是牢笼。

📝 本节和前面几节的关系

10.8 讲完职责分配的收益,这篇专栏换个角度:如果类本身都能随时改,那些设计原则还成立吗?

一、JS 的类约束为什么松

JS 是原型链语言:对象直接从别的对象继承,没有编译期的类型检查。 所以类只是一个语法糖,运行时的对象结构可以随时变。 这正是专栏标题说的【执行时不受类约束】。

二、实测:Python 也能演示

给实例 a 挂 3 个属性(nick/extra/another)——b 拿不到。 给类加 1 个方法 say_bye——b 立刻能用。 类文件一个字都没改,但运行时的行为变了。

三、灵活换来什么、失去什么

换来:不用为了加个字段去改类定义,测试里造数据特别方便。 失去:谁都可能改你——第三方库给你挂个属性,你排查半天。 还失去:看代码看不出对象长什么样,得跑起来才知道。

四、那设计原则还成立吗

成立,而且更重要:正因为约束是软的,才要靠人守住。 比如【只暴露必要的方法】——在这种语言里,私有靠约定,一旦公开就真的全公开。 所以语言越灵活,设计越重要;灵活性不是免费的,账单由维护者付。

五、动手 Demo:执行时不受类约束的JavaScript

给一个实例挂三个属性,再给类挂一个方法。 看另一个实例能拿到什么、拿不到什么。

class Person(object):
    def __init__(self, name):
        self.name = name

a, b = Person("阿甲"), Person("阿乙")
a.nick, a.extra, a.another = "小甲", 1, 2      # 只挂在 a 上
Person.say_bye = lambda self: "再见 " + self.name   # 挂在类上

print(hasattr(b, "nick"), hasattr(b, "say_bye"))   # False True

实跑输出:

--------------------------------------------------------------------
执行时不受类约束的JavaScript
--------------------------------------------------------------------

  专栏说 JS【执行时不受类约束】。Python 其实也能演示这件事:实测给实例挂东西:

      实例 a 挂上的属性            3 个(nick/extra/another)
      类上后加的方法              1 个(say_bye)
      b 有没有 nick               False
      b 能不能 say_bye            True
      类的定义改过吗              False(原文件没动)

  语言           能随时加属性/方法吗     类必须在运行前定死吗
  ------------------------------------------------------------
  JavaScript     能                      不需要 class
  Python         能(本文实测)          不需要(可动态造)
  Java/C++      不能                    需要

  **实测:a 挂 3 个属性、类上加 1 个方法,b 只能拿到类上加的那个。**
  **这说明【类是模板,但不是牢笼】**——至少在这类语言里不是。
  **专栏的意思不是说 JS 更好**:**没有约束换来灵活,也换来【谁都可能改你】**。

实测:a 挂的 3 个属性 b 拿不到(False),类上加的方法 b 立刻能用(True)。 类文件一个字都没改,运行时的行为却变了——这就是【不受类约束】。 灵活性不是免费的:语言越松,设计越要靠人守住。

30 秒实验

  1. 在 Python 里给一个实例动态挂方法,看它能不能拿到 self。
  2. 想想你的项目里,如果谁都能给对象加字段,排查问题会难多少。

常见误区

  1. 以为动态挂属性是高级技巧就该多用。它让对象长什么样变得不可预测。
  2. 以为语言松就不需要设计。越松越靠人守。
自测三问(点开对答案) 1. JS 的类约束为什么松? —— 它是原型链语言,类只是语法糖,运行时对象结构可随时变。 2. 实测结果如何? —— 实例 a 挂的 3 个属性 b 拿不到,类上加的 say_bye 方法 b 立刻能用。 3. 灵活性的代价是什么? —— 谁都可能改你的对象、看代码看不出对象形态;语言越松设计越要靠人守。

相关笔记