OOP 即 面向对象编程 (Object Oriented Programming)毫无疑问是软件设计和发展中的一大进步。事实上,一些编程语言如 Java 、C++ 就是基于 OOP 的核心概念 class 开发出来。
在高校的 CS 相关专业中,无论教授什么编程语言,OOP的学习是绝对不会被落下的。
同时,OOP在业界中也的确被大量使用,尤其是的后端服务领域、桌面软件、移动APP开发等。
因此,OOP看起来在软件行业无处不在,在这种有点教条主义的氛围下,很多程序员甚至以为 class 是编程固有的概念 —— 然而并不是。优品拍怕
OOP 只是一套帮助开发者设计和编写软件的方法论,但并不代表它能解决所有领域的问题,也不是能在所有编程语言的任何场景下都适用。我们应避免陷入这种教条主义。
JavaScript中使用Class的坑
ES6 之后,JavaScript 也引入了 class 关键字用于声明一个类。但需要注意的是,这样声明出来的类其实在底层还是使用了 JavaScript 的函数 和 原型链 (来模拟类的行为)
看个例子:
class Person { constructor (name) { this.name = name } talk () { console.log(`${this.name} says hello`) }}
上面的代码在底层实现时,非常接近于
function Person (name) { this.name = name}Person.prototype.talk = function () { console.log(`${this.name} says hello`)}
这边可以注意到 talk 其实并不是一个Person类内部封装的方法,而只是一个常规的JavaScript函数,赋值到了Person的原型上而已。因此,talk 函数里的 this 对应的是调用时的上下文而不是定义时的上下文,这点跟 Java 和 C++ 的差别很大。
这种差异最明显的影响是在别的对象试图调用这个对象的talk时
const Grey = new Person('Grey')const mockDomButton = {} // 模拟一个DOM上的按钮对象mockDomButton.onClick = Grey.talk; // 绑定点击事件mockDomButton.onClick() // 输出的结果是 undefined says hello
上面这段模拟代码输出的结果并不是我们想要的。原因是 onClick 被调用时,其实是 talk 函数在执行,且talk 函数的this 指向的是 mockDomButton 而不是 Grey ,mockDomButton 并没有 name 属性于是 输出了 undefined says hello
这种“特殊”的表现让很多 JavaScript 新手感到头疼,尤其是那些从 Java 或者 C++ 背景过来的新手前端程序员。
解决这个问题的办法当然是有的,先介绍两个仍然使用 class 的方案