JavaScript深入之new的模擬實(shí)現(xiàn)

JavaScript深入系列第十二篇硝桩,通過new的模擬實(shí)現(xiàn),帶大家揭開使用new獲得構(gòu)造函數(shù)實(shí)例的真相

new

一句話介紹 new:

new 運(yùn)算符創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象類型之一

也許有點(diǎn)難懂,我們?cè)谀M new 之前接谨,先看看 new 實(shí)現(xiàn)了哪些功能。

舉個(gè)例子:

// Otaku 御宅族塘匣,簡(jiǎn)稱宅
function Otaku (name, age) {
    this.name = name;
    this.age = age;

    this.habit = 'Games';
}

// 因?yàn)槿狈﹀憻挼木壒逝Ш溃眢w強(qiáng)度讓人擔(dān)憂
Otaku.prototype.strength = 60;

Otaku.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}

var person = new Otaku('Kevin', '18');

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60

person.sayYourName(); // I am Kevin

從這個(gè)例子中,我們可以看到忌卤,實(shí)例 person 可以:

  1. 訪問到 Otaku 構(gòu)造函數(shù)里的屬性
  2. 訪問到 Otaku.prototype 中的屬性

接下來扫夜,我們可以嘗試著模擬一下了。

因?yàn)?new 是關(guān)鍵字驰徊,所以無法像 bind 函數(shù)一樣直接覆蓋笤闯,所以我們寫一個(gè)函數(shù),命名為 objectFactory棍厂,來模擬 new 的效果颗味。用的時(shí)候是這樣的:

function Otaku () {
    ……
}

// 使用 new
var person = new Otaku(……);
// 使用 objectFactory
var person = objectFactory(Otaku, ……)

初步實(shí)現(xiàn)

分析:

因?yàn)?new 的結(jié)果是一個(gè)新對(duì)象,所以在模擬實(shí)現(xiàn)的時(shí)候牺弹,我們也要建立一個(gè)新對(duì)象浦马,假設(shè)這個(gè)對(duì)象叫 obj,因?yàn)?obj 會(huì)具有 Otaku 構(gòu)造函數(shù)里的屬性张漂,想想經(jīng)典繼承的例子晶默,我們可以使用 Otaku.apply(obj, arguments)來給 obj 添加新的屬性。

在 JavaScript 深入系列第一篇中航攒,我們便講了原型與原型鏈磺陡,我們知道實(shí)例的 __proto__ 屬性會(huì)指向構(gòu)造函數(shù)的 prototype,也正是因?yàn)榻⑵疬@樣的關(guān)系漠畜,實(shí)例可以訪問原型上的屬性币他。

現(xiàn)在,我們可以嘗試著寫第一版了:

// 第一版代碼
function objectFactory() {

    var obj = new Object(),

    Constructor = [].shift.call(arguments);

    obj.__proto__ = Constructor.prototype;

    Constructor.apply(obj, arguments);

    return obj;

};

在這一版中盆驹,我們:

  1. 用new Object() 的方式新建了一個(gè)對(duì)象 obj
  2. 取出第一個(gè)參數(shù)圆丹,就是我們要傳入的構(gòu)造函數(shù)。此外因?yàn)?shift 會(huì)修改原數(shù)組躯喇,所以 arguments 會(huì)被去除第一個(gè)參數(shù)
  3. 將 obj 的原型指向構(gòu)造函數(shù)辫封,這樣 obj 就可以訪問到構(gòu)造函數(shù)原型中的屬性
  4. 使用 apply,改變構(gòu)造函數(shù) this 的指向到新建的對(duì)象廉丽,這樣 obj 就可以訪問到構(gòu)造函數(shù)中的屬性
  5. 返回 obj

更多關(guān)于:

原型與原型鏈倦微,可以看《JavaScript深入之從原型到原型鏈》

apply,可以看《JavaScript深入之call和apply的模擬實(shí)現(xiàn)》

經(jīng)典繼承正压,可以看《JavaScript深入之繼承》

復(fù)制以下的代碼欣福,到瀏覽器中,我們可以做一下測(cè)試:

function Otaku (name, age) {
    this.name = name;
    this.age = age;

    this.habit = 'Games';
}

Otaku.prototype.strength = 60;

