前言
面向对象有三大特性:封装继承多态。
不过,js和java的封装继承多态是不一样的,我和从事java开发的朋友有过一次对话(抬杠 !--)。
我说:javascript也是面向对象语言,
他说:不对吧,js不是面向对象吧。
我说:是的,官方说的就是面向对象语言。
他说:那你知道三大特性吗?
我说:封装继承多态。
然后他说:那你说一下那都是啥意思。
我说:构造函数...原型对象...原型链....
他说:你说的这都是啥呀,构造函数和原型链是啥,听都没听过,面向对象使用类,你那js是假的面向对象吧。
我说:js后面用的是类,但在类之前用的是原型链。其实,类也是原型链的语法糖,不归根到底还是原型链吗。
因为我不懂java,他不懂js。不过js确实和java在面向对象的实现上是不一致的,js在class出来之前,是通过原型链的特性实现了面向对象编程。
家有儿女
今天这篇文章,我用《家有儿女》来通俗的说一下js中原型链是怎么完成封装继承多态的,class相关的这篇文章不提。
构造函数构建家庭成员
function Family(name, gender, token) {
//姓名
this.name = name
//性别
this.gender = gender
//身份
this.token = token
//家里有好多本书
this.bookList = ['资治通鉴', '百家菜谱', '七龙珠', '三体']
//家里的厨房可以用来做饭
this.useChuFang = function (type, name) {
console.log(`我用${type}做出了我想吃的${name}`)
}
//使用电脑
this.computer = function (type) {
//电脑有显卡,键盘,内存条,处理器等
let xianka = () => { }
let jianpan = () => { }
let chuliqi = () => { }
let write = () => {
console.log(`我是${this.name},我会用电脑写小说`)
}
let playGame = () => {
console.log(`我是${this.name},我会用电脑打游戏`)
}
switch (type) {
case "write":
write()
break
case "playGame":
playGame()
break
default:
console.log(`我是${this.name}抱歉,我不懂电脑的构造和具体原理`)
}
}
//使用化妆品
this.useHuaZhuangPin = function(){
if (this.gender === 'woman') {
console.log(this.name,'你是女性,可以使用这些化妆品')
} else {
console.log(this.name,'男人就别作妖了')
}
}
//私有变量,10瓶饮料
drinks = 10
//闭包返回函数
let fn = (num,name, drinks) => {
if(drinks>-1){
console.log(`我是${name},我拿了${num}瓶饮料,还剩${drinks}瓶饮料`)
}else{
console.log(`我是${name},我想拿饮料,发现没了`)
}
}
//闭包封装私有变量,家里的饮料
this.drinkFun = (num,name) => {
drinks = drinks - num
return fn(num,name, drinks)
}
//家庭有一笔1百万的存折
bankBook = 1000000
}
let XiaDongHai = new Family('夏东海', 'man', '父亲')
let XiaoXue = new Family('小雪', 'woman', '女儿')
let LiuMei = new Family('刘梅', 'woman', '母亲')
let LiuXing = new Family('流星', 'man', '儿子')
console.log(XiaDongHai, '夏东海')
console.log(XiaoXue, '小雪')
console.log(LiuMei, '刘梅')
console.log(LiuXing, '流星')
测试
结论:
一个构造函数就像是一个家庭,这个家庭有一些资产,是大家所共有的,每个家庭成员都可以去使用和调配这些资产,每个家庭成员都有原型链定义的方法属性和自己独有的属性。
封装
//1.构造函数封装公共方法
//夏东海用电脑写文章
XiaDongHai.computer('write')
//流星用电脑打游戏
LiuXing.computer('playGame')
//你问他们电脑的显卡原理是什么
XiaDongHai.computer('xiaka')
//他们虽然不懂电脑是怎么运行的,但是他们可以用电脑做到自己想做的事。
//2.闭包封装私有变量
//全家喝饮料
XiaDongHai.drinkFun(3,'夏东海')
LiuMei.drinkFun(2,'刘梅')
LiuXing.drinkFun(4,'流星')
XiaoXue.drinkFun(1,'小雪')
XiaDongHai.drinkFun(1,'夏东海')
测试
结论
构造函数内部可以封装公共属性方法,闭包可以封装私有变量,都可以让所有的实例对象去操作这些属性方法,并且无需知道这些属性方法是内部是如何构造的。
公共资产只要你是这个家庭成员,你就可以用它。你可以不用知道这个东西的构造原理是什么,你只需要会使用它。
你不需要会包饺子,你只需要会吃饺子
继承
//给构造函数,也就是全家添加100万元的家庭资产和一辆奔驰轿车
Family.prototype.bankBook = 1000000
Family.prototype.car = '奔驰'
//接下来我就用代码来清晰的展示面向对象的这些特征
//构建家庭成员,其实构造函数的本质作用,就是用来批量创建一些拥有相同属性或者方法的对象,不让代
码大量冗余重复。
let XiaDongHai = new Family('夏东海', 'man', '父亲')
let XiaoXue = new Family('小雪', 'woman', '女儿')
let LiuMei = new Family('刘梅', 'woman', '母亲')
let LiuXing = new Family('流星', 'man', '儿子')
测试
//夏东海将原来的奔驰车卖掉了,换了一辆新宝马车,花了10万元
Family.prototype.car = '宝马'
console.log(Family.prototype.bankBook,'???')
Family.prototype.bankBook = Family.prototype.bankBook - 100000
console.log(XiaDongHai.car,XiaDongHai.bankBook,'夏东海')
console.log(LiuMei.car,LiuMei.bankBook,'刘梅')
结论
原型链可以添加,重写一些公共属性,所有实例对象继承原型对象的属性都会受到影响。
夏东海花了家里的公共财产,所有家庭成员拥有的共同财产就会减少。但是买了新车,以后所有成员就都能坐上宝马新车了。
同甘共苦
多态
//夏东海和刘梅做饭
LiuMei.useChuFang('鸡块','大盘鸡')
XiaDongHai.useChuFang('方便面','泡面')
//流星和小雪化妆
LiuXing.useHuaZhuangPin()
XiaoXue.useHuaZhuangPin()
测试
结论
不同的方法被不同的对象调用,结果会多样性。
龙生九子各不同
结束语
其实我说的也不是很详尽,只是想变着法的想让看客明白原型链的具体作用和实际运用方法,熟练理解原型链是js开发者最重要的技能之一,现在你可以想一下vue是不是也是使用原型链的特性去让各组件操作原型上的实例方法呢。
更多继承方法请看:
js中继承的方法-CSDN博客
感觉有用的给个赞吧!