最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue對象的單層劫持圖文詳細講解

 更新時間:2023年01月06日 15:40:55   作者:BraveWangDev  
這篇文章主要介紹了vue2.x對象單層劫持的原理實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一,前言

上篇,介紹了 Vue 使用及數(shù)據(jù)初始化的流程

回顧一下,主要涉及以下幾個核心點:

  • initMixin 方法: 原型方法 Vue.prototype._init
  • vm.$options:使 options 選項在 vm 實例上被共享
  • initState 方法: Vue 初始化時,對多種數(shù)據(jù)源做集中處理
  • initData 方法:data 數(shù)據(jù)的初始化

本篇,繼續(xù)對 data 數(shù)據(jù)進行初始化操作,對象的劫持(對象屬性的單層劫持)

二,Vue 的響應(yīng)式原理

問題:Vue 的響應(yīng)式原理

Vue 的響應(yīng)式原理

核心是通過 Object.defineProperty 為屬性添加 get、set 方法,從而實現(xiàn)對數(shù)據(jù)操的劫持…

即下圖中 Data 部分:

三,對象的劫持

1,initData 中獲取 data

data 在 options 中,而 options 已被 vm 實例共享

function initData(vm){
    let data = vm.$options.data;// 拿到 vue 初始化時,用戶傳入的data數(shù)據(jù)
    console.log("進入 state.js - initData,數(shù)據(jù)初始化操作", data)
}

2,處理 data 的兩種情況

上篇說了,data 有可能是函數(shù),也有可能是對象

因此,后邊邏輯需要對 data 進行一次處理

// utils.js
export function isFunction(val){
  return typeof val == 'function'
}

如果 data 是函數(shù),需要執(zhí)行拿到顳部返回的對象

// 如果 data 是函數(shù),需要執(zhí)行 data 拿到它的返回值
if(isFunction(data)){
  data = data(); // 這樣執(zhí)行,this 不是 vm,而是window
}

測試:

let vm = new Vue({
  el: '#app',
  data() {
    console.log("打印 data函數(shù)執(zhí)行時,this的指向")
    console.log(this)
    return { message: 'Hello Vue' } // data 返回一個對象
  }
});

此時,data 函數(shù)執(zhí)行時,this 指向 window

3,處理 this 的指向問題

在 Vue 中,data 函數(shù)執(zhí)行時 this 應(yīng)指向當前 vm 實例

所以,在 data 執(zhí)行時綁定 this 為當前 vm 實例

if(isFunction(data)){
  data = data.call(vm);// data 執(zhí)行時,綁定this 為 vm
}

測試:

簡化代碼:將 data 為對象或函數(shù)兩種情況的邏輯合并:

// data 可能是函數(shù)或?qū)ο?
//  如果 data 是函數(shù),則需要讓 data 函數(shù)執(zhí)行,拿到它返回的對象
//  如果 data 是對象,不做處理
data = isFunction(data) ? data.call(vm) : data;

注意:只有根實例上的 data 可以是對象,組件必須為函數(shù)

4,核心模塊 observe:對數(shù)據(jù)進行觀測

data 數(shù)據(jù)的響應(yīng)式原理是:

通過 Object.defineProperty,重寫 data 上的所有屬性

這就需要遍歷 data 對象拿到每一個屬性,再逐一通過 Object.defineProperty 重新定義

  • observe 模塊(文件夾)
  • observe 方法 (入口)

創(chuàng)建入口文件 observe/index.js

// src/observe/index.js
export function observe(value) {
  console.log(value)
}

在 state.js 中引入并使用 observe 方法

調(diào)用 observe 方法觀測數(shù)據(jù),實現(xiàn) data 數(shù)據(jù)的響應(yīng)式

import { observe } from "./observe";
import { isFunction } from "./utils";
export function initState(vm) {
    const opts = vm.$options;
    if (opts.data) {
        initData(vm);
    }
}
function initData(vm) {
    let data = vm.$options.data;
    data = isFunction(data) ? data.call(vm) : data;
    observe(data);  // 使用 observe 實現(xiàn) data 數(shù)據(jù)的響應(yīng)式
}