Otaku.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}

function objectFactory() {
    var obj = new Object(),
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    Constructor.apply(obj, arguments);
    return obj;
};

var person = objectFactory(Otaku, 'Kevin', '18')

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60

person.sayYourName(); // I am Kevin

[]~( ̄▽ ̄)~**

返回值效果實(shí)現(xiàn)

接下來我們?cè)賮砜匆环N情況焦履,假如構(gòu)造函數(shù)有返回值拓劝,舉個(gè)例子:

function Otaku (name, age) {
    this.strength = 60;
    this.age = age;

    return {
        name: name,
        habit: 'Games'
    }
}

var person = new Otaku('Kevin', '18');

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // undefined
console.log(person.age) // undefined

在這個(gè)例子中雏逾,構(gòu)造函數(shù)返回了一個(gè)對(duì)象,在實(shí)例 person 中只能訪問返回的對(duì)象中的屬性郑临。

而且還要注意一點(diǎn)栖博,在這里我們是返回了一個(gè)對(duì)象,假如我們只是返回一個(gè)基本類型的值呢厢洞?

再舉個(gè)例子:

function Otaku (name, age) {
    this.strength = 60;
    this.age = age;

    return 'handsome boy';
}

var person = new Otaku('Kevin', '18');

console.log(person.name) // undefined
console.log(person.habit) // undefined
console.log(person.strength) // 60
console.log(person.age) // 18

結(jié)果完全顛倒過來仇让,這次盡管有返回值,但是相當(dāng)于沒有返回值進(jìn)行處理躺翻。

所以我們還需要判斷返回的值是不是一個(gè)對(duì)象丧叽,如果是一個(gè)對(duì)象,我們就返回這個(gè)對(duì)象公你,如果沒有踊淳,我們?cè)摲祷厥裁淳头祷厥裁础?/p>

再來看第二版的代碼,也是最后一版的代碼:

// 第二版的代碼
function objectFactory() {

    var obj = new Object(),

    Constructor = [].shift.call(arguments);

    obj.__proto__ = Constructor.prototype;

    var ret = Constructor.apply(obj, arguments);

    return typeof ret === 'object' ? ret : obj;

};

作者:冴羽
github:https://github.com/mqyqingfeng/Blog
掘金主頁:https://juejin.im/user/58e4b9b261ff4b006b3227f4
segmentfault主頁:https://segmentfault.com/u/yayu/articles

Vicky丶Amor 經(jīng)授權(quán)轉(zhuǎn)載省店,版權(quán)歸原作者所有嚣崭。
求關(guān)注,求點(diǎn)贊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末懦傍,一起剝皮案震驚了整個(gè)濱河市雹舀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌粗俱,老刑警劉巖说榆,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異寸认,居然都是意外死亡签财,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門偏塞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唱蒸,“玉大人,你說我怎么就攤上這事灸叼∩裥冢” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵古今,是天一觀的道長(zhǎng)屁魏。 經(jīng)常有香客問我,道長(zhǎng)捉腥,這世上最難降的妖魔是什么氓拼? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上桃漾,老公的妹妹穿的比我還像新娘坏匪。我一直安慰自己,他們只是感情好呈队,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布剥槐。 她就那樣靜靜地躺著,像睡著了一般宪摧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颅崩,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天几于,我揣著相機(jī)與錄音,去河邊找鬼沿后。 笑死沿彭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尖滚。 我是一名探鬼主播喉刘,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼漆弄!你這毒婦竟也來了睦裳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤撼唾,失蹤者是張志新(化名)和其女友劉穎廉邑,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體倒谷,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛛蒙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了渤愁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牵祟。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖抖格,靈堂內(nèi)的尸體忽然破棺而出诺苹,到底是詐尸還是另有隱情,我是刑警寧澤他挎,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布筝尾,位于F島的核電站,受9級(jí)特大地震影響办桨,放射性物質(zhì)發(fā)生泄漏筹淫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望损姜。 院中可真熱鬧饰剥,春花似錦、人聲如沸摧阅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棒卷。三九已至顾孽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間比规,已是汗流浹背若厚。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜒什,地道東北人测秸。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像灾常,于是被迫代替她去往敵國(guó)和親霎冯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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