vue 源碼探究(第一彈)

vue 源碼探究(第一彈)

最近在深 vue苫昌,接下來會有記錄一系列 vue 源碼解析方面的東西颤绕,主要從 3 個方面,開始解讀:

  • 數(shù)據(jù)代理
  • 模板解析
  • 數(shù)據(jù)雙向綁定

在解析這些的時候,會發(fā)現(xiàn)源碼中用到了很多 js 中比較核心但平時用的比較少的東西奥务,在這里也先做一個 prepare 的預(yù)熱吧物独。

問題

  1. [].slice.call(lis): 將偽數(shù)組轉(zhuǎn)換為真數(shù)組
  2. node.nodeType: 得到節(jié)點類型
  3. Object.defineProperty(obj, propertyName, {}): 給對象添加屬性(指定描述符)
  4. Object.keys(obj): 得到對象自身可枚舉屬性組成的數(shù)組
  5. obj.hasOwnProperty(prop): 判斷 prop 是否是 obj 自身的屬性
  6. DocumentFragment: 文檔碎片(高效批量更新多個節(jié)點)

解析

一、如何將偽數(shù)組轉(zhuǎn)換為真數(shù)組

首先拋出一個問題氯葬,什么叫做偽數(shù)組挡篓?

const lis = document.getElementsByTagName('li') // lis是偽數(shù)組(是一個特別的對象, length和數(shù)值下標屬性)
console.log(lis instanceof Object, lis instanceof Array, lis.forEach)// 打印結(jié)果 true false undefined

在 ES6 中,我們可以通過這樣一個方法帚称,把偽數(shù)組轉(zhuǎn)為真數(shù)組

Array.from(lis); //es6中將偽數(shù)組->真數(shù)組

如果說官研,在 ES5 中,我們應(yīng)該怎么做呢闯睹?

const lis2 = Array.prototype.slice.call(lis); // lis.slice() 通過lis調(diào)用slice
console.log(lis2 instanceof Object, lis2 instanceof Array, lis2.forEach);
// true true ? forEach() { [native code] }

這里再順便拓展一下 slice 吧

  // 數(shù)組的slice()截取數(shù)組中指定部分的元素, 生成一個新的數(shù)組  [1, 3, 5, 7, 9], slice(0, 3)
  // slice2() 內(nèi)部實現(xiàn)
  Array.prototype.slice2 = function (start, end) {
    start = start || 0
    end = start || this.length
    const arr = []
    for (var i = start; i < end; i++) {
      arr.push(this[i])
    }
    return arr
  }

二戏羽、node.nodeType: 得到節(jié)點類型

先 show code:

const elementNode = document.getElementById('test');
const attrNode = elementNode.getAttributeNode('id');
const textNode = elementNode.firstChild;
console.log(elementNode, attrNode, textNode);
// <div id="test">教育</div> id="test" "教育"
console.log(elementNode.nodeType, attrNode.nodeType, textNode.nodeType);
// 1 2 3

三、Object.defineProperty(obj, propertyName, {}): 給對象添加屬性(指定描述符)

vue 源碼中用到了很多次這個屬性瞻坝,數(shù)據(jù)的雙向綁定底層實現(xiàn)也是運用到它蛛壳,還是很有意思杏瞻,hhh

簡單舉一個例所刀,讓它做到數(shù)據(jù)綁定。

  const obj = {
    firstName: 'A',
    lastName: 'B'
  }
  // 如果說捞挥,我們想得到這個:obj.fullName = 'A-B'
  // 參數(shù)介紹:
  // obj 要在其上定義屬性的對象浮创。
  // prop 要定義或修改的屬性的名稱。
  // descriptor 將被定義或修改的屬性描述符
  Object.defineProperty(obj, 'fullName', {
    // 屬性描述符:
    // 數(shù)據(jù)描述符
    // 訪問描述符
    // 當讀取對象此屬性值時自動調(diào)用, 將函數(shù)返回的值作為屬性值, this為obj
    get () {
      return this.firstName + "-" + this.lastName
    },
    // 當修改了對象的當前屬性值時自動調(diào)用, 監(jiān)視當前屬性值的變化, 修改相關(guān)的屬性, this為obj
    set (value) {
      const names = value.split('-')
      this.firstName = names[0]
      this.lastName = names[1]
    }
  })

  console.log(obj.fullName) // A-B
  obj.fullName = 'C-D'
  console.log(obj.firstName, obj.lastName) // C D
  // 是不是感覺很像v-module中的雙向數(shù)據(jù)綁定

