国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript 中的 new 到底干了什么,跟原型鏈又有一些什么聯(lián)系?

Cympros / 2507人閱讀

摘要:原文如果按面向?qū)ο蟮乃悸啡ブv的,還是很難去理解,我們可以從另一個(gè)方向去理解一下它。

原文:https://legacy.ofcrab.com/press/javascript-new.html

如果按面向?qū)ο蟮乃悸啡ブv JavaScript 的 new,還是很難去理解,我們可以從另一個(gè)方向去理解一下它。

你這些人類

我是一名程序員,也是一個(gè)人,我可能:

有一個(gè)響亮亮的名稱

在某一天出生

是個(gè)男人

我能行走

我還能跑步

還能跳躍

能說(shuō)話

我還能寫代碼

那么,在 JavaScript 中,我們可能像下面這樣表達(dá)我:

const me = {
  name: "大胡子農(nóng)同工潘半仙",
  birth: "1988-08-08",
  sex: "male",
  walk: function (speed, direction, duration) {
    // 以 speed 的速度向 direction 方向行走 duration 長(zhǎng)的時(shí)間
  },
  run: function (speed, direction, duration) {
    // 像跑步一樣,速度
  },
  jump: function (high, direction, angle) {
    // 以 angle 角度向 direction 方向跳 high 高
  },
  speak: function (letters) {
    // 說(shuō)出 letters 這些詞
  },
  coding: function (language, line) {
    // 寫程序呢
  }
}
你們這些人類

當(dāng)然,這個(gè)世界上不可能只有我一個(gè)程序員,更不可能只有我一個(gè)人,就像我們這個(gè)小公司,就有七八百人,似乎所有這些人的數(shù)據(jù)都保存在數(shù)據(jù)庫(kù)里面:

name sex birth
潘韜 male 1988-08-08
高超 male 1985-08-09
春雨 male 1999-08-08

我們從數(shù)據(jù)庫(kù)中查詢出上面這幾條記錄,在 JavaScript 可能表示為一個(gè)二維數(shù)據(jù),然后要?jiǎng)?chuàng)建出這三個(gè)人來(lái),可能是下面這樣的:

const people = DB.query()
// people = [["潘韜", "male", "1988-08-08"], [...], [...]]
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name,
    sex,
    birth,
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
  }
}
重復(fù)的資源占用

上面大家已經(jīng)發(fā)現(xiàn),像上面這樣去創(chuàng)建三個(gè)對(duì)象, walkrunjumpspeakcoding 這五件能做的事情(方法),其實(shí)做法都一樣,但是我們卻重復(fù)的去描述該怎么做了,其實(shí)就占用了很多資源,所以,我們可能會(huì)像下面這樣改進(jìn)一下:

const walk = function walk () {}
const run = function run () {}
const jump = function jump () {}
const speak = function speak () {}
const coding = function coding () {}

for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name,
    sex,
    birth,
    walk,
    run,
    jump,
    speak,
    coding
  }
}

不同的人共用相同的資源(方法)

但是這個(gè)世界不止有人類

對(duì),人類相比于這個(gè)世界上的其它生物來(lái)講,數(shù)量根本就值得一提,如果像上面這樣,可能各種不同物種能做的事情都會(huì)要定義出不同的函數(shù),蠕動(dòng)肯定不是人類會(huì)去做的事情,但很多別的生物會(huì)做,那么為了代碼管理方便,我們把人能做的所有事情都放在一個(gè)對(duì)象里面,這樣就相當(dāng)于有了一個(gè)命名空間了,不會(huì)再跟別的物種相沖突:

const whatPeopleCanDo = {
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name,
    sex,
    birth,
    ...whatPeopleCanDo
  }
}
原型

但是,有的人可能我們并不知道他的 sex 信息是多少,有的也有可能不知道 birth 是多少,但是我們希望在創(chuàng)建這個(gè)人的時(shí)候,能給不知道的數(shù)據(jù)一些初始數(shù)據(jù),所以, whatPeopleCanDo 并不能完全的表達(dá)出一個(gè)人,我們?cè)俑倪M(jìn):

const peopleLike = {
    name: "",
    sex: "unknown",
    birth: "",
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    ...peopleLike,
    name: name || peopleLike.name,
    sex: sex || peopleLike.sex,
    birth: birth || peopleLike.birth
  }
}

這樣一來(lái),我們就可以為不知道的屬性加一些默認(rèn)值,我們稱 peopleLike 這個(gè)東東就為原型,它表示了像人類這樣的物種有哪些屬性,能干什么事情。

原型鏈

雖然上面已經(jīng)比最開始的版本好得多了,但是還是能有很大的改進(jìn)空間,我們現(xiàn)在像下面這樣改一下:

const peoplePrototype = {
    name: "",
    sex: "unknown",
    birth: "",
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name: name || peoplePrototype.name,
    sex: sex || peoplePrototype.sex,
    birth: birth || peoplePrototype.birth,
    __proto__: peoplePrototype
  }
}

