Prototype - 不一樣的 Class

我第一次接觸面向?qū)ο髸r(shí)屯伞,使用的是 Python螟炫,運(yùn)用 def __init__(self, *args): 這種 magic method 來(lái)完成自身參數(shù)的初始化璧疗。 JS 當(dāng)中也有類似的構(gòu)造器 constructor 肴甸。

我先用 ES6 中新引入的 class 語(yǔ)法來(lái)定義一個(gè)類相嵌,因?yàn)檫@樣容易理解屎暇。

class Student {
  constructor(name) {
    this.name = name;
  }
  
  hello() {
    return 'Hello, ' + this.name + '!';
  }
}

再定義一個(gè)類來(lái)繼承

class PrimaryStudent extends Student {
  constructor(name, grade) {
    super(name); // 調(diào)用父類的構(gòu)造函數(shù)
    this.grade = grade;
  }
  
  myGrade() {
    return 'I am at grade ' + this.grade;
  }
}

看似與 Python 極為相似承桥,難怪我直接用 React 寫應(yīng)用的時(shí)候并沒(méi)有發(fā)現(xiàn)不對(duì)。這種新的語(yǔ)法簡(jiǎn)化了 JS 原本復(fù)雜的原型 (prototype) 繼承根悼,也讓直接了解新語(yǔ)法的我忽略了它的本質(zhì)及特性凶异。

(為了學(xué)習(xí))回歸原本的面貌

function Student(name) {
  this.name = name;
}

Student.prototype.hello = function() {
  return 'Hello, ' + this.name + '!';
}

var kitty = new Student('kitty');
var daisy = new Student('daisy');

可以觀察到我們并不在 Student 中直接寫 hello 函數(shù)蜀撑,而是寫在了它的 prototype 中。只要我們給 prototype 定義了函數(shù)剩彬,那么 Student 生成的對(duì)象就都可以調(diào)用這個(gè)函數(shù)酷麦,省去每個(gè)對(duì)象再獨(dú)自生成函數(shù)的操作。

我們把 Student.prototype 想象成一根樹(shù)枝喉恋,kitty 和 daisy 就是生出的綠葉了沃饶,它們共用樹(shù)枝上的器官,不必自己再生出相同的器官來(lái)消耗資源轻黑。此時(shí) kitty 和 daisy 的原型指向 Student.prototype糊肤。

Javascript規(guī)定,每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性氓鄙,指向另一個(gè)對(duì)象馆揉。這個(gè)對(duì)象的所有屬性和方法,都會(huì)被構(gòu)造函數(shù)的實(shí)例繼承抖拦。

進(jìn)一步升酣,為了避免生成對(duì)象的時(shí)候漏寫 new,可以封裝一下蟋座。

function Student(props) {
    this.name = props.name || '匿名'; // 默認(rèn)值為'匿名'
    this.grade = props.grade || 1; // 默認(rèn)值為1
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
};

function createStudent(props) {
    return new Student(props || {});  // 兼顧沒(méi)有參數(shù)的情況
}

然后直接調(diào)用 createStudent() 就可以了拗踢。

Student.prototype 的繼承應(yīng)該如何寫呢脚牍?

function PrimaryStudent(props) {
    // 調(diào)用Student constructor構(gòu)造函數(shù)向臀,綁定this變量
    Student.call(this, props);
    this.grade = props.grade || 1;
}

別以為這就結(jié)束了。

Student.call(this, props); 這句代碼诸狭,確實(shí)和 Student 搭上邊了券膀,但此時(shí) PrimaryStudent.prototype 是誰(shuí)?

我們的目標(biāo)是構(gòu)造一個(gè) PrimaryStudent.prototype 驯遇,令它指向上層的 Student.prototype芹彬。

有誰(shuí)是這種關(guān)系?kitty 和 daisy 的原型好像就是叉庐。

我就不想了舒帮,前輩的方法是這樣的。

function F() {
}

F.prototype = Student.prototype;

PrimaryStudent.prototype = new F();