看了簡單的綁定砌函,我們再來深入一下~
緊接著上面的

  Object.defineProperty(obj, 'fullName2', {
    configurable: false, //是否可以重新define
    enumerable: true, // 是否可以枚舉(for..in / keys()) 這個在下面的object.key() 中會 深受感觸
    value: 'A-B', // 指定初始值
    writable: false // value是否可以修改
  })
  console.log(obj.fullName2)  // A-B
  obj.fullName2 = 'E-F'
  console.log(obj.fullName2) // A-B
  // 為什么會出現(xiàn)這個問題呢斩披?是不是因為writable的原因?那我們可以改一下嗎讹俊?

  Object.defineProperty(obj, 'fullName2', {
    configurable: true,
    enumerable: true,
    value: 'G-H',
    writable: true
  })
  // 這時候會報錯
  // Uncaught TypeError: Cannot redefine property:fullName2
  //at Function.defineProperty (<anonymous>)
  // 相信你已經(jīng)懂了吧

講到這里垦沉,會提到一個題外話,為什么說 vue 不支持 ie8 呢仍劈?
因為 Object.defineProperty 是 es5 中新增的東西厕倍,它不支持 ie8,而 vue 中的數(shù)據(jù)綁定等多處用到該屬性贩疙,所以讹弯,這也就是為什么 vue 不支持 ie8,因為這個方法不支持 ie8

四这溅、Object.keys(obj): 得到對象自身可枚舉屬性組成的數(shù)組

這里敲黑板组民、劃重點 對象自身 可枚舉

const names = Object.keys(obj);
console.log(names);
//  ["firstName", "lastName", "fullName2"]
// 為什么沒有 fullName 因為fullname中的enumerable不是true 默認為false。

五悲靴、obj.hasOwnProperty(prop): 判斷 prop 是否是 obj 自身的屬性

這個屬性還是有很多地方會用到臭胜。具體是干嘛的?
相信直譯就可以了解,看這個屬性是不是自身的庇楞。
因為有些屬性雖然可以用榜配,但有可能是原型鏈上的,而不是自己的吕晌,這個方法可以用于檢測

console.log(obj.hasOwnProperty('fullName'), obj.hasOwnProperty('toString'));
// true false

未完待續(xù)...
接下來蛋褥,還有一個更有趣的東西,文檔碎片(高效批量更新多個節(jié)點)睛驳,這也是為什么vue可以批量更新節(jié)點烙心。

下一章繼續(xù)~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乏沸,隨后出現(xiàn)的幾起案子淫茵,更是在濱河造成了極大的恐慌,老刑警劉巖蹬跃,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匙瘪,死亡現(xiàn)場離奇詭異,居然都是意外死亡蝶缀,警方通過查閱死者的電腦和手機丹喻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翁都,“玉大人碍论,你說我怎么就攤上這事”浚” “怎么了鳍悠?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坐搔。 經(jīng)常有香客問我藏研,道長,這世上最難降的妖魔是什么概行? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任蠢挡,我火速辦了婚禮,結(jié)果婚禮上占锯,老公的妹妹穿的比我還像新娘袒哥。我一直安慰自己,他們只是感情好消略,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布堡称。 她就那樣靜靜地躺著,像睡著了一般艺演。 火紅的嫁衣襯著肌膚如雪却紧。 梳的紋絲不亂的頭發(fā)上桐臊,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音晓殊,去河邊找鬼断凶。 笑死,一個胖子當著我的面吹牛巫俺,可吹牛的內(nèi)容都是我干的认烁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼介汹,長吁一口氣:“原來是場噩夢啊……” “哼却嗡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嘹承,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤窗价,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后叹卷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撼港,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年骤竹,在試婚紗的時候發(fā)現(xiàn)自己被綠了帝牡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡瘤载,死狀恐怖否灾,靈堂內(nèi)的尸體忽然破棺而出卖擅,到底是詐尸還是另有隱情鸣奔,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布惩阶,位于F島的核電站挎狸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏断楷。R本人自食惡果不足惜锨匆,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冬筒。 院中可真熱鬧恐锣,春花似錦、人聲如沸舞痰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽响牛。三九已至玷禽,卻和暖如春赫段,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背矢赁。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工糯笙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撩银。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓给涕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親额获。 傳聞我的和親對象是個殘疾皇子稠炬,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

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