我們不再把人類原型里面的所有方法都綁定到某個(gè)人身上,而是像上面這樣,用一個(gè)特殊的字段 __proto__ 來(lái)指定:我的原型是 peoplePrototype 這個(gè)對(duì)象,同時(shí),我們還制定了一個(gè)規(guī)則:如果你想請(qǐng)求我的某個(gè)方法,在我自己身上沒有,那就去我的原型上面找吧,如果我的原型上面沒有,那就去我的原型的原型上面去找,直到某個(gè)位置,沒有更上層的原型為止

像上面這樣創(chuàng)建的 people 對(duì)象,有自己的屬性,但是當(dāng)我們?nèi)ピL問 people.speak() 方法的時(shí)候,其實(shí)訪問的是 people.__proto__.speak(),這是我們的規(guī)則。

更優(yōu)雅的創(chuàng)建新新人類

我們總不能在需要?jiǎng)?chuàng)建新人的時(shí)候,都像上面這樣,自己去寫一個(gè)對(duì)象,然后再手工指定它的原型是什么,所以,我們可以創(chuàng)建一個(gè)函數(shù),專門用來(lái)生成人類的:

const peoplePrototype = {
    name: "",
    sex: "unknown",
    birth: "",
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
const makePeople = function makePeople(name, sex, birth) {
  let people = {}
  people.name = name || peoplePrototype.name
  people.sex = sex || peoplePrototype.sex
  people.birth = birth || peoplePrototype.birth
  people.__proto__ = peoplePrototype
  return people
}

people = people.map(makePeople)

現(xiàn)在這樣我們只需要引入 makePeople 這個(gè)函數(shù)就可以隨時(shí)隨地創(chuàng)建新人了。

更優(yōu)雅一點(diǎn)的改進(jìn)

顯然,上面這樣并不是最好的辦法,定義了一個(gè)原型,又定義了一個(gè)原型對(duì)象,我們可以把這兩個(gè)合并到一起,所以,就可以有下面這樣的實(shí)現(xiàn)了:

const People = function People (name, sex, birth) {
  let people = {}
  people.name = name || People.prototype.name
  people.sex = sex || People.prototype.sex
  people.birth = birth || People.prototype.birth
  people.__proto__ = People.prototype
  return people
}

People.prototype = {
    name: "",
    sex: "unknown",
    birth: "",
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}

我們直接把創(chuàng)建人類的那個(gè)函數(shù)叫作 People,這個(gè)函數(shù)有一個(gè)屬性叫 prototype,它表示用我這個(gè)函數(shù)創(chuàng)建的對(duì)象的原型是什么,這個(gè)函數(shù)做的事情還是以前那些事兒,創(chuàng)建臨時(shí)對(duì)象,設(shè)置對(duì)象的屬性,綁定一下原型,然后返回。

神奇的 this

我們除了人,還有別的動(dòng)物,比如 TigerFish等,按上面的方式,在 Tiger() 或者 Fish() 函數(shù)里面都會(huì)建立不同的 tiger 或者 fish 名稱的臨時(shí)對(duì)象,這樣太麻煩,我們把這種函數(shù)創(chuàng)建出來(lái)的對(duì)象,都可以統(tǒng)一叫作“這個(gè)對(duì)象” ,也就是 this object,不在關(guān)心是人是鬼,統(tǒng)一把所有的臨時(shí)對(duì)象都叫 thisObject 或者更簡(jiǎn)單的就叫作:這個(gè),即 this

const People = function People (name, sex, birth) {
  let this = {}
  this.name = name || People.prototype.name
  this.sex = sex || People.prototype.sex
  this.birth = birth || People.prototype.birth
  this.__proto__ = People.prototype
  return this
}

當(dāng)然,上面的這一段代碼是有問題的,只是假想一樣,這樣是不是可行。

new

到現(xiàn)在為止,我們發(fā)現(xiàn)了整個(gè)代碼的演變,是時(shí)候引出這個(gè) new 了,它來(lái)干什么呢?它后面接一個(gè)類似上面這種 People 的函數(shù),表示我需要?jiǎng)?chuàng)建一個(gè) People 的實(shí)例,它的發(fā)明就是為了解決上面這些所有重復(fù)的事情,有了 new 之后,我們不需要再每一次定義一個(gè)臨時(shí)對(duì)象,在 new 的上下文關(guān)系中,會(huì)在 People 函數(shù)體內(nèi)自動(dòng)為創(chuàng)建一個(gè)臨時(shí)變量 this,這個(gè)就表示即將被創(chuàng)建出來(lái)的對(duì)象。同時(shí),對(duì)于使用 new 創(chuàng)建的實(shí)例,會(huì)自動(dòng)的綁定到創(chuàng)建函數(shù)的 prototype 作為原型,還會(huì)自動(dòng)為 People 創(chuàng)建一個(gè) constructor 函數(shù),表示這個(gè)原型的創(chuàng)建函數(shù)是什么,所以,我們可以改成下面這樣的了:

const People = function People (name, sex, birth) {
  this.name = name || People.prototype.name
  this.sex = sex || People.prototype.sex
  this.birth = birth || People.prototype.birth
}