// 把PrimaryStudent原型的構(gòu)造函數(shù)修復(fù)為PrimaryStudent(因?yàn)樯弦痪湫薷牧薱onstructor)
PrimaryStudent.prototype.constructor = PrimaryStudent;
  • 構(gòu)造一個(gè)函數(shù) F 陡叠,令 F.prototype = Student.prototype
  • 生成一個(gè)中間對(duì)象玩郊,那么這個(gè)對(duì)象的 prototype 就可以指向 Student.prototype

這不就是我們想要的嗎?我們把該對(duì)象賦給 PrimaryStudent.prototype 枉阵,那么就可以實(shí)現(xiàn) PrimaryStudent.prototype —> Student.prototype 的指向連接了译红。

// 繼續(xù)在PrimaryStudent原型(就是new F()對(duì)象)上定義方法:
PrimaryStudent.prototype.getGrade = function () {
    return this.grade;
};

// 創(chuàng)建xiaoming:
var xiaoming = new PrimaryStudent({
    name: '小明',
    grade: 2
});
xiaoming.name; // '小明'
xiaoming.grade; // 2

// 驗(yàn)證原型:
xiaoming.__proto__ === PrimaryStudent.prototype; // true
xiaoming.__proto__.__proto__ === Student.prototype; // true

// 驗(yàn)證繼承關(guān)系:
xiaoming instanceof PrimaryStudent; // true
xiaoming instanceof Student; // true

封裝它

function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}

Child.uber = Parent.prototype; 意思是為子對(duì)象設(shè)一個(gè)uber屬性,這個(gè)屬性直接指向父對(duì)象的prototype屬性兴溜。(uber是一個(gè)德語(yǔ)詞侦厚,意思是"向上"耻陕、"上一層"。)這等于在子對(duì)象上打開(kāi)一條通道刨沦,可以直接調(diào)用父對(duì)象的方法诗宣。這一行放在這里,只是為了實(shí)現(xiàn)繼承的完備性已卷,純屬備用性質(zhì)梧田。

參考資料

廖雪峰的三篇文章(個(gè)人感覺(jué)有些晦澀,最好再去看看別的資料)

推薦阮一峰的三篇文章侧蘸,由簡(jiǎn)入深裁眯,非常不錯(cuò)。

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末讳癌,一起剝皮案震驚了整個(gè)濱河市穿稳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晌坤,老刑警劉巖逢艘,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異骤菠,居然都是意外死亡它改,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門商乎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)央拖,“玉大人,你說(shuō)我怎么就攤上這事鹉戚∠式洌” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵抹凳,是天一觀的道長(zhǎng)遏餐。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赢底,這世上最難降的妖魔是什么失都? 我笑而不...
    開(kāi)封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮幸冻,結(jié)果婚禮上粹庞,老公的妹妹穿的比我還像新娘。我一直安慰自己嘁扼,他們只是感情好信粮,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著趁啸,像睡著了一般强缘。 火紅的嫁衣襯著肌膚如雪督惰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天旅掂,我揣著相機(jī)與錄音赏胚,去河邊找鬼。 笑死商虐,一個(gè)胖子當(dāng)著我的面吹牛觉阅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秘车,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼典勇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了叮趴?” 一聲冷哼從身側(cè)響起割笙,我...
    開(kāi)封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎眯亦,沒(méi)想到半個(gè)月后伤溉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妻率,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年乱顾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宫静。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡走净,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出囊嘉,到底是詐尸還是另有隱情温技,我是刑警寧澤革为,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布扭粱,位于F島的核電站,受9級(jí)特大地震影響震檩,放射性物質(zhì)發(fā)生泄漏琢蛤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一抛虏、第九天 我趴在偏房一處隱蔽的房頂上張望博其。 院中可真熱鬧,春花似錦迂猴、人聲如沸慕淡。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)峰髓。三九已至傻寂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間携兵,已是汗流浹背疾掰。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留徐紧,地道東北人静檬。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像并级,于是被迫代替她去往敵國(guó)和親拂檩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容