經(jīng)過這次處理后,此時的 data 一定是一個對象

所以,對 data 進行檢測,如果不是對象就直接 return 結(jié)束

// src/utils
/**
 * 判斷是否為對象:類型是object,且不能為 null
 * @param {*} val 
 * @returns 
 */
export function isObject(val) {
  return typeof val == 'object' && val !== null
}
// src/observe/index.js
import { isObject } from "../utils";
export function observe(value) {
  // 如果 value 不是對象,就不需要觀測了,直接 return
  if(!isObject(value)){
    return;
  }
}

5,Observer 類:對【對象】進行觀測

完成的邏輯是這樣的:

// src/observe/index.js
export function observe(value) {
  if(!isObject(value)){
    return;
  }
  // 觀測 value 對象,實現(xiàn)數(shù)據(jù)響應(yīng)式
  return new Observer(value);
}

Observer 類:
遍歷對象屬性,使用 Object.defineProperty 重新定義 data 對象中的屬性

// src/observe/index.js
class Observer {
  constructor(value){
    // 如果value是對象,遍歷對象中的屬性,使用 Object.defineProperty 重新定義
    this.walk(value); // 循環(huán)對象屬性
  }
  // 循環(huán) data 對象,使用 Object.keys 不循環(huán)原型方法
  walk(data){
    Object.keys(data).forEach(key => { 
      // 使用 Object.defineProperty 重新定義 data 對象中的屬性
      defineReactive(data, key, data[key]);
    });
  }
}
/**
 * 給對象Obj,定義屬性key,值為value
 *  使用Object.defineProperty重新定義data對象中的屬性
 *  由于Object.defineProperty性能低,所以vue2的性能瓶頸也在這里
 * @param {*} obj 需要定義屬性的對象
 * @param {*} key 給對象定義的屬性名
 * @param {*} value 給對象定義的屬性值
 */
function defineReactive(obj, key, value) {
  Object.defineProperty(obj, key, {
    get(){ // 閉包
      return value;	// 問題:這里的 value 為什么不用 obj[key]獲???
    },
    set(newValue) {
      if (newValue === value) return
      value = newValue;
    }
  })
}

至此,obj 中的所有屬性都通過 defineProperty 重新定義,具有 get、set 方法

問題:為什么使用類而不使用函數(shù)?

TODO

問題:Object.defineProperty 中 get 為什么不用 obj[key] 來獲???

TODO

6,測試

在 data 進行初始化的 initData 方法中,

通過 observe 方法觀測 data 數(shù)據(jù),實現(xiàn)對 data 屬性的劫持

function initData(vm) {
    console.log("進入 state.js - initData,數(shù)據(jù)初始化操作")
    let data = vm.$options.data;
    data = isFunction(data) ? data.call(vm) : data;
    // data 數(shù)據(jù)的響應(yīng)式:遍歷對象拿到所有屬性,再通過Object.defineProperty 重寫 data 中的所有屬性  
    observe(data); // 觀測數(shù)據(jù)
    console.log(data)
}

打印被觀測后的 data 對象,查看執(zhí)行效果:

至此,就實現(xiàn)了對 data 屬性的劫持,但僅完成了第一層屬性的劫持

7,備注:安裝插件

// 不會自動到observe找index入口文件
import { observe } from "./observe";
// 需要指定index.js
import { observe } from "./observe/index";
// 安裝包:@rollup/plugin-node-resolve,實現(xiàn) node 方式解析文件
// npm i @rollup/plugin-node-resolve

使用插件:修改 rollup 配置文件

import babel from 'rollup-plugin-babel'
import resolve from 'rollup-plugin-node-resolve'; // 引入插件
export default {
    input:'./src/index.js',
    output:{
        file:'dist/vue.js',
        format:'umd',
        name:'Vue',
        sourcemap:true,
    },
    plugins:[
        resolve(),  // 使用插件
        babel({
            exclude:'node_modules/**'
        })
    ]
}

三,結(jié)尾