People.prototype.name = ""
People.prototype.sex = "unknown"
People.prototype.birth = ""
People.prototype.walk = function () {}
People.prototype.run = function () {}
People.prototype.jump = function () {}
People.prototype.speak = function () {}
People.prototype.coding = function () {}

people = people.map(p => new People(...p))
總結(jié)

new 到底干了什么?當(dāng) new People() 的時(shí)候

創(chuàng)建臨時(shí)變量 this,并將 this 綁定到 People 函數(shù)體里

執(zhí)行 People.prototype.constructor = People

執(zhí)行 this.__proto__ = People.prototype

執(zhí)行 People 函數(shù)體中的自定義

返回新創(chuàng)建的對(duì)象

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/103654.html

相關(guān)文章

  • 用愚公移山說(shuō)明Javascript創(chuàng)建對(duì)象的各種姿勢(shì)

    摘要:北山愚公者年且九十面山而居。工廠模式愚小公北山愚小小公北山工廠模式比較明顯的一個(gè)缺點(diǎn)就是由于生成并返回了一個(gè)中間對(duì)象,所以不能判斷對(duì)象的類型。 ??太行、王屋二山,方七百里,高萬(wàn)仞。本在冀州之南,河陽(yáng)之北....... ??嗯,按照慣例,第一句話就是騙你們點(diǎn)進(jìn)來(lái)的。在讀本文之前,希望你對(duì)Javascript的原型和原型鏈有一定了解,這有助于你更好的理解本文,之前有寫過(guò)一篇相關(guān)文章,點(diǎn)此...

    cartoon 評(píng)論0 收藏0
  • 深入學(xué)習(xí)js之——原型原型

    摘要:我們用一張圖表示構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系好了構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系我們已經(jīng)梳理清楚了,那我們?cè)趺幢硎緦?shí)例與實(shí)例原型,也就是或者和之間的關(guān)系呢。 開篇: 在Brendan Eich大神為JavaScript設(shè)計(jì)面向?qū)ο笙到y(tǒng)的時(shí)候,借鑒了Self 和Smalltalk這兩門基于原型的語(yǔ)言,之所以選擇基于原型的面向?qū)ο笙到y(tǒng),并不是因?yàn)闀r(shí)間匆忙,它設(shè)計(jì)起來(lái)相對(duì)簡(jiǎn)單,而是因?yàn)閺囊婚_始B...

    FingerLiu 評(píng)論0 收藏0
  • 深入學(xué)習(xí)js之——原型原型

    摘要:我們用一張圖表示構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系好了構(gòu)造函數(shù)和實(shí)例原型之間的關(guān)系我們已經(jīng)梳理清楚了,那我們?cè)趺幢硎緦?shí)例與實(shí)例原型,也就是或者和之間的關(guān)系呢。 開篇: 在Brendan Eich大神為JavaScript設(shè)計(jì)面向?qū)ο笙到y(tǒng)的時(shí)候,借鑒了Self 和Smalltalk這兩門基于原型的語(yǔ)言,之所以選擇基于原型的面向?qū)ο笙到y(tǒng),并不是因?yàn)闀r(shí)間匆忙,它設(shè)計(jì)起來(lái)相對(duì)簡(jiǎn)單,而是因?yàn)閺囊婚_始B...

    xialong 評(píng)論0 收藏0
  • 前端基礎(chǔ)進(jìn)階(九):詳解面向?qū)ο蟆?gòu)造函數(shù)、原型原型

    摘要:我們通過(guò)一個(gè)簡(jiǎn)單的例子與圖示,來(lái)了解構(gòu)造函數(shù),實(shí)例與原型三者之間的關(guān)系。而原型對(duì)象的指向構(gòu)造函數(shù)。于是根據(jù)構(gòu)造函數(shù)與原型的特性,我們就可以將在構(gòu)造函數(shù)中,通過(guò)聲明的屬性與方法稱為私有變量與方法,它們被當(dāng)前被某一個(gè)實(shí)例對(duì)象所獨(dú)有。 showImg(https://segmentfault.com/img/remote/1460000008593382); 如果要我總結(jié)一下學(xué)習(xí)前端以來(lái)我遇...

    Tony_Zby 評(píng)論0 收藏0
  • 進(jìn)擊的 JavaScript (七)之 原型

    摘要:創(chuàng)建一個(gè)新的對(duì)象即實(shí)例對(duì)象把新對(duì)象的指向后面構(gòu)造函數(shù)的原型對(duì)象。簡(jiǎn)單來(lái)驗(yàn)證一下等同與對(duì)象沒有原型對(duì)象的原型對(duì)像等同于構(gòu)造函數(shù)是等同于,構(gòu)造函數(shù)是七原型鏈的作用其實(shí),原型鏈的根本作用就是為了屬性的讀取。 首先說(shuō)一下,函數(shù)創(chuàng)建的相關(guān)知識(shí) 在JavaScript中,我們創(chuàng)建一個(gè)函數(shù)A(就是聲明一個(gè)函數(shù)), 那么 js引擎 就會(huì)用構(gòu)造函數(shù)Function來(lái)創(chuàng)建這個(gè)函數(shù)。所以,所有的函數(shù)的con...

    ivydom 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Cympros

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<