换一种角度看Javascript的面向对象-行为委托

javascript是一门面向对象语言,这一点应该毫无疑问。不是有句话这么说的么,js中万物皆对象,就连函数的本质都是对象,因此js里函数也是一等公民。
虽然js是面向对象的语言,但是Js却没有类的概念,其继承方式也和基于类的面向对象语言有所不同,是基于原型链的继承。
但,很久以来,我们在尝试说明js的原型链的机制时,都是用“类”的概念去做类比,构造函数,实例,继承。就连最新的ES6都添加了class关键字,这让人们越来越迷糊,js到底存不存在类,它的原型到底本质和类有什么区别?

基于类和基于原型

面向对象语言可分为两类:基于类的面向对象,这类的代表有Java,还有一类是基于原型的面向对象,这类的代表有Javascript。
在基于类的面向对象语言中,对象(object)依靠类(class)类产生,由类构造而来。而继承的实现也是基于类。
而在基于原型的面向对象语言中,对象则是依靠构造器(constructor),利用原型(prototype)构造出来,所有的对象都离不开原型。

js的继承

面向对象的语言中,免不了的就是“继承”两个字。在Java中,继承指的是类与类之间的关系,子类继承父类,这样子类就可以拥有父类的一些方法和属性。
在js中,“继承”是通过原型实现的。很多人都这么说,网上能搜到的,也这么说。
那么,仔细想想,原型以及原型链讲的是对象与对象的关系,而继承,据我所知讲的是类与类之间的关系。
很多年以来,人们在解释js的原型链时,都是按照类的思路来,因此会造成很多不大不小的误解。

什么是原型,原型链,这里不做太细致的讨论。实在不记得,可以再回去翻翻书。

一直以来,我们写js代码时,都是按照类的思想来写,也试图按照类的思想来解释js中的原型,比如:

var Person = function Person(name){
  this.name = name;
}
Person.prototype.say = function say(){
  console.log('my name is ' + this.name);
}
var Student = function Student(name){
  Person.call(this,name);
  this.type = 'student';
}
Student.prototype = Object.create(Person.prototype);

var s1 = new Student('coolcao');
s1.say(); //my name is coolcao

我们使用类的概念,将Person,Student称作父类,子类,将s1称作实例对象。
s1是通过new调用Student实例化而来。
但这和基于类的面向对象有本质的区别,基于类的实例化是由复制而来,而基于原型的面向对象,则是通过原型产生。

我们来分析一下以上代码的原型图:

原型图

Person,Student分别是两个构造函数,他们的prototype分别指向两个原型对象,而Sutdent.prototype的[[Prototype]]指向Person.prototype,s1为Student的一个实例对象,其[[Prototype]]指向Sutdent.prototype对象,这样就形成了原型链:
s1 -> Student.prototype -> Person.prototype
所以从上图看,原型链也是对象与对象之间的关系。

从上面的代码中,看出js中原型链实现的继承,代码还是有点繁琐。幸好ES6中实现了class,extends关键字,因此上面代码如果用ES6编写,将会是如下:

class Person{
  constructor(name){
    this.name = name;
  }
  say(){
    console.log('my name is ' + this.name);
  }
}

class Student extends Person{
  constructor(name){
    super(name);
    this.type = 'student';
  }
}
var s1 = new Student('coolcao');
s1.say(); //my name is coolcao

ES6的代码更简洁,而且可读性更强。看上去和Java等基于类的面向对象更贴近了。但是,请记住,class,extends只是对原型的语法糖而已,js的内部实现机制,还是用原型链实现的。
基于上面的原因,越来越误导人们,使用基于类的思想去思考javascript的原型机制。
可是,在这里,我想说的是,js的原型机制,应该是用委托来思考更合理,而不是类。
为什么这么说呢,因为javascript的原型链,都是对象与对象之间的关系,对象与对象之间,更像委托,而不是父子。

行为委托

委托是说,我这里没有,但是你那里有,我就委托你帮我做这件事。
比如上面的原型图,对于对象s1而言,它有的仅仅是name和type两个属性,而没有say()方法,但最后却能调用say()成功,是因为,s1没有这个方法,但是它的原型链上,Person.prototype对象有say()方法,于是,没有这个方法没关系,我可以委托Person.prototype对象给做这这件事嘛。
所以,委托的本质,就是对象与对象之间的关键,这和原型链是一致的。
所以,如果我们用委托的思想来重新思考一下上面的代码,将构造函数去掉,只剩下原型对象呢:

var Person = {
  init:function(name){
    this.name = name;
  },
  say:function(){
    console.log('my name is ' + this.name);
  }
}

var Student = Object.create(Person);
Student.settup = function(name){
  this.init(name);
  this.type = 'student';
}
Student.sayHi = function(){
  this.say();
}
var s1 = Object.create(Student);
s1.settup('coolcao');
s1.sayHi();

这段代码简洁了许多,我们只是把对象关联起来,并不需要那些既复杂又令人困惑的模仿类的行为(构造函数、原型以及new)。
这里,Person,Student是两个对象,而非函数。Student的原型对象指向Person,而s1对象的原型指向Student,因此三者构成了原型链:s1 -> Student -> Person,这里没有了构造函数,没有了类的误导,同样也可以很好的工作。
而且原型链关系更简洁,就是上面原型链图,去掉了构造函数 ,将Person.prototype和Student.prototype替换为Person和Student两个对象。

原型图

对象Student和s1都是通过Object.create()创建,Student委托了Person,s1委托了Student。
因此,在这里,使用委托去理解javascript的原型链更符合常规,更清晰易懂。

小结

我们从委托的角度,理解了一下js的原型链,发现一切都变的那么明朗。但是,为什么这么些年来,大家都用类的角度去分析,然后模拟类和继承来实现复杂的js代码呢?
其实很简单,用基于类的思想去组织管理代码,维护性更好,也更符合大型系统的开发思维。虽然如此理解js的原型有些偏颇。
尤其ES6出了classextends两个关键字后,代码看起来更像类式面向对象编程语言。
但在理解上,把原型链理解为委托似乎更妥些。
仁者见仁,智者见智。

参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容