自学的视频有点旧,想问下目前最流行的面向对象编写方式是否是构造函数+原型方式,就是原型里面写对象的方法,构造函数里面写对象的属性?如代码。
function createPerson(name,qq){ //构造函数里面写属性
this.name = name;
this.qq = qq;
}
createPerson.prototype.showName = function(){ //原型里面写方法
alert("我的名字" + this.name);
}
createPerson.prototype.showQQ = function(){
alert("我的QQ" + this.qq);
}
var obj = new createPerson("mike","123456");
obj.showName();
obj.showQQ();
别拿基于类的 OO 语言的观念来看待 JavaScript,因为它是基于原型的
有太多的书/教程“强行”把 JavaScript 往类型式 OO 语言上靠,ES2015 整出个
Class
语法糖也是为了满足这种不知所谓的“同比心”(后记:对,我这句话说的太激进了些,我承认)。可是 OO 是面向对象,不是面向类呀!!!所以,你告诉我:在你的应用里
Person
重到什么程度才需要你创建一个“类”出来?你要这个“类”的什么好处?继承?封装?多态?有多少客户端应用程序的代码是真的需要这些类型语言强调的特色的?用不到的话为啥非要创造“类”?当然,如果你是 generic 库/框架的作者,那么你可以无视上面那段话(如果你是的话,你当然明白我的意思)。
流行的方式?没有/不知道,针对具体的应用规模选择你的“武器”吧,真正上规模的应用有多少人能做到从底层架构开始全部自己封装的?有必要写这样的基础类吗?即使你要做和后端类似的 ORM,
Person
这样的粒度又未免太细了一些,你要写的也得是Adapter
Serializer
Mapper
这样的东西呀。我有一个“人”的对象:
我要一个小明和一个小红:
80% 的时间,我们都在写着这样的代码,要那个貌似“类”的构造器有毛用处?(知道怎么用的不用跳出来喊,我也知道)
请先掌握 面向对象 ,然后再去分辨 基于类的 OO / 基于原型的 OO 它们之间的异同,不要受 Java 语言那种教学习惯的误导把本末倒置了。
我一个同事问了我一个问题:
我认为这个问题问得很具有代表性,充分体现了那些惯常的 OO 教学法是如何把人给教傻了的……
首先,啥叫基于原型?
Object.create(prototype)
,如你所见,这个方法创造出的对象就是扩展了你传入的prototype
的,也就是原型链。如果你用构造器模式,你会弄出一个Person.prototype
这样的对象,本质上它和我直接创建的person
对象没有什么区别(区别当然有,但是在这里不重要)。OO 的本质,不是继承/封装/多态,而是 (把)一切都(看作)是对象!,即使它真的不是对象(有些不完全 OO 语言会有一些原始类型不太符合它自身对于
Object
的定义,比如 JavaScript 里就有这样的东东,我们叫它们原生类型),你也要把它看作对象。因此
var person = {}
和Person.prototype
本质上没啥区别,因为归根结底它们都是一个对象而已,而Object.create
就是要你给一个对象做原型,然后给你返回一个对象,它最近的原型链就是你传入的那个对象。看看这个:这就是上面基于
person
创造出的小明和小红,greeting
方法确实是通过原型引用的,绝不会重复定义。这个简单的例子揭示了基于原型的真正内涵,Constructor.prototype
固然也是一种实现方式,但绝非必须要这么做(对比 Java,类是你构造对象的唯一途径)。如果你把类看作是实力对象的“模版”,那么这个“模版”在 JavaScript 里就是原型,而原型就是一个单纯的对象,它不是类,也不需要变成“类”。
其次,操作属性时是否方便?
如果你定义一个构造器,唯一的方便之处在于构造器本身是一个函数,调用函数的时候可以传参,所以可以“看似很方便的”初始化实例对象的默认属性。然而这种方便是有代价的!
你需要一个对象来接受这些属性,也就是
this
;可是动态语言的this
是运行时决定的,你很难确保它是你想要的对象——所以就有了new
操作符,它干了啥我回答过好几次就不说了,搜索/MDN……而new
本身又带来一些问题(去搜),所以才搞出了很多不用new
但是保留构造器的“奇技淫巧”。对应到具体的项目中你需要问问自己:需要吗?值得吗?动态类型的特点就是不需要静态检查,放在这里就意味着:每一个实例对象不需要严格遵守模版的规则,不是说你构造器里预设了三个属性,那么我的实例对象就必须有这三个属性的。那么问题来了,如果属性没有或者不够怎么办?好吧,检查传参/使用对象构造传参等等技巧又来了……当然了你懂这些技巧不是坏事,但是懂了就一定需要这么做吗?值得吗?
就算你真的想初始化方便点,也应该构想更上一层的抽象,比如说一个 Adapter 专门用来处理和 API 的对接(这是绝大部分前端项目的数据来源),然后由它去生成实例对象,这时候实例对象是什么类型并不重要(是不是
Person
在大部分时候我并不关心,真要关心也不必自建构造器)。前端开发的重点是在 UI 编程上,我经常对后端转前端/实习生强调这个观念——不是说数据结构/算法等等不重要,而是比起这些东西,作为前端工程师你首先得打好 UI 编程的基础,然后再去深入学习和研究这些东西在前端上的实践。对于初学者,别太去纠结“如果不搞个‘类’会不会逼格不够高”这类的问题,反之我更加建议你多用用那些开源的库,去体会它们的接口调用和层次处理,然后再去理解它们在底层为你做的封装,这样的学习多了之后你自然会明白什么时候我需要什么东西。
用动机去驱动解决方案,而不是先预设解决方案来对应一切动机。 前者是 OO,后者则是基于 xxx 的对 OO 系统的实现。