本篇主要介紹了 Vue 數(shù)據(jù)初始化流程中,對象屬性的單層劫持,核心的幾個點:

  • data 為函數(shù)和對象的處理
  • data 函數(shù)中 this 的指向
  • Observer 類,對數(shù)據(jù)進行觀測
  • walk 方法,遍歷 data 屬性(后面深層就不能叫 data 了)
  • defineReactive 方法:利用 Object.defineProperty 實現(xiàn)數(shù)據(jù)劫持

下一篇,對象屬性的深層劫持

到此這篇關(guān)于Vue對象的單層劫持圖文詳細講解的文章就介紹到這了,更多相關(guān)Vue對象單層劫持內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue使用qrcode生成二維碼的方法

    vue使用qrcode生成二維碼的方法

    這篇文章給大家介紹了vue使用qrcode生成二維碼的方法,在Vue中實現(xiàn)二維碼生成需要使用第三方庫來處理生成二維碼的邏輯,常用的庫有qrcode和vue-qrcode,所以接下來小編將給大家介紹vue?qrcode生成二維碼的方法示例,需要的朋友可以參考下
    2024-01-01
  • vue歌曲進度條示例代碼

    vue歌曲進度條示例代碼

    這篇文章主要介紹了vue歌曲進度條demo,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10
  • VUE頁面中加載外部HTML的示例代碼

    VUE頁面中加載外部HTML的示例代碼

    本篇文章主要介紹了VUE頁面中加載外部HTML的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 解決vue自定義指令導(dǎo)致的內(nèi)存泄漏問題

    解決vue自定義指令導(dǎo)致的內(nèi)存泄漏問題

    這篇文章主要介紹了解決vue自定義指令導(dǎo)致的內(nèi)存泄漏問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 組件中多個el-upload存在導(dǎo)致上傳圖片失效的問題及解決

    組件中多個el-upload存在導(dǎo)致上傳圖片失效的問題及解決

    這篇文章主要介紹了組件中多個el-upload存在導(dǎo)致上傳圖片失效的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Vue2與Vue3中Ref綁定元素方式

    Vue2與Vue3中Ref綁定元素方式

    這篇文章主要介紹了Vue2與Vue3中Ref綁定元素方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • vue復(fù)合組件實現(xiàn)注冊表單功能

    vue復(fù)合組件實現(xiàn)注冊表單功能

    這篇文章主要為大家詳細介紹了vue復(fù)合組件實現(xiàn)注冊表單功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 詳解Vue用cmd創(chuàng)建項目

    詳解Vue用cmd創(chuàng)建項目

    在本篇內(nèi)容里小編給大家整理了關(guān)于Vue用cmd創(chuàng)建項目的方法講解,有興趣的朋友們跟著學(xué)習(xí)下。
    2019-02-02
  • vue3過渡動畫的詳解

    vue3過渡動畫的詳解

    這篇文章主要為大家詳細介紹了vue3過渡動畫,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Vue文件的組織結(jié)構(gòu)不合理之優(yōu)化項目結(jié)構(gòu)詳解

    Vue文件的組織結(jié)構(gòu)不合理之優(yōu)化項目結(jié)構(gòu)詳解

    在這篇博客中,我們將探討 Vue 文件組織結(jié)構(gòu)不合理的幾個常見問題,并提供解決方案,以幫助開發(fā)者創(chuàng)建更清晰、更高效的項目文件結(jié)構(gòu),希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評論

齐齐哈尔市| 赤壁市| 徐州市| 兰西县| 广西| 昌都县| 五台县| 右玉县| 肃宁县| 成都市| 自治县| 罗山县| 东乌| 夏河县| 江口县| 阿克陶县| 美姑县| 永福县| 长葛市| 博客| 夏河县| 营口市| 灌阳县| 沂水县| 松桃| 红原县| 丰县| 丘北县| 沈阳市| 理塘县| 吉木乃县| 绥棱县| 新乐市| 昌邑市| 柯坪县| 凤翔县| 神池县| 滦南县| 永泰县| 龙口市| 翁牛特旗|